Skip to content

Commit 86cfeb6

Browse files
committed
Merge pull request blakeembrey#153 from cjjavellana/master
Spreadsheet Problem Set
2 parents 5087234 + 2e11f6e commit 86cfeb6

File tree

20 files changed

+788
-4
lines changed

20 files changed

+788
-4
lines changed

problems/skiing-in-singapore/README.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
11
# Skiing in Singapore
2-
I came across this programming excercise from redmart that caught my interest. At the same time im in the midst of the harvard's cs50 course which i took through edx as a refresher. So I thought of taking up the programming excercise challenge and try to implement it using c. So without further ado, the challenge description goes like this:
3-
4-
====================
5-
62
Sometimes it's nice to take a break and code up a solution to a small, fun problem. Here is one some of our engineers enjoyed recently called Skiing In Singapore.
73

84
Well you can’t really ski in Singapore. But let’s say you hopped on a flight to the Niseko ski resort in Japan. Being a software engineer you can’t help but value efficiency, so naturally you want to ski as long as possible and as fast as possible without having to ride back up on the ski lift. So you take a look at the map of the mountain and try to find the longest ski run down.

problems/spreadsheet/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Programming Challenge
2+
3+
A spreadsheet consists of a two-dimensional array of cells, labeled A1, A2, etc. Rows are identified using letters, columns by numbers. Each cell contains either an integer (its value) or an expression. Expressions contain integers, cell references, and the operators '+', '-', '\*', '/' with the usual rules of evaluation – note that the input is RPN and should be evaluated in stack order.
4+
5+
The spreadsheet input is defined as follows:
6+
7+
1. Line 1: two integers, defining the width and height of the spreadsheet (n, m)
8+
9+
2. n\*m lines each containing an expression which is the value of the corresponding cell (cells enumerated in the order A1, A2, A<n>, B1, ...)
10+
11+
## The Input
12+
3 2
13+
A2
14+
4 5 *
15+
A1
16+
A1 B2 / 2 +
17+
3
18+
39 B1 B2 * /
19+
20+
## The Output
21+
3 2
22+
20.00000
23+
20.00000
24+
20.00000
25+
8.66667
26+
3.00000
27+
1.50000

solutions/c/spreadsheet/3x2.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
3 2
2+
A2
3+
4 5 *
4+
A1
5+
A1 B2 / 2 +
6+
3
7+
39 B1 B2 * /

solutions/c/spreadsheet/Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
all: spreadsheet
3+
4+
spreadsheet: spreadsheet.c matrix.c matrix.h stackcalc.h stackcalc.c regex.h regex.c commons.h commons.c
5+
clang -ggdb3 -O0 -std=c99 -Wall -Werror -o spreadsheet spreadsheet.c matrix.c regex.c commons.c stackcalc.c -I/usr/local/include -L/usr/local/lib/ -lpcre2-8
6+
7+
test: matrix_test.c regex.c commons.c regex.h matrix.h stackcalc.h stackcalc.c
8+
clang -o matrixTest -ggdb3 -Wall -Werror -O0 -std=c99 -I/usr/local/include matrix_test.c matrix.c regex.c commons.c stackcalc.c -L/usr/local/lib/ -lpcre2-8 -lcmocka
9+
10+
clean:
11+
rm -f *.o a.out spreadsheet core

solutions/c/spreadsheet/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Dependencies
2+
3+
This program depends on the following:
4+
1. pcre2-10.20 - Pattern matching, regular expression
5+
2. cmocka-1.0.0 - For Unit Tests
6+
7+
Please refer to their respective documentations on how to install these libraries into your respective system
8+
9+
# Execution
10+
It is required that the $LD\_LIBRARY\_PATH environment variable be set to the directory where the pcre.so is located if it is located other than /usr/lib
11+
12+

solutions/c/spreadsheet/commons.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include "commons.h"
2+
3+
int getNumberOfDigits(int n)
4+
{
5+
if (n < 0) return -1;
6+
if (n < 10) return 1;
7+
if (n < 100) return 2;
8+
if (n < 1000) return 3;
9+
if (n < 10000) return 4;
10+
if (n < 100000) return 5;
11+
if (n < 1000000) return 6;
12+
13+
return -1;
14+
}

solutions/c/spreadsheet/commons.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
/**
3+
* Returns the number of digits in the integer n
4+
*/
5+
int getNumberOfDigits(int n);
6+

