diff options
| author | Physick <96335032+DegustatorPonos@users.noreply.github.com> | 2026-08-02 22:52:27 +0500 |
|---|---|---|
| committer | Physick <96335032+DegustatorPonos@users.noreply.github.com> | 2026-08-02 22:52:27 +0500 |
| commit | d1a1ebd54cabc6646f20f6b1b341751a2bf3c2ec (patch) | |
| tree | 71f7d5d2d0c5960b25e95f99981c5a2c330302be /src/puzzles | |
| parent | 5af3200076b72e2f9f19c202ab9d2a7364004017 (diff) | |
puzzle parser
Diffstat (limited to 'src/puzzles')
| -rw-r--r-- | src/puzzles/parser.c | 160 | ||||
| -rw-r--r-- | src/puzzles/puzzle.c | 6 | ||||
| -rw-r--r-- | src/puzzles/puzzle.h | 3 |
3 files changed, 164 insertions, 5 deletions
diff --git a/src/puzzles/parser.c b/src/puzzles/parser.c new file mode 100644 index 0000000..cb958e7 --- /dev/null +++ b/src/puzzles/parser.c @@ -0,0 +1,160 @@ +#include <string.h> +#include "puzzle.h" +#include <raylib.h> +#include <stdlib.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> + +/// Reads a uint8_t from file. +/// Assumes that the file is on the position +uint8_t read_u8(FILE *file) { + uint8_t outp; + fread(&outp, 1, 1, file); + return outp; +} + +/// Reads a uint32_t (little-endian) from file. +/// Assumes that the file is on the position +uint32_t read_u32(FILE *file) { + uint32_t outp = 0; + for (int i = 0; i < 4; i++) { + outp += ((uint32_t)read_u8(file)) << (i * 8); + } + return outp; +} + +/// Reads a double from file. +/// Assumes that the file is on the position +double read_double(FILE *file) { + double outp; + fread(&outp, sizeof(double), 1, file); + return outp; +} + +/// Reads a null terminated string from file. +/// Assumes that the file if on the position. +/// Allocates the string. +char *read_string(FILE *file) { + char buf[8192]; + size_t idx = 0; + int c; + + while (idx < sizeof(buf) - 1) { + c = fgetc(file); + + if (c == 0 || c == EOF) break; + + buf[idx] = (char)c; + idx += 1; + } + + buf[idx] = 0x0; + return strdup(buf); +} + +typedef enum { + TYPE_NULL = 0, + TYPE_BOOL = 1, + TYPE_NUM = 2, + TYPE_STRING = 3, + TYPE_LIST = 4, +} V1_IO_TYPE; + +void ReadPuzzleIO_V1(FILE *file, PuzzleIO *io) { + uint8_t type = read_u8(file); + + switch (type) { + case TYPE_NULL: // NULL + io->type = WREN_TYPE_NULL; + io->value = NULL; + break; + + case TYPE_BOOL: + { + bool *outp = malloc(sizeof(bool)); + *outp = read_u8(file) != 0; + io->type = WREN_TYPE_BOOL; + io->value = outp; + break; + } + + case TYPE_NUM: + { + double *outp = malloc(sizeof(double)); + *outp = read_double(file); + io->type = WREN_TYPE_NUM; + io->value = outp; + break; + } + + case TYPE_STRING: + io->type = WREN_TYPE_STRING; + io->value = read_string(file); + break; + + case TYPE_LIST: + TraceLog(LOG_ERROR, "The arrays are not yet supported"); + io->type = WREN_TYPE_NULL; + io->value = NULL; + break; + + default: + return; + } +} + +void readTestV1(FILE *file, Test *outp) { + outp->RecieverName = read_string(file); + outp->MainMethodSignature = read_string(file); + outp->argc = read_u32(file); + outp->argv = malloc(sizeof(PuzzleIO) * outp->argc); + + for (size_t i = 0; i < outp->argc; i++) { + ReadPuzzleIO_V1(file, &outp->argv[i]); + } + + ReadPuzzleIO_V1(file, &outp->ExpectedResult); +} + +// Reads file with the specification from puzzle_specs_v1.md. +// Assumes the first byte of the file was read and the file was not rewinded. +Puzzle *parseFileV1(FILE *file) { + Puzzle *outp = malloc(sizeof(Puzzle)); + if (outp == NULL) return NULL; + + outp->Name = read_string(file); + outp->Description = read_string(file); + outp->InitialCode = read_string(file); + outp->TestC = read_u32(file); + + outp->Tests = malloc(sizeof(Test) * outp->TestC); + for (size_t i = 0; i < outp->TestC; i++) { + readTestV1(file, &outp->Tests[i]); + } + + return outp; +} + +Puzzle *ReadPuzzleFromFile(const char *path) { + FILE *file = fopen(path, "r"); + if (file == NULL) { + perror("Failed to parse the puzzle file"); + return NULL; + } + + uint8_t spec_version = read_u8(file); + printf("Version: %d\n", spec_version); + Puzzle *outp = NULL; + switch (spec_version) { + case 1: + outp = parseFileV1(file); + break; + default: + TraceLog(LOG_ERROR, "Failed to parse the puzzle file: unknown spec version"); + break; + } + + fclose(file); + return outp; +} diff --git a/src/puzzles/puzzle.c b/src/puzzles/puzzle.c index 2da9ffc..6d0a4a0 100644 --- a/src/puzzles/puzzle.c +++ b/src/puzzles/puzzle.c @@ -41,9 +41,9 @@ void FreeTests(Test *Tests, size_t TestC) { if (TestC == 0 || Tests == NULL) return; for (size_t i = 0; i < TestC; i++) { Test *t = &Tests[i]; - free(t->RecieverName); - free(t->MainMethodSignature); - free(t->argv); + if (t->RecieverName != NULL) free(t->RecieverName); + if (t->MainMethodSignature != NULL) free(t->MainMethodSignature); + if (t->argv != NULL) free(t->argv); } free(Tests); } diff --git a/src/puzzles/puzzle.h b/src/puzzles/puzzle.h index e7aebb1..20193ca 100644 --- a/src/puzzles/puzzle.h +++ b/src/puzzles/puzzle.h @@ -56,8 +56,7 @@ typedef struct { Test *Tests; } Puzzle; -// TODO -void ReadPuzzleFromFile(const char *path); +Puzzle *ReadPuzzleFromFile(const char *path); void FreePuzzle(Puzzle *self); /// A prebuilt puzzle. Used for debuging |
