Skip to content
This repository was archived by the owner on Dec 12, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions problems/skiing-in-singapore/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
# Skiing in Singapore
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:

====================

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.

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.
Expand Down
27 changes: 27 additions & 0 deletions problems/spreadsheet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Programming Challenge

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.

The spreadsheet input is defined as follows:

1. Line 1: two integers, defining the width and height of the spreadsheet (n, m)

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, ...)

## The Input
3 2
A2
4 5 *
A1
A1 B2 / 2 +
3
39 B1 B2 * /

## The Output
3 2
20.00000
20.00000
20.00000
8.66667
3.00000
1.50000
7 changes: 7 additions & 0 deletions solutions/c/spreadsheet/3x2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
3 2
A2
4 5 *
A1
A1 B2 / 2 +
3
39 B1 B2 * /
11 changes: 11 additions & 0 deletions solutions/c/spreadsheet/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

all: spreadsheet

spreadsheet: spreadsheet.c matrix.c matrix.h stackcalc.h stackcalc.c regex.h regex.c commons.h commons.c
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

test: matrix_test.c regex.c commons.c regex.h matrix.h stackcalc.h stackcalc.c
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

clean:
rm -f *.o a.out spreadsheet core
12 changes: 12 additions & 0 deletions solutions/c/spreadsheet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Dependencies

This program depends on the following:
1. pcre2-10.20 - Pattern matching, regular expression
2. cmocka-1.0.0 - For Unit Tests

Please refer to their respective documentations on how to install these libraries into your respective system

# Execution
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


14 changes: 14 additions & 0 deletions solutions/c/spreadsheet/commons.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include "commons.h"

int getNumberOfDigits(int n)
{
if (n < 0) return -1;
if (n < 10) return 1;
if (n < 100) return 2;
if (n < 1000) return 3;
if (n < 10000) return 4;
if (n < 100000) return 5;
if (n < 1000000) return 6;

return -1;
}
6 changes: 6 additions & 0 deletions solutions/c/spreadsheet/commons.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

/**
* Returns the number of digits in the integer n
*/
int getNumberOfDigits(int n);

215 changes: 215 additions & 0 deletions solutions/c/spreadsheet/matrix.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
#define _XOPEN_SOURCE 700
#define PCRE2_CODE_UNIT_WIDTH 8

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <pcre2.h>

#include "regex.h"
#include "matrix.h"
#include "commons.h"

// ~ Static function propotypes ==================
static int isCyclicError(const Worksheet *worksheet, const char *visitedCells, CellReference *cellReference);

/**
* Initializes the worksheet cells of size rows * columns.
*
* Returns 0 if an error is encountered.
*/
int initWorksheet(Worksheet *worksheet, int rows, int columns) {
worksheet->rows = rows;
worksheet->cols = columns;

char ***matrix = (char ***) malloc(sizeof(char **) * rows);
for(int i = 0; i < rows; i++) {
matrix[i] = (char **) malloc(sizeof(char *) * columns);

for(int j = 0; j < columns; j++) {
matrix[i][j] = (char *) calloc(sizeof(char) * CELL_CONTENT_LIMIT, sizeof(char));
}
}

worksheet->cells = matrix;
return 1;
}

int closeWorksheet(Worksheet *w)
{
for(int i = 0; i < w->rows; i++)
{
for(int j = 0; j < w->cols; j++)
{
free(w->cells[i][j]);
}
free(w->cells[i]);
}
free(w->cells);
free(w);
return 1;
}

/**
* Sets s to the worksheet cell at row, column.
*
* Returns 0 if strlen(s) > CELL_CONTENT_LIMIT
*/
int setValue(Worksheet *worksheet, int row, int column, char* s) {
if (strlen(s) <= CELL_CONTENT_LIMIT) {
strncpy(worksheet->cells[row][column], s, strlen(s));
return 1;
} else {
return 0;
}
}

/**
* Returns the value at row, col
*/
char* getValue(const Worksheet *worksheet, int row, int column) {
return worksheet->cells[row][column];
}

int getValue2(const Worksheet *w, char **buffer, int row, int column)
{
if (w == NULL) return 0;
if (w->cells[row][column] == NULL) return 0;

*buffer = malloc(sizeof(char) * strlen(w->cells[row][column]) + 1);
strcpy(*buffer, w->cells[row][column]);

return 1;
}

/**
* Converts the given location (row, column) to a spreadsheet cell reference i.e. A1
*/
CellReference *convertToCellReference(const MatrixLocation *location)
{
CellReference *ref = malloc(sizeof(CellReference));

char *colRef = malloc(sizeof(char) * getNumberOfDigits(location->col) + 1);
sprintf(colRef, "%d", location->col + 1);

// row ref + col ref + null terminator
ref->cellReference = malloc(sizeof(char) * (1 + strlen(colRef) + 1) + 1);
sprintf(ref->cellReference, "%c%s", (char)(location->row + ROW_TO_ASCII_OFFSET), colRef);
free(colRef);

return ref;
}

