From a8d2f7b47b79fdca3648b3e8d23b081036a4a0eb Mon Sep 17 00:00:00 2001 From: Christian Kroll Date: Mon, 7 Mar 2011 00:32:38 +0000 Subject: [PATCH] squeezed 216 bytes --- games/tetris/bucket.h | 7 +++-- games/tetris/highscore.c | 42 ++------------------------ games/tetris/highscore.h | 36 ++++++++++++++++++++--- games/tetris/input.c | 16 ++-------- games/tetris/input.h | 9 +++++- games/tetris/variant_bastet.c | 55 ++++++++++++++++++----------------- games/tetris/variant_bastet.h | 12 ++++---- games/tetris/variant_fp.h | 9 +++++- games/tetris/variant_std.c | 19 ++++++++++-- games/tetris/variant_std.h | 14 ++++++++- games/tetris/variants.h | 4 ++- 11 files changed, 125 insertions(+), 98 deletions(-) diff --git a/games/tetris/bucket.h b/games/tetris/bucket.h index ce74ade..dc371af 100644 --- a/games/tetris/bucket.h +++ b/games/tetris/bucket.h @@ -2,6 +2,7 @@ #define BUCKET_H_ #include +#include #include "../../config.h" #include "piece.h" @@ -11,6 +12,8 @@ ***********/ #define TETRIS_BUCKET_INVALIDROW -4 +#define TETRIS_BUCKET_MAX_COLUMNS (INT8_MAX - 4) +#define TETRIS_BUCKET_MAX_ROWS /********* @@ -85,7 +88,7 @@ tetris_bucket_iterator_t; /** * constructs a bucket with the given dimensions * @param nWidth width of bucket (4 <= n <= 16) - * @param nHeight height of bucket (4 <= n <= 124) + * @param nHeight height of bucket (4 <= n <= TETRIS_BUCKET_MAX_COLUMNS) * @return pointer to a newly created bucket */ tetris_bucket_t *tetris_bucket_construct(int8_t nWidth, @@ -291,7 +294,7 @@ inline static tetris_bucket_status_t tetris_bucket_getStatus(tetris_bucket_t *p) /** * returns the given row of the dump (as bitmap) * @param pBucket the bucket we want information from - * @param nRow the number of the row (0 <= nRow <= 124) + * @param nRow the number of the row (0 <= nRow <= TETRIS_BUCKET_MAX_COLUMNS) * @return bitmap of the requested row (LSB is leftmost column) */ inline static uint16_t tetris_bucket_getDumpRow(tetris_bucket_t *pBucket, diff --git a/games/tetris/highscore.c b/games/tetris/highscore.c index 8d0669a..ce6b9eb 100644 --- a/games/tetris/highscore.c +++ b/games/tetris/highscore.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "../../config.h" #include "../../scrolltext/scrolltext.h" #include "../../joystick/joystick.h" @@ -24,7 +25,7 @@ uint16_t tetris_highscore_inputName(void) while (1) { // we need our own blink interval - nBlink = (nBlink + 1) % 4; + nBlink = (nBlink + 1) % 4u; // construct command for scrolltext and execute static uint8_t const nOffset[3] = {15, 19, 23}; @@ -100,42 +101,5 @@ uint16_t tetris_highscore_retrieveHighscore(tetris_highscore_index_t nIndex) eeprom_read_word(&tetris_highscore[nIndex]); // a score of 65535 is most likely caused by uninitialized EEPROM addresses - if (nHighscore == 65535) - { - nHighscore = 0; - } - - return nHighscore; -} - - -void tetris_highscore_saveHighscore(tetris_highscore_index_t nIndex, - uint16_t nHighscore) -{ - if (nHighscore > tetris_highscore_retrieveHighscore(nIndex)) - { - eeprom_write_word(&tetris_highscore[nIndex], nHighscore); - } -} - - -uint16_t tetris_highscore_retrieveHighscoreName(tetris_highscore_index_t nIdx) -{ - uint16_t nHighscoreName = - eeprom_read_word(&tetris_highscore_name[nIdx]); - - // a value of 65535 is most likely caused by uninitialized EEPROM addresses - if (nHighscoreName == 65535) - { - nHighscoreName = 0; - } - - return nHighscoreName; -} - - -void tetris_highscore_saveHighscoreName(tetris_highscore_index_t nIndex, - uint16_t nHighscoreName) -{ - eeprom_write_word(&tetris_highscore_name[nIndex], nHighscoreName); + return nHighscore == UINT16_MAX ? 0 : nHighscore; } diff --git a/games/tetris/highscore.h b/games/tetris/highscore.h index 2e0f5a3..10e2994 100644 --- a/games/tetris/highscore.h +++ b/games/tetris/highscore.h @@ -2,6 +2,8 @@ #define TETRIS_HIGHSCORE_H_ #include +#include "../../compat/eeprom.h" + /** * indexes for different tetris variants @@ -20,6 +22,13 @@ enum tetris_highscore_index typedef enum tetris_highscore_index tetris_highscore_index_t; #endif + +// global array for the high score +extern uint16_t tetris_highscore[TETRIS_HISCORE_END] EEMEM; +// global array for the champion's initials +extern uint16_t tetris_highscore_name[TETRIS_HISCORE_END] EEMEM; + + /** * lets the user enter his initials (three characters) * @return name packed into a uint16_t @@ -37,11 +46,18 @@ uint16_t tetris_highscore_retrieveHighscore(tetris_highscore_index_t nIndex); /** * saves the high score into the storage (EEPROM) - * @param nIndex the variant dependent index of the high score + * @param nIdx the variant dependent index of the high score * @param nHighscoreName the high score */ +inline static void tetris_highscore_saveHighscore(tetris_highscore_index_t nIndex, - uint16_t nHighscore); + uint16_t nHighscore) +{ + if (nHighscore > tetris_highscore_retrieveHighscore(nIndex)) + { + eeprom_write_word(&tetris_highscore[nIndex], nHighscore); + } +} /** @@ -49,7 +65,14 @@ void tetris_highscore_saveHighscore(tetris_highscore_index_t nIndex, * @param nIdx the variant dependent index of the high score * @return the initials of the champion packed into a uint16_t */ -uint16_t tetris_highscore_retrieveHighscoreName(tetris_highscore_index_t nIdx); +inline static +uint16_t tetris_highscore_retrieveHighscoreName(tetris_highscore_index_t nIdx) +{ + uint16_t nHighscoreName = + eeprom_read_word(&tetris_highscore_name[nIdx]); + + return nHighscoreName; +} /** @@ -57,7 +80,12 @@ uint16_t tetris_highscore_retrieveHighscoreName(tetris_highscore_index_t nIdx); * @param nIndex the variant dependent index of the high score * @param nHighscoreName the initials of the champion packed into a uint16_t */ +inline static void tetris_highscore_saveHighscoreName(tetris_highscore_index_t nIndex, - uint16_t nHighscoreName); + uint16_t nHighscoreName) +{ + eeprom_write_word(&tetris_highscore_name[nIndex], nHighscoreName); +} + #endif /*TETRIS_HIGHSCORE_H_*/ diff --git a/games/tetris/input.c b/games/tetris/input.c index b9373f7..7cabf4b 100644 --- a/games/tetris/input.c +++ b/games/tetris/input.c @@ -140,23 +140,11 @@ static void tetris_input_chatterProtect(tetris_input_t *pIn, * @return mapped tetris command * @see tetris_input_command_t */ +static tetris_input_command_t tetris_input_mapCommand(tetris_bearing_t nBearing, tetris_input_command_t nCmd) { - static tetris_input_command_t const nMapping[] PROGMEM = - { - TETRIS_INCMD_DOWN, TETRIS_INCMD_ROT_CW, TETRIS_INCMD_RIGHT, - TETRIS_INCMD_LEFT, - - TETRIS_INCMD_RIGHT, TETRIS_INCMD_LEFT, TETRIS_INCMD_ROT_CW, - TETRIS_INCMD_DOWN, - - TETRIS_INCMD_ROT_CW, TETRIS_INCMD_DOWN, TETRIS_INCMD_LEFT, - TETRIS_INCMD_RIGHT - }; - - return (nBearing == TETRIS_BEARING_0) || (nCmd >= TETRIS_INCMD_ROT_CCW) ? - nCmd : (PM(nMapping[(nBearing - 1) * 4 + nCmd])); + return (nCmd < TETRIS_INCMD_ROT_CCW) ? (nCmd - nBearing + 4) % 4u : nCmd; } diff --git a/games/tetris/input.h b/games/tetris/input.h index 4a84da0..3b44a60 100644 --- a/games/tetris/input.h +++ b/games/tetris/input.h @@ -33,9 +33,9 @@ */ enum tetris_input_command { - TETRIS_INCMD_LEFT, /**< move piece left */ TETRIS_INCMD_RIGHT, /**< move piece right */ TETRIS_INCMD_DOWN, /**< lower piece by one row */ + TETRIS_INCMD_LEFT, /**< move piece left */ TETRIS_INCMD_ROT_CW, /**< rotate clockwise */ TETRIS_INCMD_ROT_CCW, /**< rotate counter clockwise */ TETRIS_INCMD_DROP, /**< move piece to the ground immediately */ @@ -43,6 +43,13 @@ enum tetris_input_command TETRIS_INCMD_PAUSE, /**< pause the game */ TETRIS_INCMD_NONE /**< idle (must alway be the last one) */ }; +/* R D L C + * RDLC 0 1 2 3 + * DLCR -1 -1 -1 -1 + * LCRD -2 -2 -2 -2 + * CRDL -3 -3 -3 -3 + */ + #ifdef NDEBUG typedef uint8_t tetris_input_command_t; #else diff --git a/games/tetris/variant_bastet.c b/games/tetris/variant_bastet.c index 9005896..0f2aaf8 100644 --- a/games/tetris/variant_bastet.c +++ b/games/tetris/variant_bastet.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "../../random/prng.h" #include "../../compat/pgmspace.h" #include "../../menu/menu.h" @@ -21,6 +22,12 @@ #define TETRIS_BASTET_HEIGHT_FACTOR 5 +#ifdef RANDOM_SUPPORT + #define RANDOM8() random8() +#else + #define RANDOM8() (rand() % (UINT8_MAX + 1)) +#endif + /*************************** * non-interface functions * @@ -34,21 +41,18 @@ static void tetris_bastet_doPreprocessing(tetris_bastet_variant_t *pBastet) { // retrieve sane start and stop values for the column and row indices - int8_t nWidth = tetris_bucket_getWidth(pBastet->pBucket); - int8_t nStartRow = tetris_bucket_getHeight(pBastet->pBucket) - 1; - int8_t nStopRow = tetris_bucket_getFirstTaintedRow(pBastet->pBucket); + int8_t const nWidth = tetris_bucket_getWidth(pBastet->pBucket); + int8_t const nStartRow = tetris_bucket_getHeight(pBastet->pBucket) - 1; + int8_t const nStopRow = tetris_bucket_getFirstTaintedRow(pBastet->pBucket); - // clear old precalculated scores - for (uint8_t i = 0; i < nWidth + 3; ++i) - { - pBastet->pColScore[i] = 0; - } + // clear old precalculated scores (last three elements are always 0) + memset(pBastet->pColScore, 0, nWidth * sizeof(int16_t)); // calculate the column heights of the actual bucket configuration - // NOTE: in this loop, pColScore contains the actual column heights, + // NOTE: in this loop, pColScore stores the actual column heights, // later it will contain the "score impact" of every unchanged column for (int8_t y = nStartRow; y >= nStopRow; --y) { - uint16_t nDumpRow = tetris_bucket_getDumpRow(pBastet->pBucket, y); + uint16_t const nDumpRow = tetris_bucket_getDumpRow(pBastet->pBucket, y); uint16_t nColMask = 0x0001; for (uint8_t x = 0; x < nWidth; ++x) { @@ -70,25 +74,21 @@ static void tetris_bastet_doPreprocessing(tetris_bastet_variant_t *pBastet) // calculate the maxima of the 4-tuples from column 0 to width-1 for (uint8_t i = 0; i < nWidth; ++i) { + // casting from int16_t to int8_t is safe here, since at this point + // pColScore only contains column heights which never exceed INT8_MAX-4 int8_t t0 = pBastet->pColScore[i] > pBastet->pColScore[i + 1] ? - i : i + 1; + pBastet->pColScore[i] : pBastet->pColScore[i + 1]; int8_t t1 = pBastet->pColScore[i + 2] > pBastet->pColScore[i + 3] ? - i + 2 : i + 3; - pBastet->pStartingRow[i + 3] = - pBastet->pColScore[t0] > pBastet->pColScore[t1] ? - pBastet->pColScore[t0] : pBastet->pColScore[t1]; + pBastet->pColScore[i + 2] : pBastet->pColScore[i + 3]; + pBastet->pStartingRow[i + 3] = t0 > t1 ? t0 : t1; } - // normalize to bucket geometry - for (uint8_t i = 0; i < nWidth + 3; ++i) + for (uint8_t i = nWidth + 3; i--;) { + // normalize to bucket geometry pBastet->pStartingRow[i] = nStartRow - pBastet->pStartingRow[i]; - } - - // calculate the score impact of every column - for (uint8_t x = 0; x < nWidth; ++x) - { - pBastet->pColScore[x] *= TETRIS_BASTET_HEIGHT_FACTOR; + // finally calculate the score impact of every column + pBastet->pColScore[i] *= TETRIS_BASTET_HEIGHT_FACTOR; } } @@ -309,7 +309,7 @@ void *tetris_bastet_construct(tetris_bucket_t *pBucket) pBastet->pBucket = pBucket; int8_t nWidth = tetris_bucket_getWidth(pBastet->pBucket); - pBastet->pColScore = (uint16_t*) calloc(nWidth + 3, sizeof(uint16_t)); + pBastet->pColScore = (int16_t*) calloc(nWidth + 3, sizeof(int16_t)); pBastet->pStartingRow = (int8_t*) calloc(nWidth + 3, sizeof(int8_t)); pBastet->pColHeights = (int8_t*) calloc(nWidth, sizeof(int8_t)); @@ -349,7 +349,7 @@ tetris_piece_t* tetris_bastet_choosePiece(void *pVariantData) // perturb score (-2 to +2) to avoid stupid tie handling for (uint8_t i = 0; i < 7; ++i) { - pBastet->nPieceScore[i].nScore += random8() % 5 - 2; + pBastet->nPieceScore[i].nScore += RANDOM8() % 5 - 2; } // sort pieces by their score in ascending order @@ -366,7 +366,7 @@ tetris_piece_t* tetris_bastet_choosePiece(void *pVariantData) tetris_piece_t *pPiece = NULL; uint8_t const nPercent[4] = {191, 235, 250, 255}; - uint8_t const nRnd = random8(); + uint8_t const nRnd = RANDOM8(); for (uint8_t i = 0; i < 4; ++i) { if (nRnd <= nPercent[i]) @@ -503,7 +503,8 @@ tetris_highscore_index_t tetris_bastet_getHighscoreIndex(void *pVariantData) void tetris_bastet_setLastInput(void *pVariantData, - tetris_input_command_t inCmd) + tetris_input_command_t inCmd, + uint8_t bMoveOk) { return; } diff --git a/games/tetris/variant_bastet.h b/games/tetris/variant_bastet.h index 9437d3f..6f7e0c4 100644 --- a/games/tetris/variant_bastet.h +++ b/games/tetris/variant_bastet.h @@ -40,7 +40,7 @@ typedef struct tetris_bastet_variant uint16_t nLines; /** number of completed lines */ tetris_piece_t *pPreviewPiece; /** the piece for the preview */ tetris_bucket_t *pBucket; /** bucket to be examined */ - uint16_t *pColScore; /** score impact of every column*/ + int16_t *pColScore; /** score impact of every column*/ int8_t *pStartingRow; /** starting point for collision*/ int8_t *pColHeights; /** predicted column heights */ tetris_bastet_scorepair_t nPieceScore[7]; /** score for every piece */ @@ -192,12 +192,14 @@ tetris_highscore_index_t tetris_bastet_getHighscoreIndex(void *pVariantData); /** - * informs the bastet instance about the player's last move - * @param pVariantData the variant data object we want to modify - * @param inCmd player's last command + * inform the Bastet instance about the player's last input + * @param pVariantData the Bastet object we want to modify + * @param inCmd the last issued command + * @param bMoveOk 1 if the last move was possible, otherwise 0 */ void tetris_bastet_setLastInput(void *pVariantData, - tetris_input_command_t inCmd); + tetris_input_command_t inCmd, + uint8_t bMoveOk); /** diff --git a/games/tetris/variant_fp.h b/games/tetris/variant_fp.h index 390b9a4..9b324b4 100644 --- a/games/tetris/variant_fp.h +++ b/games/tetris/variant_fp.h @@ -33,7 +33,14 @@ tetris_variant_t const tetrisFpVariant; tetris_highscore_index_t tetris_fp_getHighscoreIndex(void *pVariantData); +/** + * inform the First Person Tetris instance about the player's last input + * @param pVariantData the First Person Tetris data object we want to modify + * @param inCmd the last issued command + * @param bMoveOk 1 if the last move was possible, otherwise 0 + */ void tetris_fp_setLastInput(void *pVariantData, - tetris_input_command_t inCmd); + tetris_input_command_t inCmd, + uint8_t bMoveOk); #endif /*VARIANT_FP_H_*/ diff --git a/games/tetris/variant_std.c b/games/tetris/variant_std.c index cefc27c..7978b54 100644 --- a/games/tetris/variant_std.c +++ b/games/tetris/variant_std.c @@ -16,6 +16,17 @@ #include "variant_std.h" +/*********** + * defines * + ***********/ + +#ifdef RANDOM_SUPPORT + #define RANDOM8() random8() +#else + #define RANDOM8() rand() +#endif + + /*************** * entry point * ***************/ @@ -74,8 +85,9 @@ void *tetris_std_construct(tetris_bucket_t *pBucket) malloc(sizeof(tetris_standard_variant_t)); assert(pStdVariant != NULL); memset(pStdVariant, 0, sizeof(tetris_standard_variant_t)); + // don't begin with S and Z pieces according to official tetris guidelines pStdVariant->pPreviewPiece = - tetris_piece_construct(random8() % 7, TETRIS_PC_ANGLE_0); + tetris_piece_construct(RANDOM8() % 5, TETRIS_PC_ANGLE_0); return pStdVariant; } @@ -103,7 +115,7 @@ tetris_piece_t* tetris_std_choosePiece(void *pVariantData) (tetris_standard_variant_t *)pVariantData; tetris_piece_t *pPiece = pStdVariant->pPreviewPiece; pStdVariant->pPreviewPiece = - tetris_piece_construct(random8() % 7, TETRIS_PC_ANGLE_0); + tetris_piece_construct(RANDOM8() % 7, TETRIS_PC_ANGLE_0); return pPiece; } @@ -241,7 +253,8 @@ tetris_highscore_index_t tetris_std_getHighscoreIndex(void *pVariantData) void tetris_std_setLastInput(void *pVariantData, - tetris_input_command_t inCmd) + tetris_input_command_t inCmd, + uint8_t bMoveOk) { } diff --git a/games/tetris/variant_std.h b/games/tetris/variant_std.h index f062eab..1da739b 100644 --- a/games/tetris/variant_std.h +++ b/games/tetris/variant_std.h @@ -175,10 +175,22 @@ tetris_piece_t* tetris_std_getPreviewPiece(void *pVariantData); tetris_highscore_index_t tetris_std_getHighscoreIndex(void *pVariantData); +/** + * inform the Tetris instance about the player's last input + * @param pVariantData the Tetris data object we want to modify + * @param inCmd the last issued command + * @param bMoveOk 1 if the last move was possible, otherwise 0 + */ void tetris_std_setLastInput(void *pVariantData, - tetris_input_command_t inCmd); + tetris_input_command_t inCmd, + uint8_t bMoveOk); +/** + * returns the bearing which is requested by the Tetris instance + * @param pVariantData the variant data object we want information from + * @return always TETRIS_BEARING_0 as we don't change the bearing in Bastet + */ tetris_bearing_t tetris_std_getBearing(void *pVariantData); #endif /*VARIANT_STD_H_*/ diff --git a/games/tetris/variants.h b/games/tetris/variants.h index 3cbcc40..d2f2d35 100644 --- a/games/tetris/variants.h +++ b/games/tetris/variants.h @@ -134,9 +134,11 @@ typedef struct tetris_variant * inform the variant about the player's last input * @param pVariantData the variant data object we want to modify * @param inCmd the last issued command + * @param bMoveOk 1 if the last move was possible, otherwise 0 */ void (*setLastInput)(void *pVariantData, - tetris_input_command_t inCmd); + tetris_input_command_t inCmd, + uint8_t bMoveOk); /** * retrieves the variant's preferred bearing of the bucket