Skip to content
This repository was archived by the owner on Dec 12, 2023. It is now read-only.

Commit acaa87e

Browse files
committed
Added spreadsheet problem set and solution; Fixed spelling errors in skiing in singapore problem
1 parent b1012cd commit acaa87e

File tree

22 files changed

+817
-1
lines changed

22 files changed

+817
-1
lines changed

problems/skiing-in-singapore/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
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:
2+
I came across this programming exercise 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 exercise challenge and try to implement it using c. So without further ado, the challenge description goes like this:
33

44
====================
55

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: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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
28+
29+
# Dependencies
30+
31+
This program depends on the following:
32+
1. pcre2-10.20 - Pattern matching, regular expression
33+
2. cmocka-1.0.0 - For Unit Tests
34+
35+
Please refer to their respective documentations on how to install these libraries into your respective system
36+
37+
# Execution
38+
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
39+
40+

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+
Binary file not shown.
Binary file not shown.

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+

0 commit comments

Comments
 (0)