/**
* Returns a pointer to a MatrixLocation structure
*/
MatrixLocation *convertToMatrixLocation(const CellReference *ref)
{
MatrixLocation *loc = malloc(sizeof(MatrixLocation));
loc->row = ((int) toupper(ref->cellReference[0])) - ROW_TO_ASCII_OFFSET;

char *col = calloc(sizeof(char) + strlen(ref->cellReference), sizeof(char));
col = strncpy(col, ref->cellReference + 1, strlen(ref->cellReference) - 1);
loc->col = atoi(col) - 1;
free(col);
return loc;
}

/**
* Checks if a given formula at row, col refers to some cells which themselves
* refer back to row,col
*
* Returns 0 if an error is encountered.
*/
int isCyclicRefError(const Worksheet *worksheet, int row, int col)
{
MatrixLocation m = { row, col };

CellReference *cellRef = convertToCellReference(&m);
int result = isCyclicError(worksheet, "", cellRef);

free(cellRef->cellReference);
free(cellRef);
return result;
}

/**
* An internal function for checking cyclic reference dependency error.
*
* ==========
* Returns 1 if cyclic dependency is found, 0 if otherwise
*/
static int isCyclicError(const Worksheet *worksheet, const char *visitedCells, CellReference *cellRef)
{
pcre2_match_data *match_data = NULL;
char *saveptr = NULL;
int rc = 0;

MatrixLocation *m = convertToMatrixLocation(cellRef);

char *cellValue = NULL;
getValue2(worksheet, &cellValue, m->row, m->col);
free(m);

if (cellValue == NULL)
{
return 0;
}

// do work on working copy
char *token = NULL;
token = strtok_r(cellValue, " ", &saveptr);
pcre2_code *re = getCellReferencePattern();
while(token != NULL)
{
match_data = pcre2_match_data_create(20, NULL);
int subjectLength = strlen(token);
rc = pcre2_match(re, (PCRE2_SPTR) token, subjectLength, 0, 0, match_data, NULL);

if (rc > 0)
{
// search if current cellref is in the visited cells
pcre2_code *searchVal = compilePattern(token);
int isCyclicDependency = pcre2_match(searchVal, (PCRE2_SPTR) visitedCells, strlen(visitedCells), 0, 0, match_data, NULL);
if (isCyclicDependency > 0)
{
free(cellValue);
free(match_data);
free(searchVal);
free(re);
return 1;
}

free(searchVal);

//length of existing visitedCells + space character + length of cellRef to be appended + null terminator
char *newVisitedCells = malloc(sizeof(char) * (strlen(visitedCells) + 1 + strlen(cellRef->cellReference)) + 1);
strcpy(newVisitedCells, visitedCells);
strcat(newVisitedCells, " ");
strcat(newVisitedCells, cellRef->cellReference);

CellReference *tokenCellRef = malloc(sizeof(CellReference));
tokenCellRef->cellReference = token;

if(isCyclicError(worksheet, (const char *) newVisitedCells, tokenCellRef))
{
free(cellValue);
free(newVisitedCells);
free(match_data);
free(re);
return 1;
}

free(newVisitedCells);
free(tokenCellRef);
}
token = strtok_r(NULL, " ", &saveptr);
free(match_data);
}

free(cellValue);
free(re);
return 0;
}

73 changes: 73 additions & 0 deletions solutions/c/spreadsheet/matrix.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@

typedef struct
{
char ***cells;
int rows;
int cols;
} Worksheet;

typedef struct
{
int row;
int col;
} MatrixLocation;

typedef struct
{
char *cellReference;
} CellReference;

// The maximum content of a cell (4k)
#define CELL_CONTENT_LIMIT 2048

#define ROW_TO_ASCII_OFFSET 65

/**
* Initializes the 2d matrix of size rows * columns.
*
* Returns 0 if an error is encountered.
*/
int initWorksheet(Worksheet *worksheet, int rows, int columns);

/**
* Closes and releases the resources of the worksheet
*/
int closeWorksheet(Worksheet *w);

/**
* Returns 1 if a cyclic dependency is detected. 0 if otherwise.
*/
int isCyclicRefError(const Worksheet *worksheet, int row, int col);

/**
* Sets cellContent into the worksheet
*/
int setValue(Worksheet *worksheet, int row, int column, char *cellContent);

/**
* Returns the value at row, col
*/
char* getValue(const Worksheet *worksheet, int row, int column);

/**
* Returns the value at row, col and writes it into the buffer.
*
* Usage:
*
* char *buffer;
* getValue2(w, &buffer, row, column);
*
*/
int getValue2(const Worksheet *w, char **buffer, int row, int column);

/**
* Returns a pointer to a CellReference structure
*/
CellReference *convertToCellReference(const MatrixLocation *matrixLocation);

/**
* Returns a pointer to a MatrixLocation structure
*/
MatrixLocation *convertToMatrixLocation(const CellReference *cellReference);


Binary file added solutions/c/spreadsheet/matrixTest
Binary file not shown.
Loading