solutions/c/spreadsheet/matrix.c

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
#define _XOPEN_SOURCE 700
2+
#define PCRE2_CODE_UNIT_WIDTH 8
3+
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <ctype.h>
7+
#include <string.h>
8+
#include <pcre2.h>
9+
10+
#include "regex.h"
11+
#include "matrix.h"
12+
#include "commons.h"
13+
14+
// ~ Static function propotypes ==================
15+
static int isCyclicError(const Worksheet *worksheet, const char *visitedCells, CellReference *cellReference);
16+
17+
/**
18+
* Initializes the worksheet cells of size rows * columns.
19+
*
20+
* Returns 0 if an error is encountered.
21+
*/
22+
int initWorksheet(Worksheet *worksheet, int rows, int columns) {
23+
worksheet->rows = rows;
24+
worksheet->cols = columns;
25+
26+
char ***matrix = (char ***) malloc(sizeof(char **) * rows);
27+
for(int i = 0; i < rows; i++) {
28+
matrix[i] = (char **) malloc(sizeof(char *) * columns);
29+
30+
for(int j = 0; j < columns; j++) {
31+
matrix[i][j] = (char *) calloc(sizeof(char) * CELL_CONTENT_LIMIT, sizeof(char));
32+
}
33+
}
34+
35+
worksheet->cells = matrix;
36+
return 1;
37+
}
38+
39+
int closeWorksheet(Worksheet *w)
40+
{
41+
for(int i = 0; i < w->rows; i++)
42+
{
43+
for(int j = 0; j < w->cols; j++)
44+
{
45+
free(w->cells[i][j]);
46+
}
47+
free(w->cells[i]);
48+
}
49+
free(w->cells);
50+
free(w);
51+
return 1;
52+
}
53+
54+
/**
55+
* Sets s to the worksheet cell at row, column.
56+
*
57+
* Returns 0 if strlen(s) > CELL_CONTENT_LIMIT
58+
*/
59+
int setValue(Worksheet *worksheet, int row, int column, char* s) {
60+
if (strlen(s) <= CELL_CONTENT_LIMIT) {
61+
strncpy(worksheet->cells[row][column], s, strlen(s));
62+
return 1;
63+
} else {
64+
return 0;
65+
}
66+
}
67+
68+
/**
69+
* Returns the value at row, col
70+
*/
71+
char* getValue(const Worksheet *worksheet, int row, int column) {
72+
return worksheet->cells[row][column];
73+
}
74+
75+
int getValue2(const Worksheet *w, char **buffer, int row, int column)
76+
{
77+
if (w == NULL) return 0;
78+
if (w->cells[row][column] == NULL) return 0;
79+
80+
*buffer = malloc(sizeof(char) * strlen(w->cells[row][column]) + 1);
81+
strcpy(*buffer, w->cells[row][column]);
82+
83+
return 1;
84+
}
85+
86+
/**
87+
* Converts the given location (row, column) to a spreadsheet cell reference i.e. A1
88+
*/
89+
CellReference *convertToCellReference(const MatrixLocation *location)
90+
{
91+
CellReference *ref = malloc(sizeof(CellReference));
92+
93+
char *colRef = malloc(sizeof(char) * getNumberOfDigits(location->col) + 1);
94+
sprintf(colRef, "%d", location->col + 1);
95+
96+
// row ref + col ref + null terminator
97+
ref->cellReference = malloc(sizeof(char) * (1 + strlen(colRef) + 1) + 1);
98+
sprintf(ref->cellReference, "%c%s", (char)(location->row + ROW_TO_ASCII_OFFSET), colRef);
99+
free(colRef);
100+
101+
return ref;
102+
}
103+
104+
/**
105+
* Returns a pointer to a MatrixLocation structure
106+
*/
107+
MatrixLocation *convertToMatrixLocation(const CellReference *ref)
108+
{
109+
MatrixLocation *loc = malloc(sizeof(MatrixLocation));
110+
loc->row = ((int) toupper(ref->cellReference[0])) - ROW_TO_ASCII_OFFSET;
111+
112+
char *col = calloc(sizeof(char) + strlen(ref->cellReference), sizeof(char));
113+
col = strncpy(col, ref->cellReference + 1, strlen(ref->cellReference) - 1);
114+
loc->col = atoi(col) - 1;
115+
free(col);
116+
return loc;
117+
}
118+
119+
/**
120+
* Checks if a given formula at row, col refers to some cells which themselves
121+
* refer back to row,col
122+
*
123+
* Returns 0 if an error is encountered.
124+
*/
125+
int isCyclicRefError(const Worksheet *worksheet, int row, int col)
126+
{
127+
MatrixLocation m = { row, col };
128+
129+
CellReference *cellRef = convertToCellReference(&m);
130+
int result = isCyclicError(worksheet, "", cellRef);
131+
132+
free(cellRef->cellReference);
133+
free(cellRef);
134+
return result;
135+
}
136+
137+
/**
138+
* An internal function for checking cyclic reference dependency error.
139+
*
140+
* ==========
141+
* Returns 1 if cyclic dependency is found, 0 if otherwise
142+
*/
143+
static int isCyclicError(const Worksheet *worksheet, const char *visitedCells, CellReference *cellRef)
144+
{
145+
pcre2_match_data *match_data = NULL;
146+
char *saveptr = NULL;
147+
int rc = 0;
148+
149+
MatrixLocation *m = convertToMatrixLocation(cellRef);
150+
151+
char *cellValue = NULL;
152+
getValue2(worksheet, &cellValue, m->row, m->col);
153+
free(m);
154+
155+
if (cellValue == NULL)
156+
{
157+
return 0;
158+
}
159+
160+
// do work on working copy
161+
char *token = NULL;
162+
token = strtok_r(cellValue, " ", &saveptr);
163+
pcre2_code *re = getCellReferencePattern();
164+
while(token != NULL)
165+
{
166+
match_data = pcre2_match_data_create(20, NULL);
167+
int subjectLength = strlen(token);
168+
rc = pcre2_match(re, (PCRE2_SPTR) token, subjectLength, 0, 0, match_data, NULL);
169+
170+
if (rc > 0)
171+
{
172+
// search if current cellref is in the visited cells
173+
pcre2_code *searchVal = compilePattern(token);
174+
int isCyclicDependency = pcre2_match(searchVal, (PCRE2_SPTR) visitedCells, strlen(visitedCells), 0, 0, match_data, NULL);
175+
if (isCyclicDependency > 0)
176+
{
177+
free(cellValue);
178+
free(match_data);
179+
free(searchVal);
180+
free(re);
181+
return 1;
182+
}
183+
184+
free(searchVal);
185+
186+
//length of existing visitedCells + space character + length of cellRef to be appended + null terminator
187+
char *newVisitedCells = malloc(sizeof(char) * (strlen(visitedCells) + 1 + strlen(cellRef->cellReference)) + 1);
188+
strcpy(newVisitedCells, visitedCells);
189+
strcat(newVisitedCells, " ");
190+
strcat(newVisitedCells, cellRef->cellReference);
191+
192+
CellReference *tokenCellRef = malloc(sizeof(CellReference));
193+
tokenCellRef->cellReference = token;
194+
195+
if(isCyclicError(worksheet, (const char *) newVisitedCells, tokenCellRef))
196+
{
197+
free(cellValue);
198+
free(newVisitedCells);
199+
free(match_data);
200+
free(re);
201+
return 1;
202+
}
203+
204+
free(newVisitedCells);
205+
free(tokenCellRef);
206+
}
207+
token = strtok_r(NULL, " ", &saveptr);
208+
free(match_data);
209+
}
210+
211+
free(cellValue);
212+
free(re);
213+
return 0;
214+
}
215+

