From 8111301a14a77d2f9a49a09ed7f1ed8aa5a60e0d Mon Sep 17 00:00:00 2001 From: Jeremy Rand Date: Wed, 23 Jul 2014 09:45:10 -0500 Subject: [PATCH] More game logic --- game.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- game.h | 4 +- 2 files changed, 116 insertions(+), 2 deletions(-) diff --git a/game.c b/game.c index 2eff471..dad387b 100644 --- a/game.c +++ b/game.c @@ -7,6 +7,8 @@ */ +#include +#include #include "game.h" @@ -20,6 +22,7 @@ #define POS_TO_X(pos) ((pos) % (BOARD_SIZE + 2)) #define POS_TO_Y(pos) ((pos) / (BOARD_SIZE + 2)) #define X_Y_TO_POS(x, y) (((y) * (BOARD_SIZE + 2)) + (x)) +#define POS_IN_DIR(pos, dir) ((pos) + (dir)) // The maximum which the game supports in any one tile is 2^19 because that is // the largest number which fits in a 6 character tile. Once this is reached, @@ -96,11 +99,90 @@ void initGame(void) gNumEmptyTiles++; } } + + addRandomTile(); + addRandomTile(); +} + + +tPos nextPosInDir(tPos pos, tDir dir) +{ + tPos result = pos; + tPos nextPos; + tTileValue tileValue = gTileValues[pos]; + tTileValue nextValue; + + while (true) { + nextPos = POS_IN_DIR(result, dir); + nextValue = gTileValues[nextPos]; + + if ((nextValue != 0) && + (nextValue != tileValue)) + break; + + result = nextPos; + if (nextValue != 0) + break; + } + return result; } void slideInDirection(tDir dir) { + tPos pos; + tPos destPos; + int8_t incr; + + if (dir > 0) { + pos = 0; + incr = 1; + } else { + pos = NUM_TILES - 1; + incr = -1; + } + + for ( ; ((pos >= 0) && (pos < NUM_TILES)); pos += incr) { + if (gTileValues[pos] == BLOCKED_TILE_VALUE) + continue; + destPos = nextPosInDir(pos, dir); + if (destPos == pos) + continue; + + if (gTileValues[destPos] > 0) { + gTileValues[destPos]++; + gNumEmptyTiles++; + } else { + gTileValues[destPos] = gTileValues[pos]; + } + gTileValues[pos] = 0; // Empty the old position + } +} + + +void addRandomTile(void) +{ + int8_t randTile; + tPos pos; + + if (gNumEmptyTiles == 0) + return; + + randTile = (rand() % gNumEmptyTiles); + + for (pos = 0; pos < NUM_TILES; pos++) { + if (gTileValues[pos] == 0) { + if (randTile == 0) { + if (rand() < (RAND_MAX / 10)) + gTileValues[pos] = 2; // This creates a 4 + else + gTileValues[pos] = 1; // This creates a 2 + gNumEmptyTiles--; + return; + } + randTile--; + } + } } @@ -124,7 +206,37 @@ bool isGameWon(void) bool isGameLost(void) { - return (gNumEmptyTiles == 0); + tPos x; + tPos y; + tPos pos; + tTileValue tileValue; + + if (gNumEmptyTiles > 0) + return false; + + for (x = 1; x <= BOARD_SIZE; x++) { + for (y = 1; y <= BOARD_SIZE; y++) { + pos = X_Y_TO_POS(x, y); + tileValue = gTileValues[pos]; + + assert(tileValue > 0); + + // If a tile value matches another adjacent tile value, then there + // are still moves. + if (tileValue == gTileValues[POS_IN_DIR(pos, DIR_DOWN)]) + return false; + if (tileValue == gTileValues[POS_IN_DIR(pos, DIR_RIGHT)]) + return false; + + // Because we iterate over all tiles, we only need to check two of + // the four directions. That will compare all possible pairs. It + // will also check the edge against the blocking tiles but whatever. + } + } + + // If we get to here, there were no matching tiles so there are no available + // moves. + return true; } diff --git a/game.h b/game.h index e468faa..aa137d8 100644 --- a/game.h +++ b/game.h @@ -20,7 +20,7 @@ typedef int8_t tDir; -typedef uint8_t tPos; +typedef int8_t tPos; typedef uint32_t tScore; @@ -28,6 +28,8 @@ void initGame(void); void slideInDirection(tDir dir); +void addRandomTile(void); + tScore currentScore(void); tScore nextTarget(void);