#include "rooster.h" #include #include #include #include /* * The rooster type this program is build around. */ typedef struct rooster_data { char *rost; int height; int width; toestand state; } rooster; rooster *grid_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; rooster *rp = malloc(sizeof(rooster)); if (rp == NULL) { return NULL; } rp->rost = malloc(grid_size * sizeof(char)); rp->height = height; rp->width = width; rp->state = STATE_BEGIN; strcpy(rp->rost, input); return rp; } /* * Sets a grids width and height * * Input: * fh: the stream to read the grid from. * rost: a rooster file to store the width and height in. * * Side effects: * the rooster 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, rooster *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; fseek(fh, 0, SEEK_SET); return 1; } rooster *grid_from_file(FILE *fh) { if (fh == NULL) { return NULL; } rooster rost = { NULL, 0, 0, STATE_BEGIN }; // Sets the width and height of the rooster. 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); rooster *return_rooster = malloc(sizeof(rost)); if (return_rooster == NULL) { return NULL; } memcpy(return_rooster, &rost, sizeof(rost)); return return_rooster; } toestand rooster_vraag_toestand(const rooster *rp) { if (rp != NULL) { return rp->state; } return STATE_VERLOREN; } void rooster_zet_toestand(rooster *rp, toestand t) { if (rp != NULL) { switch (t) { case STATE_BEGIN: rp->state = STATE_BEGIN; break; case STATE_AAN_HET_SPELEN: rp->state = STATE_AAN_HET_SPELEN; break; case STATE_GEWONNEN: rp->state = STATE_GEWONNEN; break; case STATE_VERLOREN: rp->state = STATE_VERLOREN; break; case STATE_QUIT: rp->state = STATE_QUIT; break; } } } void rooster_klaar(rooster *rp) { if (rp != NULL) { if (rp->rost != NULL) { free(rp->rost); } free(rp); } } int rooster_breedte(const rooster *rp) { if (rp == NULL) { return 0; } return rp->width; } int rooster_hoogte(const rooster *rp) { if (rp == NULL) { return 0; } return rp->height; } static int internal_location(const rooster *rp, const int x, const int y) { return y * (rp->width + 1) + x; } int rooster_bevat(const rooster *rp, int x, int y) { if (rp != NULL && rp->rost != NULL) { if (x >= 0 && y >= 0 && x < rp->width && y < rp->height) { return 1; } } return 0; } char rooster_kijk(const rooster *rp, int x, int y) { if (rp != NULL && rp->rost != NULL && rooster_bevat(rp, x, y) == 1) { return rp->rost[internal_location(rp, x, y)]; } return '\0'; } int rooster_plaats(rooster *rp, int x, int y, char c) { if (rp != NULL && rp->rost != NULL && rooster_bevat(rp, x, y) == 1) { rp->rost[internal_location(rp, x, y)] = c; return 1; } return 0; } char *rooster_vraag_rij(const rooster *rp, int y) { if (rp != NULL && rp->rost != NULL && rooster_bevat(rp, 0, y) == 1) { // we're going to remove the newline so this is long enough char *row = malloc((rp->width + 1) * sizeof(char)); memcpy(row, &rp->rost[internal_location(rp, 0, y)], rp->width * sizeof(char)); row[rp->width] = '\0'; return row; } return NULL; } rooster *rooster_kopieer(const rooster *rp) { if (rp != NULL && rp->rost != NULL) { const size_t grid_memory = ((rp->width + 1) * rp->height + 1) * sizeof(char); char *grid = malloc(grid_memory); if (grid == NULL) { return NULL; } rooster *new_rooster = malloc(sizeof(*rp)); if (new_rooster == NULL) { return NULL; } memcpy(grid, rp->rost, grid_memory); memcpy(new_rooster, rp, sizeof(*rp)); new_rooster->rost = grid; return new_rooster; } return NULL; } void rooster_zoek(const rooster *rp, char c, int *x, int *y) { if (rp == NULL || rp->rost == NULL) { *x = -1; *y = -1; return; } const char search[2] = {c}; int strpos = strcspn(rp->rost, search); if (rp->rost[strpos] == '\0') { *x = -1; *y = -1; return; } *x = strpos % (rp->width + 1); *y = strpos / (rp->width + 1); }