solutions/c/spreadsheet/matrix.h

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
2+
typedef struct
3+
{
4+
char ***cells;
5+
int rows;
6+
int cols;
7+
} Worksheet;
8+
9+
typedef struct
10+
{
11+
int row;
12+
int col;
13+
} MatrixLocation;
14+
15+
typedef struct
16+
{
17+
char *cellReference;
18+
} CellReference;
19+
20+
// The maximum content of a cell (4k)
21+
#define CELL_CONTENT_LIMIT 2048
22+
23+
#define ROW_TO_ASCII_OFFSET 65
24+
25+
/**
26+
* Initializes the 2d matrix of size rows * columns.
27+
*
28+
* Returns 0 if an error is encountered.
29+
*/
30+
int initWorksheet(Worksheet *worksheet, int rows, int columns);
31+
32+
/**
33+
* Closes and releases the resources of the worksheet
34+
*/
35+
int closeWorksheet(Worksheet *w);
36+
37+
/**
38+
* Returns 1 if a cyclic dependency is detected. 0 if otherwise.
39+
*/
40+
int isCyclicRefError(const Worksheet *worksheet, int row, int col);
41+
42+
/**
43+
* Sets cellContent into the worksheet
44+
*/
45+
int setValue(Worksheet *worksheet, int row, int column, char *cellContent);
46+
47+
/**
48+
* Returns the value at row, col
49+
*/
50+
char* getValue(const Worksheet *worksheet, int row, int column);
51+
52+
/**
53+
* Returns the value at row, col and writes it into the buffer.
54+
*
55+
* Usage:
56+
*
57+
* char *buffer;
58+
* getValue2(w, &buffer, row, column);
59+
*
60+
*/
61+
int getValue2(const Worksheet *w, char **buffer, int row, int column);
62+
63+
/**
64+
* Returns a pointer to a CellReference structure
65+
*/
66+
CellReference *convertToCellReference(const MatrixLocation *matrixLocation);
67+
68+
/**
69+
* Returns a pointer to a MatrixLocation structure
70+
*/
71+
MatrixLocation *convertToMatrixLocation(const CellReference *cellReference);
72+
73+

solutions/c/spreadsheet/matrixTest

17.3 KB
Binary file not shown.

0 commit comments

Comments
 (0)