Add the ability to save and load your game.

This commit is contained in:
Jeremy Rand 2015-07-16 19:40:27 -05:00
parent 0bce2a1da6
commit 45ca073efa
5 changed files with 175 additions and 6 deletions

View File

@ -7,6 +7,8 @@
//
#include <conio.h>
#include <stdio.h>
#include <string.h>
#include "game.h"
@ -15,6 +17,7 @@
// Macros
#define SQUARE_XY(x, y) (theGame.squares[((y) * BOARD_SIZE) + (x)])
#define SAVE_GAME_FILE "a2sudoku.game"
// Typedefs
@ -80,12 +83,94 @@ void startGame(tDifficulty difficulty, tUpdatePosCallback callback)
SQUARE_XY(x, y).knownAtStart = true;
SQUARE_XY(x, y).correct = true;
}
refreshPos(x, y);
}
}
}
void saveGame(void)
{
FILE *saveFile = fopen(SAVE_GAME_FILE, "wb");
if (saveFile != NULL) {
bool isValid = true;
fwrite(&isValid, sizeof(isValid), 1, saveFile);
fwrite(&theGame, sizeof(theGame), 1, saveFile);
savePuzzle(theGame.puzzle, saveFile);
fclose(saveFile);
}
}
void deleteGame(void)
{
// So, I tried using unlink() from unistd.h but it seems it
// does nothing on an Apple // with cc65. Instead, I will
// just open the file for writing and close it again which
// will leave it empty. That way, there won't be a saved
// game in the file.
FILE *saveFile = fopen(SAVE_GAME_FILE, "wb");
if (saveFile != NULL) {
bool isValid = false;
fwrite(&isValid, sizeof(isValid), 1, saveFile);
fclose(saveFile);
}
}
#undef LOAD_GAME_DEBUG
bool loadGame(tUpdatePosCallback callback)
{
bool isValid = false;
bool result = false;
FILE *saveFile= fopen(SAVE_GAME_FILE, "rb");
if (saveFile == NULL) {
#ifdef LOAD_GAME_DEBUG
printf("Cannot open save game file\n");
cgetc();
#endif
return false;
}
if ((fread(&isValid, sizeof(isValid), 1, saveFile) != 1) ||
(!isValid)) {
fclose(saveFile);
#ifdef LOAD_GAME_DEBUG
printf("Save is not valid\n");
cgetc();
#endif
return false;
}
if (fread(&theGame, sizeof(theGame), 1, saveFile) != 1) {
fclose(saveFile);
deleteGame();
#ifdef LOAD_GAME_DEBUG
printf("Unable to read game from save\n");
cgetc();
#endif
return false;
}
theGame.callback = callback;
theGame.puzzle = loadPuzzle(saveFile);
fclose(saveFile);
deleteGame();
if (theGame.puzzle == NULL) {
#ifdef LOAD_GAME_DEBUG
printf("Unable to read puzzle from save\n");
cgetc();
#endif
return false;
}
return true;
}
void refreshAllPos(void)
{
tPos x, y;

View File

@ -43,5 +43,9 @@ extern bool toggleScratchValueAtPos(tPos x, tPos y, tSquareVal val);
// Returns false if the last move cannot be undone.
extern bool undoLastMove(void);
extern void saveGame(void);
extern bool loadGame(tUpdatePosCallback callback);
#endif /* defined(__a2sudoku__game__) */

View File

@ -128,4 +128,19 @@ tSquareVal getStartValueAtPos(tPuzzle *puzzle, tPos x, tPos y)
bool checkValueAtPos(tPuzzle *puzzle, tSquareVal val, tPos x, tPos y)
{
return (PUZZLE_SOLVED_VAL(PUZZLE_SQUARE(puzzle, x, y)) == val);
}
void savePuzzle(tPuzzle *puzzle, FILE *saveFile)
{
fwrite(puzzle, sizeof(*puzzle), 1, saveFile);
}
tPuzzle *loadPuzzle(FILE *saveFile)
{
if (fread(&thePuzzle, sizeof(thePuzzle), 1, saveFile) != 1)
return NULL;
return &thePuzzle;
}

View File

@ -9,6 +9,7 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#ifndef __a2sudoku__puzzles__
@ -50,5 +51,9 @@ extern tSquareVal getStartValueAtPos(struct tPuzzle *puzzle, tPos x, tPos y);
extern bool checkValueAtPos(struct tPuzzle *puzzle, tSquareVal val, tPos x, tPos y);
extern void savePuzzle(struct tPuzzle *puzzle, FILE *saveFile);
extern struct tPuzzle *loadPuzzle(FILE *saveFile);
#endif /* defined(__a2sudoku__puzzles__) */

View File

@ -517,24 +517,59 @@ void youWon(void)
bool playGame(void)
{
bool shouldSave = false;
bool gameLoaded = false;
char ch;
initUI();
clrscr();
printf("\n\nLoading your puzzle for you\n Please be patient...");
textMode();
if (loadGame(updatePos)) {
bool gotAnswer = false;
printf("\n\nYou have a saved puzzle!\n Would you like to continue it (Y/N)");
while (!gotAnswer) {
ch = cgetc();
switch (ch) {
case 'y':
case 'Y':
printf("\n\nLoading your saved puzzle");
gameLoaded = true;
gotAnswer = true;
shouldSave = true;
break;
case 'n':
case 'N':
gotAnswer = true;
break;
default:
printf("\007");
break;
}
}
}
cursorX = 0;
cursorY = 0;
drawGrid();
if (!gameLoaded) {
clrscr();
printf("\n\nLoading a new puzzle for you\n Please be patient...");
startGame(gameOptions.difficulty, updatePos);
}
startGame(gameOptions.difficulty, updatePos);
drawGrid();
refreshAllPos();
graphicsMode();
while (true) {
char ch;
bool shouldNotBeep = true;
bool shouldRefresh = false;
@ -568,6 +603,11 @@ bool playGame(void)
case 'Q':
case CH_ESC:
shutdownUI();
if (shouldSave) {
clrscr();
printf("\n\nSaving your puzzle so you can continue\n later...");
saveGame();
}
return false;
case 'i':
@ -637,51 +677,71 @@ bool playGame(void)
case '8':
case '9':
shouldNotBeep = setValueAtPos(cursorX, cursorY, ch - '0');
if (shouldNotBeep)
shouldSave = true;
break;
case CH_F1:
case '!':
shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 1);
if (shouldNotBeep)
shouldSave = true;
break;
case CH_F2:
case '@':
shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 2);
if (shouldNotBeep)
shouldSave = true;
break;
case CH_F3:
case '#':
shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 3);
if (shouldNotBeep)
shouldSave = true;
break;
case CH_F4:
case '$':
shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 4);
if (shouldNotBeep)
shouldSave = true;
break;
case CH_F5:
case '%':
shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 5);
if (shouldNotBeep)
shouldSave = true;
break;
case CH_F6:
case '^':
shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 6);
if (shouldNotBeep)
shouldSave = true;
break;
case CH_F7:
case '&':
shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 7);
if (shouldNotBeep)
shouldSave = true;
break;
case CH_F8:
case '*':
shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 8);
if (shouldNotBeep)
shouldSave = true;
break;
case CH_F9:
case '(':
shouldNotBeep = toggleScratchValueAtPos(cursorX, cursorY, 9);
if (shouldNotBeep)
shouldSave = true;
break;
case 'u':