diff --git a/games/tetris/bucket.c b/games/tetris/bucket.c index 49e845e..5533b98 100644 --- a/games/tetris/bucket.c +++ b/games/tetris/bucket.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include "../../autoconf.h" #include "bucket.h" #include "piece.h" diff --git a/games/tetris/bucket.h b/games/tetris/bucket.h index a32cc54..0b4736c 100644 --- a/games/tetris/bucket.h +++ b/games/tetris/bucket.h @@ -1,7 +1,7 @@ #ifndef BUCKET_H_ #define BUCKET_H_ -#include +#include #include "../../autoconf.h" #include "piece.h" diff --git a/games/tetris/highscore.c b/games/tetris/highscore.c index fe96451..c1a39b9 100644 --- a/games/tetris/highscore.c +++ b/games/tetris/highscore.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include "highscore.h" #include "../../config.h" #include "../../scrolltext/scrolltext.h" diff --git a/games/tetris/input.c b/games/tetris/input.c index 444169f..7aabfc6 100644 --- a/games/tetris/input.c +++ b/games/tetris/input.c @@ -1,15 +1,15 @@ #include +#include #include -#include #include -#include "../../config.h" +#include "../../compat/pgmspace.h" #include "../../joystick/joystick.h" -#include "../../util.h" #include "../../scrolltext/scrolltext.h" -#include "input.h" +#include "../../util.h" +#include "../../config.h" #include "bearing.h" +#include "input.h" -#include "../../compat/pgmspace.h" #define WAIT(ms) wait(ms) #define PM(value) pgm_read_byte(&value) @@ -86,7 +86,7 @@ void tetris_input_chatterProtect(tetris_input_t *pIn, // amount of loop cycles a command is ignored after its button has been // released (every command has its own counter) - static const uint8_t nInitialIgnoreValue[TETRIS_INCMD_NONE] PROGMEM = + static uint8_t const nInitialIgnoreValue[TETRIS_INCMD_NONE] PROGMEM = { TETRIS_INPUT_CHATTER_TICKS_LEFT, TETRIS_INPUT_CHATTER_TICKS_RIGHT, @@ -143,7 +143,7 @@ void tetris_input_chatterProtect(tetris_input_t *pIn, tetris_input_command_t tetris_input_mapCommand(tetris_bearing_t nBearing, tetris_input_command_t nCmd) { - const tetris_input_command_t nMapping[] = + tetris_input_command_t const nMapping[] = { TETRIS_INCMD_DOWN, TETRIS_INCMD_ROT_CW, TETRIS_INCMD_RIGHT, TETRIS_INCMD_LEFT, @@ -224,9 +224,10 @@ tetris_input_command_t tetris_input_queryJoystick(tetris_input_t *pIn) // memorize current command (for detecting prolonged key presses) pIn->cmdRawLast = cmdJoystick; + // remap command according to current bearing tetris_input_command_t cmdReturn = tetris_input_mapCommand(pIn->nBearing, cmdJoystick); - // remap command according to current bearing + return cmdReturn; } @@ -420,7 +421,7 @@ void tetris_input_setLevel(tetris_input_t *pIn, assert(pIn != NULL); assert(nLvl <= TETRIS_INPUT_LEVELS - 1); - static const uint8_t nCycles[] PROGMEM = {TETRIS_INPUT_LVL_CYCLES}; + static uint8_t const nCycles[] PROGMEM = {TETRIS_INPUT_LVL_CYCLES}; if (pIn->nLevel != nLvl) { diff --git a/games/tetris/input.h b/games/tetris/input.h index 604280d..d8a2e02 100644 --- a/games/tetris/input.h +++ b/games/tetris/input.h @@ -1,7 +1,7 @@ #ifndef INPUT_H_ #define INPUT_H_ -#include +#include #include "bearing.h" /** diff --git a/games/tetris/piece.c b/games/tetris/piece.c index 9eae4ba..eafbebb 100644 --- a/games/tetris/piece.c +++ b/games/tetris/piece.c @@ -1,13 +1,9 @@ #include #include -#include -#include "piece.h" +#include -#ifdef __AVR__ - #include -#else - #define PROGMEM -#endif +#include "../../compat/pgmspace.h" +#include "piece.h" /***************************** @@ -26,6 +22,7 @@ tetris_piece_t *tetris_piece_construct(tetris_piece_shape_t s, return p_piece; } + void tetris_piece_destruct(tetris_piece_t *pPc) { assert(pPc != NULL); @@ -40,11 +37,12 @@ void tetris_piece_destruct(tetris_piece_t *pPc) uint16_t tetris_piece_getBitmap(tetris_piece_t *pPc) { assert(pPc != NULL); + assert((pPc->angle < 4) && (pPc->shape < 7)); // Lookup table: // A value in an array represents a piece in a specific angle (rotating // clockwise from index 0). - static const uint16_t piece[][4] PROGMEM = + static uint16_t const piece[][4] PROGMEM = {{0x0F00, 0x2222, 0x0F00, 0x2222}, // LINE {0x4E00, 0x4640, 0x0E40, 0x4C40}, // T {0x0660, 0x0660, 0x0660, 0x0660}, // SQUARE @@ -53,44 +51,19 @@ uint16_t tetris_piece_getBitmap(tetris_piece_t *pPc) {0x6C00, 0x4620, 0x6C00, 0x4620}, // S {0xC600, 0x4C80, 0xC600, 0x4C80}}; // Z - #ifdef __AVR__ - return pgm_read_word(&piece[pPc->shape][pPc->angle]); - #else - return piece[pPc->shape][pPc->angle]; - #endif + return pgm_read_word(&piece[pPc->shape][pPc->angle]); } void tetris_piece_rotate(tetris_piece_t *pPc, - tetris_piece_rotation_t r) + tetris_piece_rotation_t nRotation) { assert(pPc != NULL); + assert(nRotation < 2); // we just rotate through the available angles in the given direction and - // make wrap arounds where appropriate - switch (r) - { - case TETRIS_PC_ROT_CW: - if (pPc->angle == TETRIS_PC_ANGLE_270) - { - pPc->angle = TETRIS_PC_ANGLE_0; - } - else - { - ++pPc->angle; - } - break; - case TETRIS_PC_ROT_CCW: - if (pPc->angle == TETRIS_PC_ANGLE_0) - { - pPc->angle = TETRIS_PC_ANGLE_270; - } - else - { - --pPc->angle; - } - break; - } + // wrap around (via modulo) where appropriate + pPc->angle = (pPc->angle + ((nRotation == TETRIS_PC_ROT_CW) ? 1 : 3)) % 4; } @@ -118,11 +91,7 @@ int8_t tetris_piece_getAngleCount(tetris_piece_t *pPc) { assert(pPc != NULL); - static const int8_t angleCounts[] PROGMEM = {2, 4, 1, 4, 4, 2, 2}; + static int8_t const angleCounts[] PROGMEM = {2, 4, 1, 4, 4, 2, 2}; -#ifdef __AVR__ - return pgm_read_word(&angleCounts[pPc->shape]); -#else - return angleCounts[pPc->shape]; -#endif + return pgm_read_byte(&angleCounts[pPc->shape]); } diff --git a/games/tetris/piece.h b/games/tetris/piece.h index f7283ba..502c869 100644 --- a/games/tetris/piece.h +++ b/games/tetris/piece.h @@ -1,7 +1,7 @@ #ifndef TETRIS_PIECE_H_ #define TETRIS_PIECE_H_ -#include +#include /** * \defgroup TetrisPieceTypes Piece: Data types @@ -17,7 +17,7 @@ typedef enum tetris_piece_shape_t { TETRIS_PC_LINE, /**< the I shaped brick */ TETRIS_PC_T, /**< the T shaped brick */ - TETRIS_PC_SQUARE, /**< the sqare shaped brick */ + TETRIS_PC_SQUARE, /**< the square shaped brick */ TETRIS_PC_L, /**< the L shaped brick */ TETRIS_PC_LBACK, /**< the reverse L shaped brick */ TETRIS_PC_S, /**< the S shaped brick */ @@ -101,10 +101,10 @@ uint16_t tetris_piece_getBitmap(tetris_piece_t *pPc); /** * rotates a piece * @param pPc piece to rotate - * @param r type of rotation (see tetris_piece_rotation_t) + * @param nRotation type of rotation (see tetris_piece_rotation_t) */ void tetris_piece_rotate(tetris_piece_t *pPc, - tetris_piece_rotation_t r); + tetris_piece_rotation_t nRotation); /** diff --git a/games/tetris/tetris_main.c b/games/tetris/tetris_main.c index 33be32d..058bdad 100644 --- a/games/tetris/tetris_main.c +++ b/games/tetris/tetris_main.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include "tetris_main.h" #include "variants.h" @@ -12,7 +12,7 @@ #include "highscore.h" -void tetris_main(const tetris_variant_t *const pVariantMethods) +void tetris_main(tetris_variant_t const *const pVariantMethods) { // get view dependent dimensions of the bucket int8_t nWidth; diff --git a/games/tetris/tetris_main.h b/games/tetris/tetris_main.h index aeb5602..6e7298e 100644 --- a/games/tetris/tetris_main.h +++ b/games/tetris/tetris_main.h @@ -8,7 +8,7 @@ * runs the tetris game * @param pVariantMethods struct of function pointers for a game variant */ -void tetris_main(const tetris_variant_t *const pVariantMethods); +void tetris_main(tetris_variant_t const *const pVariantMethods); #endif /* TETRIS_MAIN_H_ */ diff --git a/games/tetris/variant_bastet.c b/games/tetris/variant_bastet.c index 236f87b..3d5fdac 100644 --- a/games/tetris/variant_bastet.c +++ b/games/tetris/variant_bastet.c @@ -1,12 +1,10 @@ -#include +#include #include #include #include - #include "../../random/prng.h" #include "../../compat/pgmspace.h" #include "../../menu/menu.h" -#include "variant_bastet.h" #include "variants.h" #include "tetris_main.h" #include "input.h" @@ -14,6 +12,14 @@ #include "bucket.h" #include "bearing.h" #include "input.h" +#include "variant_bastet.h" + + +/*********** + * defines * + ***********/ + +#define TETRIS_BASTET_HEIGHT_FACTOR 5 /*************************** @@ -21,31 +27,17 @@ ***************************/ /** - * resets the array for the column heights - * @param pBastet bastet instance whose array should be reset - * @param nStart start index - * @param nStop stop index - */ -void tetris_bastet_clearColHeights(tetris_bastet_variant_t *pBastet, - int8_t nStart, - int8_t nStop) -{ - for (int i = nStart; i <= nStop; ++i) - { - pBastet->pColHeights[i] = 0; - } -} - - -/** - * calculate the actual column heights (without any prediction) + * calculate the score impact of every column (without any prediction) * @param pBastet bastet instance whose column heights should be calculated */ -void tetris_bastet_calcActualColHeights(tetris_bastet_variant_t *pBastet) +void tetris_bastet_calcActualColumnsScoreImpact(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_getFirstMatterRow(pBastet->pBucket); + + // calculate the column heights of the actual bucket configuration for (int8_t y = nStartRow; y >= nStopRow; --y) { uint16_t nDumpRow = tetris_bucket_getDumpRow(pBastet->pBucket, y); @@ -54,11 +46,16 @@ void tetris_bastet_calcActualColHeights(tetris_bastet_variant_t *pBastet) { if ((nDumpRow & nColMask) != 0) { - pBastet->pActualColHeights[x] = nStartRow - y + 1; + pBastet->pActualColScoreImpact[x] = nStartRow - y + 1; } nColMask <<= 1; } } + // calculate the score impact of every column + for (int x = 0; x < nWidth; ++x) + { + pBastet->pActualColScoreImpact[x] *= TETRIS_BASTET_HEIGHT_FACTOR; + } } @@ -111,8 +108,8 @@ uint8_t tetris_bastet_calcPredictedColHeights(tetris_bastet_variant_t *pBastet, * @param pa the first value to compare * @param pb the second value to compare */ -int tetris_bastet_qsortCompare(const void *pa, - const void *pb) +int tetris_bastet_qsortCompare(void const *pa, + void const *pb) { tetris_bastet_scorepair_t *pScorePairA = (tetris_bastet_scorepair_t *)pa; tetris_bastet_scorepair_t *pScorePairB = (tetris_bastet_scorepair_t *)pb; @@ -158,7 +155,7 @@ void tetris_bastet(void) * construction/destruction * ****************************/ -const tetris_variant_t tetrisBastetVariant = +tetris_variant_t const tetrisBastetVariant = { &tetris_bastet_construct, &tetris_bastet_destruct, @@ -189,9 +186,8 @@ void *tetris_bastet_construct(tetris_bucket_t *pBucket) pBastet->pBucket = pBucket; int8_t nWidth = tetris_bucket_getWidth(pBastet->pBucket); - pBastet->pActualColHeights = (int8_t*) calloc(nWidth, sizeof(int8_t)); + pBastet->pActualColScoreImpact = (int8_t*) calloc(nWidth, sizeof(int8_t)); pBastet->pColHeights = (int8_t*) calloc(nWidth, sizeof(int8_t)); - tetris_bastet_clearColHeights(pBastet, 0, nWidth - 1); return pBastet; } @@ -202,9 +198,9 @@ void tetris_bastet_destruct(void *pVariantData) assert(pVariantData != 0); tetris_bastet_variant_t *pBastetVariant = (tetris_bastet_variant_t *)pVariantData; - if (pBastetVariant->pActualColHeights != NULL) + if (pBastetVariant->pActualColScoreImpact != NULL) { - free(pBastetVariant->pActualColHeights); + free(pBastetVariant->pActualColScoreImpact); } if (pBastetVariant->pColHeights != NULL) { @@ -268,11 +264,11 @@ int16_t tetris_bastet_evaluateMove(tetris_bastet_variant_t *pBastet, { if ((x >= nStartCol) && (x <= nStopCol)) { - nScore -= 5 * pBastet->pColHeights[x]; + nScore -= TETRIS_BASTET_HEIGHT_FACTOR * pBastet->pColHeights[x]; } else { - nScore -= 5 * pBastet->pActualColHeights[x]; + nScore -= pBastet->pActualColScoreImpact[x]; } } @@ -283,7 +279,7 @@ int16_t tetris_bastet_evaluateMove(tetris_bastet_variant_t *pBastet, void tetris_bastet_evaluatePieces(tetris_bastet_variant_t *pBastet) { // precache actual column heights - tetris_bastet_calcActualColHeights(pBastet); + tetris_bastet_calcActualColumnsScoreImpact(pBastet); int8_t nWidth = tetris_bucket_getWidth(pBastet->pBucket); tetris_piece_t *pPiece = tetris_piece_construct(TETRIS_PC_LINE, TETRIS_PC_ANGLE_0); @@ -295,6 +291,7 @@ void tetris_bastet_evaluatePieces(tetris_bastet_variant_t *pBastet) for (int8_t nAngle = TETRIS_PC_ANGLE_0; nAngle < nAngleCount; ++nAngle) { tetris_piece_setAngle(pPiece, nAngle); + tetris_piece_rotate(pPiece, TETRIS_PC_ROT_CW); for (int8_t nCol = -3; nCol < nWidth; ++nCol) { int16_t nScore = tetris_bastet_evaluateMove(pBastet, @@ -302,8 +299,8 @@ void tetris_bastet_evaluatePieces(tetris_bastet_variant_t *pBastet) nMaxScore = nMaxScore > nScore ? nMaxScore : nScore; } } - pBastet->nPieceScores[nBlock].shape = nBlock; - pBastet->nPieceScores[nBlock].nScore = nMaxScore; + pBastet->nPieceScore[nBlock].shape = nBlock; + pBastet->nPieceScore[nBlock].nScore = nMaxScore; } tetris_piece_destruct(pPiece); } @@ -320,11 +317,11 @@ 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->nPieceScores[i].nScore += random8() % 5 - 2; + pBastet->nPieceScore[i].nScore += random8() % 5 - 2; } // sort pieces by their score in ascending order - qsort(pBastet->nPieceScores, 7, sizeof(tetris_bastet_scorepair_t), + qsort(pBastet->nPieceScore, 7, sizeof(tetris_bastet_scorepair_t), &tetris_bastet_qsortCompare); // new "preview" piece (AKA "won't give you this one") @@ -333,18 +330,26 @@ tetris_piece_t* tetris_bastet_choosePiece(void *pVariantData) tetris_piece_destruct(pBastet->pPreviewPiece); } pBastet->pPreviewPiece = - tetris_piece_construct(pBastet->nPieceScores[6].shape, + tetris_piece_construct(pBastet->nPieceScore[6].shape, TETRIS_PC_ANGLE_0); tetris_piece_t *pPiece = NULL; - const uint8_t nPercent[4] = {75, 92, 98, 100}; + uint8_t const nPercent[4] = {75, 92, 98, 100}; uint8_t nRnd = rand() % 100; for (uint8_t i = 0; i < 4; ++i) { if (nRnd < nPercent[i]) { - pPiece = tetris_piece_construct(pBastet->nPieceScores[i].shape, - TETRIS_PC_ANGLE_0); + // circumvent a trick where the line piece consecutively gets the + // lowest score although it removes a line every time + if ((pBastet->nPieceScore[i].shape == TETRIS_PC_LINE) && + (pBastet->nPieceScore[i].nScore >= -28000)) + { + i += ((i == 0) ? 1 : -1); + } + + pPiece = tetris_piece_construct(pBastet->nPieceScore[i].shape, + TETRIS_PC_ANGLE_0); break; } } diff --git a/games/tetris/variant_bastet.h b/games/tetris/variant_bastet.h index 0cb2965..b06a841 100644 --- a/games/tetris/variant_bastet.h +++ b/games/tetris/variant_bastet.h @@ -1,7 +1,7 @@ #ifndef BAST_H_ #define BAST_H_ -#include +#include #include "variants.h" #include "bucket.h" #include "piece.h" @@ -32,20 +32,20 @@ tetris_bastet_scorepair_t; typedef struct tetris_bastet_variant_t { - uint16_t nScore; /** score of the player */ - uint16_t nHighscore; /** highscore */ - uint16_t nHighscoreName; /** champion's initials */ - uint8_t nLevel; /** current level */ - uint16_t nLines; /** number of completed lines */ - tetris_piece_t *pPreviewPiece; /** the piece for the preview */ - tetris_bucket_t *pBucket; /** bucket to be examined */ - int8_t *pActualColHeights; /** actual columns heights */ - int8_t *pColHeights; /** predicted column heights */ - tetris_bastet_scorepair_t nPieceScores[7]; /** score for every piece */ + uint16_t nScore; /** score of the player */ + uint16_t nHighscore; /** highscore */ + uint16_t nHighscoreName; /** champion's initials */ + uint8_t nLevel; /** current level */ + uint16_t nLines; /** number of completed lines */ + tetris_piece_t *pPreviewPiece; /** the piece for the preview */ + tetris_bucket_t *pBucket; /** bucket to be examined */ + int8_t *pActualColScoreImpact; /** score impact of every column*/ + int8_t *pColHeights; /** predicted column heights */ + tetris_bastet_scorepair_t nPieceScore[7]; /** score for every piece */ } tetris_bastet_variant_t; -const tetris_variant_t tetrisBastetVariant; +tetris_variant_t const tetrisBastetVariant; /**************************** diff --git a/games/tetris/variant_fp.c b/games/tetris/variant_fp.c index 1d19546..5168ca0 100644 --- a/games/tetris/variant_fp.c +++ b/games/tetris/variant_fp.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include "../../random/prng.h" #include "../../compat/pgmspace.h" @@ -44,7 +44,7 @@ void tetris_fp(void) * construction/destruction * ****************************/ -const tetris_variant_t tetrisFpVariant = +tetris_variant_t const tetrisFpVariant = { &tetris_std_construct, &tetris_std_destruct, diff --git a/games/tetris/variant_fp.h b/games/tetris/variant_fp.h index 6164c25..d3a5b80 100644 --- a/games/tetris/variant_fp.h +++ b/games/tetris/variant_fp.h @@ -1,7 +1,7 @@ #ifndef VARIANT_FP_H_ #define VARIANT_FP_H_ -#include +#include #include "variant_std.h" #include "variants.h" #include "highscore.h" @@ -20,7 +20,7 @@ void tetris_fp(void); -const tetris_variant_t tetrisFpVariant; +tetris_variant_t const tetrisFpVariant; /********************* diff --git a/games/tetris/variant_std.c b/games/tetris/variant_std.c index 75cf0a9..b4a6836 100644 --- a/games/tetris/variant_std.c +++ b/games/tetris/variant_std.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include "../../autoconf.h" #include "../../random/prng.h" @@ -51,7 +51,7 @@ void tetris(void) ****************************/ #ifdef GAME_TETRIS -const tetris_variant_t tetrisStdVariant = +tetris_variant_t const tetrisStdVariant = { &tetris_std_construct, &tetris_std_destruct, diff --git a/games/tetris/variant_std.h b/games/tetris/variant_std.h index 3c209d8..2d11217 100644 --- a/games/tetris/variant_std.h +++ b/games/tetris/variant_std.h @@ -1,7 +1,7 @@ #ifndef VARIANT_STD_H_ #define VARIANT_STD_H_ -#include +#include #include "../../autoconf.h" #include "variants.h" #include "piece.h" @@ -39,7 +39,7 @@ typedef struct tetris_standard_variant_t tetris_standard_variant_t; -const tetris_variant_t tetrisStdVariant; +tetris_variant_t const tetrisStdVariant; /**************************** diff --git a/games/tetris/variants.h b/games/tetris/variants.h index 71d71d7..de27c11 100644 --- a/games/tetris/variants.h +++ b/games/tetris/variants.h @@ -1,7 +1,7 @@ #ifndef VARIANTS_H_ #define VARIANTS_H_ -#include +#include #include "bucket.h" #include "piece.h" #include "highscore.h" diff --git a/games/tetris/view.c b/games/tetris/view.c index d7b7dd8..b09ac94 100644 --- a/games/tetris/view.c +++ b/games/tetris/view.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include "../../autoconf.h" #include "../../pixel.h" #include "../../util.h" @@ -609,7 +609,7 @@ void tetris_view_formatHighscoreName(uint16_t nHighscoreName, * construction/destruction * ****************************/ -tetris_view_t *tetris_view_construct(const tetris_variant_t *const pVarMethods, +tetris_view_t *tetris_view_construct(tetris_variant_t const *const pVarMethods, void *pVariantData, tetris_bucket_t *pBucket) { diff --git a/games/tetris/view.h b/games/tetris/view.h index a5e40c1..cee956a 100644 --- a/games/tetris/view.h +++ b/games/tetris/view.h @@ -1,7 +1,7 @@ #ifndef TETRIS_VIEW_H_ #define TETRIS_VIEW_H_ -#include +#include #include "variants.h" #include "piece.h" #include "bucket.h" @@ -28,9 +28,9 @@ tetris_view_mode_t; /** data structure that drives the view module */ typedef struct tetris_view_t { - const tetris_variant_t *pVariantMethods; /** variant function pointers */ + tetris_variant_t const *pVariantMethods; /** variant function pointers */ void *pVariant; /** associated variant object */ - tetris_bucket_t *pBucket; /** associated bucket */ + tetris_bucket_t *pBucket; /** associated bucket */ tetris_view_mode_t modeCurrent; /** current presentation mode */ tetris_view_mode_t modeOld; /** old presentation mode */ uint8_t nOldLevel; /** for detecting level changes */ @@ -57,7 +57,7 @@ tetris_view_t; * @param pBucket pointer to bucket which should be observed * @return pointer to a newly created view */ -tetris_view_t *tetris_view_construct(const tetris_variant_t *const pVarMethods, +tetris_view_t *tetris_view_construct(tetris_variant_t const *const pVarMethods, void *pVariantData, tetris_bucket_t *pBucket);