#include "grid.h" #include #include #include /* * The grid type this program is build around. */ typedef struct grid_data { char *rost; int height; int width; state state; } 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->rost = malloc(grid_size * sizeof(char)); gp->height = height; gp->width = width; gp->state = STATE_BEGIN; strcpy(gp->rost, input); return gp; } /* * Sets a grids width and height * * Input: * fh: the stream to read the grid from. * rost: a grid file to store the width and height in. * * 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 *rost) { while (getc(fh) != '\n') { if (feof(fh)) { return 0; } rost->width++; } if (rost->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) % (rost->width + 1) != 0) { // Not all lines are the same width return 0; } rost->height = (int)ftell(fh) / (int)sizeof(char) / (rost->width + 1); fseek(fh, 0, SEEK_SET); return 1; } grid *grid_create_from_file(FILE *fh) { if (fh == NULL) { return NULL; } grid rost = { NULL, 0, 0, STATE_BEGIN }; // Sets the width and height of the grid. if (get_grid_sizes(fh, &rost) != 1) { // Unlogical file structure. return NULL; } const int grid_size = (rost.width + 1) * rost.height + 1; rost.rost = malloc(grid_size * sizeof(char)); if (rost.rost == NULL) { return NULL; } // This makes the strncat() work. rost.rost[0] = '\0'; char *line = malloc((rost.width + 2) * sizeof(char)); if (line == NULL) { return NULL; } for (int i = 0; i < rost.height; i++) { if (fgets(line, rost.width + 2, fh) == NULL) { free(rost.rost); free(line); return NULL; } // Validate that the line length is correct if ((int)strcspn(line, "\n") != rost.width) { free(rost.rost); free(line); return NULL; } // Width is without the newline at the end. strncat(rost.rost, line, rost.width + 1); } free(line); grid *return_grid = malloc(sizeof(rost)); if (return_grid == NULL) { return NULL; } memcpy(return_grid, &rost, sizeof(rost)); 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->rost != NULL) { free(gp->rost); } 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->rost != 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->rost != NULL && grid_contains(gp, x, y) == 1) { return gp->rost[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->rost != NULL && grid_contains(gp, x, y) == 1) { gp->rost[internal_location(gp, x, y)] = c; return 1; } return 0; } char *grid_fetch_row(const grid *gp, const int y) { if (gp != NULL && gp->rost != 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->rost[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->rost != NULL) { const size_t grid_memory = ((gp->width + 1) * gp->height + 1) * sizeof(char); char *rost = malloc(grid_memory); if (rost == NULL) { return NULL; } grid *new_grid = malloc(sizeof(*gp)); if (new_grid == NULL) { return NULL; } memcpy(rost, gp->rost, grid_memory); memcpy(new_grid, gp, sizeof(*gp)); new_grid->rost = rost; return new_grid; } return NULL; } void grid_find(const grid *gp, const char c, int *x, int *y) { if (gp == NULL || gp->rost == NULL) { *x = -1; *y = -1; return; } const char search[2] = {c}; const int char_index = (int)strcspn(gp->rost, search); if (gp->rost[char_index] == '\0') { *x = -1; *y = -1; return; } *x = char_index % (gp->width + 1); *y = char_index / (gp->width + 1); }