#include #include #include #include #include #define pt cout << #define pter cerr << #define nl '\n' #define in cin >> using namespace std; // -------- START RAII HELPERS-------- unsigned long allocatedMem = 0; void *alloc(size_t size) { void *ptr = malloc(size); if (ptr == nullptr) { pter "Memory allocation failed" << nl; return nullptr; } allocatedMem += 1; return ptr; } void dealloc(void *ptr) { if (ptr) free(ptr); allocatedMem -= 1; } bool assert_alloc() { return !allocatedMem; } // -------- END RAII HELPERS-------- struct Move { char player; int moveX; int moveY; }; struct Moves { int x; int y; vector moves; }; bool isValidPlayer(char c) { return c >= 'A' && c <= 'Z' && c != 'X'; } Moves serialize(const string &s) { // TODO: add check for impossible board sizes Moves result; istringstream iss(s); iss >> result.x >> result.y; result.x <<= 1; result.y <<= 1; string player; int x, y; while (iss >> player >> x >> y) { if (player == "END") break; if (!isValidPlayer(player[0])) { string err = "Invalid player: " + player; throw invalid_argument(err); } result.moves.push_back({player[0], x, y}); } return result; } char **allocBoard(int x, int y) { char **board = static_cast(alloc(x * sizeof(char *))); for (int i = 0; i < x; ++i) { board[i] = static_cast(alloc(y * sizeof(char))); } return board; } void initBoard(char **board, int x, int y) { for (int i = 0; i < x; ++i) { for (int j = 0; j < y; j++) { board[i][j] = (j & 1 || i & 1) ? ' ' : '.'; } } } char **allocAndInitBoard(int x, int y) { char **board = allocBoard(x, y); initBoard(board, x, y); return board; } void deallocBoard(char **board, int x) { for (int i = 0; i < x; ++i) { dealloc(board[i]); } dealloc(board); } void printBoard(char **board, int x, int y) { for (int i = 0; i < x; ++i) { for (int j = 0; j < y; ++j) { pt board[i][j]; } pt nl; } } char toLowerCase(char c) { return c | 32; } int normalizePlayer(char c) { return toLowerCase(c) - 'a'; } void printScores(map &points) { // TODO: change this to custom sort before submission vector > ranking(points.begin(), points.end()); sort(ranking.begin(), ranking.end(), [](const pair &a, const pair &b) { return a.second < b.second; }); // Print the ranks for (const auto &rank: ranking) { pt rank.first << ": " << rank.second << " boxes" << nl; } } bool isValidMove(int x, int y) { // TODO: simplify this return !(x & 1 != y & 1 && !(x & 1)); } void addPoint( map &points, char **board, int x, int y, char player ) { if (board[x][y] == ' ') { points[player]++; board[x][y] = player; } } void solveVertical( int moveX, int moveY, char **board, map &points, int x, int y, char player ) { // TODO: fix ambiguity: // - // | // - // in the condition above, we do not know what to do at the end of the board // need to check for x-1, x+1, y-1, y+1 // check for any box below current move if (moveX < x - 3 && board[moveX + 2][moveY] != ' ' && board[moveX + 1][moveY - 1] != ' ') { int rightEdge = moveY == y - 1 ? 1 : board[moveX + 1][moveY + 1] != ' '; if (rightEdge) { addPoint(points, board, moveX + 1, moveY, player); } } // check for any box above current move if (moveX > 1 && board[moveX - 2][moveY] != ' ' && board[moveX - 1][moveY - 1] != ' ') { int rightEdge = moveY == y - 1 ? 1 : board[moveX - 1][moveY + 1] != ' '; if (rightEdge) { addPoint(points, board, moveX - 1, moveY, player); } } } void solveHorizontal( int moveX, int moveY, char **board, map &points, int y, char player ) { if (moveY) { if (moveY == y - 1) { if (board[moveX][moveY - 2] != ' ' && ( board[moveX + 1][moveY - 1] != ' ' && board[moveX - 1][moveY - 1] != ' ')) { addPoint(points, board, moveX, moveY - 1, player); } } else { if (board[moveX][moveY - 2] != ' ' || board[moveX][moveY + 2] != ' ') { if (board[moveX + 1][moveY - 1] != ' ' && board[moveX - 1][moveY - 1] != ' ') { addPoint(points, board, moveX, moveY - 1, player); } if (board[moveX + 1][moveY + 1] != ' ' && board[moveX - 1][moveY + 1] != ' ') { addPoint(points, board, moveX, moveY + 1, player); } } } } else { if (board[moveX][moveY + 2] != ' ' && (board[moveX + 1][moveY + 1] != ' ' && board[moveX - 1][moveY + 1] != ' ')) { addPoint(points, board, moveX, moveY + 1, player); } } } void solve(Moves moves, char **board) { map points; for (Move &move: moves.moves) { int moveX = move.moveX; int moveY = move.moveY; char player = move.player; if (!isValidMove(moveX, moveY)) { pt "Invalid move by: " << player << " at (x, y): (" << moveX << ", " << moveY << ")" << nl; board[moveX][moveY] = 'X'; printBoard(board, moves.x, moves.y); printScores(points); pt "Exiting.." << nl; return; } board[moveX][moveY] = toLowerCase(player); // TODO: if (moveX % 2 == 0 && moveY % 2 == 1) { solveVertical(moveX, moveY, board, points, moves.x, moves.y, player); } else if (moveX % 2 == 1 && moveY % 2 == 0) { solveHorizontal(moveX, moveY, board, points, moves.y, player); } else { pt "Invalid move by: " << player << " at (x, y): (" << moveX << ", " << moveY << ")" << nl; board[moveX][moveY] = 'X'; printBoard(board, moves.x, moves.y); printScores(points); pt "Exiting.." << nl; return; } } printScores(points); printBoard(board, moves.x, moves.y); } /* void solve(Moves moves, char **board) { /* TODO: use custom arr for points over map *int *points = static_cast(alloc(26)); for (int i = 0; i < 26; i++) { points[i] = 0; }#1# map points; for (const auto &move: moves.moves) { int moveX = move.moveX; int moveY = move.moveY; char player = move.player; board[moveX][moveY] = toLowerCase(player); if (moveX % 2 == 0 && moveY % 2 == 1) { if (moveX > 0 && board[moveX - 1][moveY] == '|' && board[moveX - 1][moveY - 1] == '-' && board[moveX - 1][moveY + 1] == '-') { points[player]++; } if (moveX < moves.x - 1 && board[moveX + 1][moveY] == '|' && board[moveX + 1][moveY - 1] == '-' && board[moveX + 1][moveY + 1] == '-') { points[player]++; } } else if (moveX % 2 == 1 && moveY % 2 == 0) { if (moveY > 0 && board[moveX][moveY - 1] == '-' && board[moveX - 1][moveY - 1] == '|' && board[moveX + 1][moveY - 1] == '|') { points[player]++; } if (moveY < moves.y - 1 && board[moveX][moveY + 1] == '-' && board[moveX - 1][moveY + 1] == '|' && board[moveX + 1][moveY + 1] == '|') { points[player]++; } } } vector > ranking(points.begin(), points.end()); sort(ranking.begin(), ranking.end(), [](const pair &a, const pair &b) { return a.second < b.second; }); for (const auto &rank: ranking) { pt rank.first << ": " << rank.second << " boxes" << nl; } printBoard(board, moves.x, moves.y); // dealloc(points); } */ int init(char *fileName) { // --- IO START --- FILE *inp = fopen(fileName, "r"); if (inp == nullptr) { pter "File not found" << nl; return 1; } fseek(inp, 0L, SEEK_END); const long sz = ftell(inp); fseek(inp, 0L, SEEK_SET); char *fileInpPtr = static_cast(alloc(sz + 1 * sizeof(char))); fileInpPtr[sz] = '\0'; for (int i = 0; i < sz; ++i) { fscanf(inp, "%c", &fileInpPtr[i]); } // --- IO END --- // --- ALGORITHM START --- Moves moves = serialize(fileInpPtr); char **board = allocAndInitBoard(moves.x, moves.y); solve(moves, board); // --- ALGORITHM END --- // --- CLEANUP START --- dealloc(fileInpPtr); deallocBoard(board, moves.x); fclose(inp); if (!assert_alloc()) { pter "Memory leak detected" << nl; return 1; } // --- CLEANUP END --- return 0; } int main(int argc, char **argv) { if (argc < 2) { pter "No input file provided" << nl; return 1; } try { return init(argv[1]); } catch (const invalid_argument &e) { pter e.what() << nl; return 1; } }