From a72acd5f374a476c9d9e5204e225af1dbf7d305e Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Sun, 9 Aug 2020 20:19:39 -0500 Subject: [PATCH] Puzzles sorted for difficulty. Chasing IIgs memory corruption issues. --- importer/importer.pro | 2 +- importer/main.c | 202 +++++++++++++++++++++++++++++++++++++++- warehouse/main.c | 85 +++++++++-------- warehouse/warehouse.pro | 10 ++ 4 files changed, 258 insertions(+), 41 deletions(-) diff --git a/importer/importer.pro b/importer/importer.pro index 8b6e209..7e0157c 100644 --- a/importer/importer.pro +++ b/importer/importer.pro @@ -4,4 +4,4 @@ CONFIG -= app_bundle CONFIG -= qt SOURCES += \ - main.c + main.c diff --git a/importer/main.c b/importer/main.c index 1b2d097..6f080d3 100644 --- a/importer/main.c +++ b/importer/main.c @@ -17,10 +17,15 @@ * 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 @@ -30,6 +35,16 @@ #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[] = { "_# .$@+*" }; @@ -47,7 +62,7 @@ int isLegal(char c) { } -int main(int argc, char *argv[]) { +int dumbImporter(int argc, char *argv[]) { char puzzle[MAX_WIDTH][MAX_WIDTH]; char line[MAX_LINE]; // Ooo! Look! Potential buffer overflow! @@ -168,3 +183,186 @@ int main(int argc, char *argv[]) { return 0; } + + +int sortByCrates(const void *a, const void *b) { + PuzzleT *p1 = (PuzzleT *)a; + PuzzleT *p2 = (PuzzleT *)b; + + return (p1->crates - 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 @@ -34,6 +34,12 @@ segment "warehouse"; #endif +#ifdef DMALLOC +#define DMALLOC_FUNC_CHECK +#include "dmalloc.h" +#endif + + #define MAX_WIDTH 20 #define MAX_HEIGHT 12 @@ -98,7 +104,7 @@ static byte crateInitialCount; static byte cratesOnTarget; static byte cratesInitiallyOnTarget; -static char puzzleChars[] = { "_# .$@+*" }; +//static char puzzleChars[] = { "_# .$@+*" }; static CoordT tileLookup[TILE_COUNT] = { { 10 * 8, 0 }, @@ -114,16 +120,15 @@ static CoordT tileLookup[TILE_COUNT] = { void countSolved(void); void drawAvatar(void); -byte drawMenu(char *title, char *menuItems[], byte requestedWidth, byte *height, byte *offsetX, byte *offsetY); +byte drawMenu(const char *title, const char *menuItems[], byte *height, byte *offsetX, byte *offsetY); void drawPuzzle(void); void forceFullRedraw(void); void levelComplete(void); -void loadPuzzle(jint16 number); +void loadPuzzle(void); bool mainMenu(void); -char menu(char *title, char *menuItems[], char selected, byte width, byte offsetX, byte offsetY); +char menu(const char *title, const char *menuItems[], char selected); void moveCrate(byte sx, byte sy, byte dx, byte dy); void play(void); -void printPuzzle(char *message, byte which[MAX_WIDTH][MAX_HEIGHT]); void printAt(jlImgT *font, jint16 cx, jint16 cy, const char *what, ...); bool readInput(byte *key); void redraw(void); @@ -175,7 +180,7 @@ void drawAvatar(void) { } -byte drawMenu(char *title, char *menuItems[], byte requestedWidth, byte *height, byte *offsetX, byte *offsetY) { +byte drawMenu(const char *title, const char *menuItems[], byte *height, byte *offsetX, byte *offsetY) { jint16 count = 0; jint16 lx = ((byte)221 % 40) << 3; // Left-hand block ASCII @@ -191,7 +196,7 @@ byte drawMenu(char *title, char *menuItems[], byte requestedWidth, byte *height, jint16 x2; jint16 y2; jint16 y3; - byte width = requestedWidth; + byte width = 0; // 222 223 221 // 222 220 221 @@ -307,7 +312,7 @@ void levelComplete(void) { } -void loadPuzzle(jint16 number) { +void loadPuzzle(void) { FILE *in = NULL; byte x = 0; byte y = 0; @@ -319,14 +324,14 @@ void loadPuzzle(jint16 number) { crateCount = 0; cratesOnTarget = 0; - puzzleCurrent = number; // Skip to requested puzzle. - fseek(in, puzzleIndex[number - 1], SEEK_SET); + fseek(in, puzzleIndex[puzzleCurrent - 1], SEEK_SET); // Load width of puzzle fread(&puzzle.width, sizeof(byte), 1, in); // Load height of puzzle fread(&puzzle.height, sizeof(byte), 1, in); + // Load the puzzle itself for (y=0; y= 0) && running && !jlUtilMustExit()) { - choice = menu("Main Menu", options, choice, 0, 0, 0); + choice = menu("Main Menu", options, choice); switch (choice) { case 0: // Return to Game choice = -1; @@ -413,7 +418,7 @@ bool mainMenu(void) { break; case 4: // Reset Level - if (1 == menu("Reset Level?", reset, 0, 0, 0, 0)) { + if (1 == menu("Reset Level?", reset, 0)) { resetPuzzle(); forceFullRedraw(); choice = -1; @@ -421,7 +426,7 @@ bool mainMenu(void) { break; case 5: // Exit - running = (0 == menu("Exit Game?", yesno, 0, 0, 0, 0)); + running = (0 == menu("Exit Game?", yesno, 0)); break; } } @@ -430,13 +435,15 @@ bool mainMenu(void) { } -char menu(char *title, char *menuItems[], char selected, byte width, byte offsetX, byte offsetY) { +char menu(const char *title, const char *menuItems[], char selected) { byte count = 0; byte inMenuYOffset = 7; byte key; byte height; byte ox; byte oy; + byte offsetX = 0; + byte offsetY = 0; char result = -1; bool inMenu = true; jint16 rx = ((byte)175 % 40) << 3; // Right Arrows ASCII @@ -454,7 +461,7 @@ char menu(char *title, char *menuItems[], char selected, byte width, byte offset ox = offsetX; oy = offsetY; - count = drawMenu(title, menuItems, width, &height, &ox, &oy); + count = drawMenu(title, menuItems, &height, &ox, &oy); inMenuYOffset += oy; xpos = (ox + 2) * 8; @@ -633,7 +640,7 @@ void play(void) { // Load new level? if (puzzleLast != puzzleCurrent) { puzzleLast = puzzleCurrent; - loadPuzzle(puzzleCurrent); + loadPuzzle(); avatarXLast = -1; avatarYLast = -1; jlDrawClear(); @@ -648,20 +655,6 @@ void play(void) { } -void printPuzzle(char *message, byte which[MAX_WIDTH][MAX_HEIGHT]) { - byte bx = 0; // Board coordinates. - byte by = 0; - - printf("%s\n", message); - for (by=0; by