#include "rooster.h" #include #include #include /* * The rooster type this program is build around. */ typedef struct rooster_data { char *rost; int height; int width; toestand state; } rooster; /* * 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) { if (fh == NULL) { return 0; } 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 *rooster_lees(FILE *fh) { if (fh == NULL) { return NULL; } rooster rost = { NULL, 0, 0, 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 VERLOREN; } void rooster_zet_toestand(rooster *rp, toestand t) { if (rp != NULL) { switch (t) { case BEGIN: rp->state = BEGIN; break; case AAN_HET_SPELEN: rp->state = AAN_HET_SPELEN; break; case GEWONNEN: rp->state = GEWONNEN; break; case VERLOREN: rp->state = VERLOREN; 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; } 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); }