/* * Created by snapshot112 on 2/10/2025 */ #include "grid.h" #include #include #include /* * The grid type this program is build around. */ typedef struct grid_data { char *locations; int height; int width; state state; } grid; /* * Translate x and y coordinates to a location index on the grid. */ static int internal_location(const grid *gp, const int x, const int y) { return y * (gp->width + 1) + x; } grid *grid_create_from_string(const char* input) { int width = 0; int height = 0; const size_t len = strlen(input) / sizeof(char); if (input == NULL || len == 0) { printf("invalid input\n"); return NULL; } for (int i = 0; input[i] != '\n'; i++) { width++; } height = (int)len / (width + 1); for (int i = 0; i < height; i = i + width + 1) { if ((int)strcspn(&input[i], "\n") != width) { printf("line %d was not %d wide\n", i, width); return NULL; } } const int grid_size = (width + 1) * height + 1; grid *gp = malloc(sizeof(grid)); if (gp == NULL) { return NULL; } gp->locations = malloc(grid_size * sizeof(char)); gp->height = height; gp->width = width; gp->state = STATE_BEGIN; strcpy(gp->locations, input); return gp; } /* * Sets a grids width and height * * Input: * fh: The stream to read the grid from. * gp: A pointer to the grid whose width and height you want to set. * * Side effects: * the grid gets its width and height set * * Output: * 1 if the file width and height seem to match with its size * 0 otherwise */ static int get_grid_sizes(FILE *fh, grid *gp) { while (getc(fh) != '\n') { if (feof(fh)) { return 0; } gp->width++; } if (gp->width == 0) { return 0; } fseek(fh, 0, SEEK_END); // Get file size (- 1 for the blank newline and EOF at the end) if (ftell(fh) % (gp->width + 1) != 0) { // Not all lines are the same width return 0; } gp->height = (int)ftell(fh) / (int)sizeof(char) / (gp->width + 1); fseek(fh, 0, SEEK_SET); return 1; } grid *grid_create_from_file(FILE *fh) { if (fh == NULL) { return NULL; } grid temp_grid = { NULL, 0, 0, STATE_BEGIN }; // Sets the width and height of the grid. if (get_grid_sizes(fh, &temp_grid) != 1) { // Unlogical file structure. return NULL; } const int grid_size = (temp_grid.width + 1) * temp_grid.height + 1; temp_grid.locations = malloc(grid_size * sizeof(char)); if (temp_grid.locations == NULL) { return NULL; } // This makes the strncat() work. temp_grid.locations[0] = '\0'; char *line = malloc((temp_grid.width + 2) * sizeof(char)); if (line == NULL) { return NULL; } for (int i = 0; i < temp_grid.height; i++) { if (fgets(line, temp_grid.width + 2, fh) == NULL) { free(temp_grid.locations); free(line); return NULL; } // Validate that the line length is correct if ((int)strcspn(line, "\n") != temp_grid.width) { free(temp_grid.locations); free(line); return NULL; } // Width is without the newline at the end. strncat(temp_grid.locations, line, temp_grid.width + 1); } free(line); grid *return_grid = malloc(sizeof(temp_grid)); if (return_grid == NULL) { return NULL; } memcpy(return_grid, &temp_grid, sizeof(temp_grid)); return return_grid; } state grid_fetch_state(const grid *gp) { if (gp != NULL) { return gp->state; } return STATE_VERLOREN; } void grid_put_state(grid *gp, const state t) { if (gp != NULL) { switch (t) { case STATE_BEGIN: gp->state = STATE_BEGIN; break; case STATE_AAN_HET_SPELEN: gp->state = STATE_AAN_HET_SPELEN; break; case STATE_GEWONNEN: gp->state = STATE_GEWONNEN; break; case STATE_VERLOREN: gp->state = STATE_VERLOREN; break; case STATE_QUIT: gp->state = STATE_QUIT; break; } } } void grid_cleanup(grid *gp) { if (gp != NULL) { if (gp->locations != NULL) { free(gp->locations); } free(gp); } } int grid_width(const grid *gp) { if (gp == NULL) { return 0; } return gp->width; } int grid_height(const grid *gp) { if (gp == NULL) { return 0; } return gp->height; } int grid_contains(const grid *gp, const int x, const int y) { if (gp != NULL && gp->locations != NULL) { if (x >= 0 && y >= 0 && x < gp->width && y < gp->height) { return 1; } } return 0; } char grid_fetch(const grid *gp, const int x, const int y) { if (gp != NULL && gp->locations != NULL && grid_contains(gp, x, y) == 1) { return gp->locations[internal_location(gp, x, y)]; } return '\0'; } int grid_put(grid *gp, const int x, const int y, const char c) { if (gp != NULL && gp->locations != NULL && grid_contains(gp, x, y) == 1) { gp->locations[internal_location(gp, x, y)] = c; return 1; } return 0; } char *grid_fetch_row(const grid *gp, const int y) { if (gp != NULL && gp->locations != NULL && grid_contains(gp, 0, y) == 1) { // we're going to remove the newline so this is long enough char *row = malloc((gp->width + 1) * sizeof(char)); memcpy(row, &gp->locations[internal_location(gp, 0, y)], gp->width * sizeof(char)); row[gp->width] = '\0'; return row; } return NULL; } grid *grid_copy(const grid *gp) { if (gp != NULL && gp->locations != NULL) { const size_t grid_memory = ((gp->width + 1) * gp->height + 1) * sizeof(char); char *locations = malloc(grid_memory); if (locations == NULL) { return NULL; } grid *new_grid = malloc(sizeof(*gp)); if (new_grid == NULL) { return NULL; } memcpy(locations, gp->locations, grid_memory); memcpy(new_grid, gp, sizeof(*gp)); new_grid->locations = locations; return new_grid; } return NULL; } void grid_find(const grid *gp, const char c, int *x, int *y) { if (gp == NULL || gp->locations == NULL) { *x = -1; *y = -1; return; } const char search[2] = {c}; const int char_index = (int)strcspn(gp->locations, search); if (gp->locations[char_index] == '\0') { *x = -1; *y = -1; return; } *x = char_index % (gp->width + 1); *y = char_index / (gp->width + 1); }