cmpsc330hw2/main.cpp
Sandipsinh Rathod 8ff786df97
miscellaneous
2024-10-10 18:16:59 -04:00

354 lines
8.3 KiB
C++

#include <algorithm>
#include <iostream>
#include <map>
#include <sstream>
#include <vector>
#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<Move> 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);
}
Move move;
move.player = player[0];
move.moveX = x;
move.moveY = y;
result.moves.push_back(move);
}
return result;
}
char **allocBoard(int x, int y) {
char **board = static_cast<char **>(alloc(x * sizeof(char *)));
for (int i = 0; i < x; ++i) {
board[i] = static_cast<char *>(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 normalize(char c) {
return toLowerCase(c) - 'a';
}
void swap(pair<char, int> *a, int i, int j) {
pair<char, int> temp = a[i];
a[i] = a[j];
a[j] = temp;
}
void bubbleSort(pair<char, int> *a) {
for (int i = 0; i < 25; i++) {
for (int j = 0; j < 25 - i; j++) {
if (a[j].second > a[j + 1].second)
swap(a, j, j + 1);
}
}
}
void printScores(int *points) {
pair<char, int> *arr = static_cast<pair<char, int> *>(alloc(26 * sizeof(pair<char, int>)));
for (int i = 0; i < 26; i++) {
pair<char, int> p;
p.first = static_cast<char>(i + 'a');
p.second = points[i];
arr[i] = p;
}
bubbleSort(arr);
int prev = -1;
for (int i = 0; i < 26; i++) {
if (arr[i].second != -1) {
pt arr[i].first << ": " << arr[i].second << " boxes" << (
i == 25 || prev == arr[i].second ? " (win)\n" : nl);
prev = arr[i].second;
}
}
dealloc(arr);
}
bool isValidMove(int x, int y) {
return (x & 1) != (y & 1);
}
void addPoint(
int *points,
char **board,
int x,
int y,
char player
) {
if (board[x][y] == ' ') {
if (points[normalize(player)] == -1) {
points[normalize(player)] = 1;
} else {
points[normalize(player)]++;
}
board[x][y] = player;
}
}
void solveVertical(
int moveX,
int moveY,
char **board,
int *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,
int *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) {
int *points = static_cast<int *>(alloc(26 * (sizeof(int))));
for (int i = 0; i < 26; i++) {
points[i] = -1;
}
for (int i = 0; i < moves.moves.size(); i++) {
Move move = moves.moves[i];
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;
}
}
printBoard(board, moves.x, moves.y);
printScores(points);
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<char *>(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;
pter "Usage: dotsandboxes /path/to/input.txt" << nl;
return 1;
}
try {
return init(argv[1]);
} catch (const invalid_argument &e) {
pter e.what() << nl;
return 1;
}
}