/* * Warehouse for JoeyLib - A Sokoban Clone * Copyright (C) 2020 Scott Duensing * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ // Puzzles can be up to 20x12 in size. // https://www.letslogic.com/ #include #include #include #include #define MAX_WIDTH 20 #define MAX_HEIGHT 12 #define MAX_LINE 8192 typedef struct PuzzleS { char puzzle[MAX_WIDTH][MAX_HEIGHT]; unsigned char crates; unsigned char targets; unsigned char width; char height; int16_t area; } PuzzleT; static char puzzleChars[] = { "_# .$@+*" }; int isLegal(char c) { int x; if (c == '-') c = ' '; for (x=0; x<(int)strlen(puzzleChars); x++) { if (puzzleChars[x] == c) { return x + 1; } } return 0; } int dumbImporter(int argc, char *argv[]) { char puzzle[MAX_WIDTH][MAX_WIDTH]; char line[MAX_LINE]; // Ooo! Look! Potential buffer overflow! char height; unsigned char width; unsigned char b1; unsigned char b2; int16_t x; int16_t y; int16_t count; int32_t bytes; FILE *in; FILE *puzzles; FILE *index; if (argc != 4) { printf("%s: [letslogic.txt] [puzzles.dat] [index.dat]\n", argv[0]); return 1; } in = fopen(argv[1], "rt"); if (!in) { printf("Unable to read %s\n", argv[1]); return 2; } puzzles = fopen(argv[2], "wb"); if (!puzzles) { fclose(in); printf("Unable to write %s\n", argv[2]); return 2; } index = fopen(argv[3], "wb"); if (!index) { fclose(puzzles); fclose(in); printf("Unable to write %s\n", argv[3]); return 2; } // Skip two bytes at the front of the index file to later write the puzzle count into. fputc(0, index); fputc(0, index); bytes = 0; count = 0; height = -1; width = 0; while (fgets(line, MAX_LINE, in)) { // Is there a newline to remove? if ((strlen(line) > 0) && (line[strlen(line) - 1] == '\n')) { line[strlen(line) - 1] = 0; } // Is there anything on this line? if (strlen(line) > 0) { // Is this a puzzle line? if (isLegal(line[0]) > 0) { // Got it. Read this line. if (width < strlen(line)) { width = strlen(line); //printf("Width %d\n", width); } height++; for (x=0; x= 0) { // Yep! Output it! height++; // Make it 1 based ('width' has been 1 based the whole time) if ((width & 1) == 1) { // Width must be even - fill new column with empty space for (y=0; ycrates - p2->crates); } int sortBySize(const void *a, const void *b) { PuzzleT *p1 = (PuzzleT *)a; PuzzleT *p2 = (PuzzleT *)b; return (p1->area - p2->area); } int sortingImporter(int argc, char *argv[]) { char *letsLogicIn; char *puzzleOut; char *indexOut; char line[MAX_LINE]; // Ooo! Look! Potential buffer overflow! unsigned char b1; unsigned char b2; int16_t count; int16_t size; int16_t x; int16_t y; int16_t z; int32_t bytes; FILE *in; FILE *puzzlesFile; FILE *indexFile; PuzzleT *puzzles; PuzzleT *temp; if (argc != 4) { printf("%s: [letslogic.txt] [puzzles.dat] [index.dat]\n", argv[0]); return 1; } letsLogicIn = argv[1]; puzzleOut = argv[2]; indexOut = argv[3]; // Open exported puzzles file from LetsLogic. in = fopen(letsLogicIn, "rt"); if (!in) { printf("Unable to read %s\n", letsLogicIn); return 2; } // Start with enough RAM for 100 puzzles. size = 100; puzzles = (PuzzleT *)malloc(sizeof(PuzzleT) * size); count = 0; puzzles[count].crates = 0; puzzles[count].targets = 0; puzzles[count].area = 0; puzzles[count].width = 0; puzzles[count].height = -1; // Read all puzzles into memory. while (fgets(line, MAX_LINE, in)) { // Is there a newline to remove? if ((strlen(line) > 0) && (line[strlen(line) - 1] == '\n')) { line[strlen(line) - 1] = 0; } // Is there anything on this line? if (strlen(line) > 0) { // Is this a puzzle line? if (isLegal(line[0]) > 0) { // Got it. Read this line. if (puzzles[count].width < strlen(line)) { puzzles[count].width = strlen(line); } puzzles[count].height++; for (x=0; x= 0) { // Yep! Finalize it! puzzles[count].height++; // Make it 1 based ('width' has been 1 based the whole time) if ((puzzles[count].width & 1) == 1) { // Width must be even - fill new column with empty space for (y=0; y 2) && (puzzles[count].height > 2)) { puzzles[count].area = puzzles[count].width * puzzles[count].height; //printf("Puzzle %d is %dx%d with %d crates\n", count, puzzles[count].width, puzzles[count].height, puzzles[count].crates); count++; // Do we need more RAM? if (count >= size) { size += 100; temp = (PuzzleT *)realloc(puzzles, sizeof(PuzzleT) * size); if (!temp) { printf("Unable to allocate RAM for puzzles!\n"); return 3; } puzzles = temp; } } // Reset for next pass. puzzles[count].crates = 0; puzzles[count].targets = 0; puzzles[count].area = 0; puzzles[count].width = 0; puzzles[count].height = -1; } } } } fclose(in); // Sort it for some kind of difficulty ramp. qsort(puzzles, count, sizeof(PuzzleT), sortBySize); qsort(puzzles, count, sizeof(PuzzleT), sortByCrates); // Write puzzles in our format. puzzlesFile = fopen(puzzleOut, "wb"); if (!puzzles) { printf("Unable to write %s\n", puzzleOut); return 4; } indexFile = fopen(indexOut, "wb"); if (!indexOut) { fclose(puzzlesFile); printf("Unable to write %s\n", indexOut); return 5; } // Write number of puzzles into index. fwrite(&count, sizeof(int16_t), 1, indexFile); bytes = 0; for (z=0; z