diff --git a/animations/Makefile b/animations/Makefile index 35bd854..c3ef712 100644 --- a/animations/Makefile +++ b/animations/Makefile @@ -13,13 +13,13 @@ ifeq ($(ANIMATION_MATRIX),y) SRC += matrix.c endif -ifeq ($(ANIMATION_STONEFLY),y) - SRC += stonefly.c -endif +ifeq ($(ANIMATION_STONEFLY),y) + SRC += stonefly.c +endif -ifeq ($(ANIMATION_FLYINGDOTS),y) - SRC += flyingdots.c -endif +ifeq ($(ANIMATION_FLYINGDOTS),y) + SRC += flyingdots.c +endif ifeq ($(ANIMATION_GAMEOFLIFE),y) SRC += gameoflife.c diff --git a/defaults.mk b/defaults.mk index 98eeb8e..3fb73d6 100644 --- a/defaults.mk +++ b/defaults.mk @@ -19,7 +19,7 @@ export HOSTCC # flags for the compiler CFLAGS ?= -Wall -W -Wno-unused-parameter -Wno-sign-compare -CFLAGS += -g -Os -std=gnu99 -fgnu89-inline +CFLAGS += -g -Os -std=gnu99 -fgnu89-inline -DNDEBUG # flags for the linker LDFLAGS += -T ./avr5.x -mmcu=$(MCU) @@ -33,7 +33,7 @@ MACHINE = $(shell uname -m) #$(info $(OSTYPE)) ifeq ($(OSTYPE),cygwin) - CFLAGS_SIM = -g -Wall -pedantic -std=c99 -O2 -D_WIN32 -mno-cygwin + CFLAGS_SIM = -g -Wall -pedantic -std=c99 -O0 -D_WIN32 -mno-cygwin LDFLAGS_SIM = -Wl -mno-cygwin -T simulator/i386pe.x LIBS_SIM = -lglut32 -lglu32 -lopengl32 else diff --git a/display_loop.c b/display_loop.c index b8dcc51..a144d69 100644 --- a/display_loop.c +++ b/display_loop.c @@ -7,7 +7,7 @@ #include "animations/programm.h" #include "animations/matrix.h" #include "animations/gameoflife.h" -#include "animations/stonefly.h" +#include "animations/stonefly.h" #include "animations/flyingdots.h" #include "borg_hw/borg_hw.h" #include "can/borg_can.h" @@ -92,12 +92,12 @@ void display_loop(){ break; #endif -#ifdef ANIMATION_STONEFLY - case 9: - stonefly(); - break; -#endif - +#ifdef ANIMATION_STONEFLY + case 9: + stonefly(); + break; +#endif + #ifdef ANIMATION_GAMEOFLIFE case 10: gameoflife(); @@ -109,10 +109,10 @@ void display_loop(){ flyingdots(); break; #endif - #ifdef ANIMATION_MHERWEG - case 11: + case 11: + flydots(); lines1(); dots1(); movinglines(); @@ -141,10 +141,9 @@ void display_loop(){ break; #endif - - case 42: - mode = 1; - break; + case 42: + mode = 1; + break; #ifdef MENU_SUPPORT case 43: diff --git a/games/config.in b/games/config.in index b4cbad7..ec80ad4 100644 --- a/games/config.in +++ b/games/config.in @@ -2,6 +2,7 @@ mainmenu_option next_comment comment "Games" dep_bool "tetris" GAME_TETRIS $JOYSTICK_SUPPORT $RANDOM_SUPPORT +dep_bool "bastet" GAME_BASTET $GAME_TETRIS dep_bool "space invaders" GAME_SPACE_INVADERS $JOYSTICK_SUPPORT $RANDOM_SUPPORT dep_bool "snake" GAME_SNAKE $JOYSTICK_SUPPORT $RANDOM_SUPPORT diff --git a/games/tetris/Makefile b/games/tetris/Makefile index a2e8475..0d53203 100644 --- a/games/tetris/Makefile +++ b/games/tetris/Makefile @@ -3,6 +3,10 @@ TOPDIR = ../.. include $(TOPDIR)/defaults.mk -SRC = piece.c playfield.c view.c logic.c input.c bast.c +ifeq ($(GAME_BASTET),y) + SRC = piece.c playfield.c view.c logic.c input.c bast.c +else + SRC = piece.c playfield.c view.c logic.c input.c +endif include $(TOPDIR)/rules.mk diff --git a/games/tetris/bast.c b/games/tetris/bast.c index fae80ef..5b458cc 100644 --- a/games/tetris/bast.c +++ b/games/tetris/bast.c @@ -1,6 +1,7 @@ #include #include #include +#include "../../random/prng.h" #include "piece.h" #include "playfield.h" #include "bast.h" @@ -13,18 +14,46 @@ /* Function: tetris_bastet_clearColHeights; * Description: resets the array for the column heights * Argument pBastet: bastet instance whose array should be reset + * Argument nStart: start index + * Argument nStop: stop index * Return value: void */ -void tetris_bastet_clearColHeights(tetris_bastet_t *pBastet) +void tetris_bastet_clearColHeights(tetris_bastet_t *pBastet, + int8_t nStart, + int8_t nStop) { - int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield); - for (int i = 0; i < nWidth; ++i) + for (int i = nStart; i <= nStop; ++i) { pBastet->pColHeights[i] = 0; } } +/* Function: tetris_bastet_qsortCompare + * Description: compare function for quick sorting the pieces by score + * Argument pa: the first value to compare + * Argument pb: the second value to compare + * Return value: void + */ +int tetris_bastet_qsortCompare(const void *pa, const void *pb) +{ + tetris_bastet_scorepair_t *pScoreA = (tetris_bastet_scorepair_t *)pa; + tetris_bastet_scorepair_t *pScoreB = (tetris_bastet_scorepair_t *)pb; + if (pScoreA->nScore == pScoreB->nScore) + { + return 0; + } + else if (pScoreA->nScore < pScoreB->nScore) + { + return -1; + } + else + { + return 1; + } +} + + /**************************** * construction/destruction * ****************************/ @@ -43,7 +72,7 @@ tetris_bastet_t* tetris_bastet_construct(tetris_playfield_t *pPl) int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield); pBastet->pColHeights = (int8_t*) calloc(nWidth, sizeof(int8_t)); - tetris_bastet_clearColHeights(pBastet); + tetris_bastet_clearColHeights(pBastet, 0, nWidth - 1); return pBastet; } @@ -87,20 +116,46 @@ int16_t tetris_bastet_evalPos(tetris_bastet_t *pBastet, pPiece, nColumn); nScore += 5000 * nLines; + // determine sane start and stop columns whose heights we want to calculate + int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield); + int8_t nStartCol = ((nColumn - 1) < 0) ? 0 : nColumn - 1; + int8_t nStopCol; + // do we start at the left most position? + if (nColumn <= -3) + { + // in case we start at the left most position we calculate all heights + nStopCol = nWidth - 1; + // reset all column heights to zero + tetris_bastet_clearColHeights(pBastet, 0 , nWidth); + } + // if not, only calculate columns which are affected by the piece + else + { + nStopCol = (nColumn + 3) < nWidth ? nColumn + 3 : nWidth - 1; + // clear affected column heights to prevent miscalculations + tetris_bastet_clearColHeights(pBastet, nStartCol, nStopCol); + } + // go through every row and calculate column heights tetris_playfield_iterator_t iterator; - int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield); int8_t nHeight = 1; uint16_t *pDump = tetris_playfield_predictBottomRow(&iterator, pBastet->pPlayfield, pPiece, nColumn); + if (pDump == NULL) + { + // an immediately returned NULL is caused by a full dump -> low score + return -32766; + } while (pDump != NULL) { - for (int x = 0; x < nWidth; ++x) + uint16_t nColMask = 0x0001 << nStartCol; + for (int x = nStartCol; x <= nStopCol; ++x) { - if ((*pDump & (0x0001 << x)) != 0) + if ((*pDump & nColMask) != 0) { pBastet->pColHeights[x] = nHeight; } + nColMask <<= 1; } pDump = tetris_playfield_predictNextRow(&iterator); ++nHeight; @@ -111,8 +166,84 @@ int16_t tetris_bastet_evalPos(tetris_bastet_t *pBastet, nScore -= 5 * pBastet->pColHeights[x]; } - // reset column height array for later use - tetris_bastet_clearColHeights(pBastet); - return nScore; } + + +/* Function: tetris_bastet_minimax + * Description: calculates the best possible score for every piece + * Argument pBastet: the bastet instance of interest + * Return value: void + */ +void tetris_bastet_minimax(tetris_bastet_t *pBastet) +{ + int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield); + tetris_piece_t *pPiece = tetris_piece_construct(TETRIS_PC_LINE, + TETRIS_PC_ANGLE_0); + for (int8_t nBlock = TETRIS_PC_LINE; nBlock <= TETRIS_PC_Z; ++nBlock) + { + int16_t nMaxScore = -32768; + tetris_piece_changeShape(pPiece, nBlock); + int8_t nAngleCount = tetris_piece_angleCount(pPiece); + for (int8_t nAngle = TETRIS_PC_ANGLE_0; nAngle < nAngleCount; ++nAngle) + { + tetris_piece_changeAngle(pPiece, nAngle); + for (int8_t nCol = -3; nCol < nWidth; ++nCol) + { + int16_t nScore = tetris_bastet_evalPos(pBastet, pPiece, nCol); + nMaxScore = nMaxScore > nScore ? nMaxScore : nScore; + } + } + pBastet->nPieceScores[nBlock].shape = nBlock; + pBastet->nPieceScores[nBlock].nScore = nMaxScore; + } + tetris_piece_destruct(pPiece); +} + + +/* Function: tetris_bastet_choosePiece + * Description: calculates the worst possible piece + * Argument pBastet: the bastet instance of interest + * Return value: the worst possible piece + */ +tetris_piece_t* tetris_bastet_choosePiece(tetris_bastet_t *pBastet) +{ + const uint8_t nPercent[7] = {75, 92, 98, 100, 100, 100, 100}; + tetris_bastet_minimax(pBastet); + + // 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; + } + + qsort(pBastet->nPieceScores, 7, sizeof(tetris_bastet_scorepair_t), + &tetris_bastet_qsortCompare); + + uint8_t rnd = rand() % 100; + for (uint8_t i = 0; i < 7; i++) + { + if (rnd < nPercent[i]) + { + return tetris_piece_construct(pBastet->nPieceScores[i].shape, + TETRIS_PC_ANGLE_0); + } + } + + //should not arrive here + return tetris_piece_construct(pBastet->nPieceScores[0].shape, + TETRIS_PC_ANGLE_0); +} + + +/* Function: tetris_bastet_choosePreviewPiece + * Description: returns the best possible piece + * (run tetris_bastet_choosePiece first!) + * Argument pBastet: the bastet instance of interest + * Return value: the worst possible piece + */ +tetris_piece_t* tetris_bastet_choosePreviewPiece(tetris_bastet_t *pBastet) +{ + return tetris_piece_construct(pBastet->nPieceScores[6].shape, + TETRIS_PC_ANGLE_0); +} diff --git a/games/tetris/bast.h b/games/tetris/bast.h index 5ea4f71..4acc9cd 100644 --- a/games/tetris/bast.h +++ b/games/tetris/bast.h @@ -9,10 +9,19 @@ * types * *********/ +typedef struct tetris_bastet_scorepair_t +{ + tetris_piece_shape_t shape; + int16_t nScore; +} +tetris_bastet_scorepair_t; + + typedef struct tetris_bastet_t { - tetris_playfield_t *pPlayfield; // the playfield to be examined - int8_t *pColHeights; // array of calculated column heights + tetris_playfield_t *pPlayfield; // the playfield to be examined + int8_t *pColHeights; // array of calculated heights + tetris_bastet_scorepair_t nPieceScores[7]; // score for every piece } tetris_bastet_t; @@ -52,4 +61,17 @@ int16_t tetris_bastet_evalPos(tetris_bastet_t *pBastet, tetris_piece_t *pPiece, int8_t nColumn); + +/* Function: tetris_bastet_minimax + * Description: calculates the best possible score for every piece + * Argument pBastet: the bastet instance of interest + * Return value: void + */ +void tetris_bastet_minimax(); + + +tetris_piece_t* tetris_bastet_choosePiece(tetris_bastet_t *pBastet); + +tetris_piece_t* tetris_bastet_choosePreviewPiece(tetris_bastet_t *pBastet); + #endif /* BAST_H_ */ diff --git a/games/tetris/logic.c b/games/tetris/logic.c index 02e2ed1..ab53939 100644 --- a/games/tetris/logic.c +++ b/games/tetris/logic.c @@ -8,37 +8,54 @@ #include #include +#include "../../autoconf.h" #include "../../compat/eeprom.h" #include "../../compat/pgmspace.h" #include "../../menu/menu.h" +#include "../../random/prng.h" #include "logic.h" #include "piece.h" #include "playfield.h" #include "view.h" #include "input.h" -#include "../../random/prng.h" + +#ifdef GAME_BASTET +#include "bast.h" +#endif #ifdef EEMEM - /*********************** - * Highscore in EEPROM * - ***********************/ +/*********************** + * Highscore in EEPROM * + ***********************/ - uint16_t tetris_logic_nHighscore EEMEM; +uint16_t tetris_logic_nHighscore EEMEM; #endif - // MSB is leftmost pixel -static uint8_t icon[8] PROGMEM = - {0x0f, 0x0f, 0xc3, 0xdb, 0xdb, 0xc3, 0xf0, 0xf0}; // Tetris icon - +// Tetris icon, MSB is leftmost pixel void tetris(); - -game_descriptor_t tetris_game_descriptor __attribute__((section(".game_descriptors"))) ={ - &tetris, - icon, +static uint8_t tetris_icon[8] PROGMEM = + { 0x0f, 0x0f, 0xc3, 0xdb, 0xdb, 0xc3, 0xf0, 0xf0 }; +game_descriptor_t tetris_game_descriptor + __attribute__((section(".game_descriptors"))) = +{ + &tetris, + tetris_icon, }; +#ifdef GAME_BASTET +// Bastet icon, MSB is leftmost pixel +static uint8_t bastet_icon[8] PROGMEM = + { 0x81, 0xc3, 0xff, 0x99, 0xff, 0xff, 0x66, 0x3c }; +game_descriptor_t bastet_game_descriptor + __attribute__((section(".game_descriptors"))) = +{ + &tetris_bastet, + bastet_icon, +}; +#endif + /*************************** * non-interface functions * @@ -104,7 +121,7 @@ void tetris_logic_saveHighscore(uint16_t nHighscore) */ tetris_logic_t *tetris_logic_construct() { - tetris_logic_t *pLogic = (tetris_logic_t *)malloc(sizeof(tetris_logic_t)); + tetris_logic_t *pLogic = (tetris_logic_t *) malloc(sizeof(tetris_logic_t)); assert(pLogic != NULL); memset(pLogic, 0, sizeof(tetris_logic_t)); return pLogic; @@ -130,7 +147,28 @@ void tetris_logic_destruct(tetris_logic_t *pLogic) * Description: runs the tetris game * Return value: void */ -void tetris () +void tetris() +{ + tetris_main(0); +} + + +/* Function: tetris_bastet + * Description: runs the bastet game + * Return value: void + */ +void tetris_bastet() +{ + tetris_main(1); +} + + +/* Function: tetris_main + * Description: runs the tetris game + * Argument nBastet: 0 for normal Tetris, 1 for Bastet + * Return value: void + */ +void tetris_main(int8_t nBastet) { // get view dependent dimensions of the playfield int8_t nWidth; @@ -145,6 +183,9 @@ void tetris () tetris_playfield_t *pPl = tetris_playfield_construct(nWidth, nHeight); tetris_input_t *pIn = tetris_input_construct(); tetris_view_t *pView = tetris_view_construct(pLogic, pPl); +#ifdef GAME_BASTET + tetris_bastet_t *pBastet; +#endif // runtime variable int8_t nPieceRow; @@ -157,15 +198,28 @@ void tetris () } // initialize current and next piece - tetris_piece_t *pPiece = NULL; - tetris_piece_t *pNextPiece = pPiece = - tetris_piece_construct(random8() % 7, TETRIS_PC_ANGLE_0); + tetris_piece_t *pPiece; + tetris_piece_t *pNextPiece; +#ifdef GAME_BASTET + if (nBastet) + { + pBastet = tetris_bastet_construct(pPl); + pNextPiece = pPiece = NULL; + } + else + { +#endif + pNextPiece = pPiece = + tetris_piece_construct(random8() % 7, TETRIS_PC_ANGLE_0); + tetris_logic_setPreviewPiece(pLogic, pNextPiece); +#ifdef GAME_BASTET + } +#endif // the view only monitors the logic and the playfield object for the game // status so we must put information like the next piece or the current // highscore to a place where the view can find it tetris_logic_setHighscore(pLogic, nHighscore); - tetris_logic_setPreviewPiece(pLogic, pNextPiece); // pace flag tetris_input_pace_t inPace; @@ -178,22 +232,45 @@ void tetris () { // the playfield awaits a new piece case TETRIS_PFS_READY: - // make preview piece the current piece and create new preview piece - pPiece = pNextPiece; - pNextPiece = - tetris_piece_construct(random8() % 7, TETRIS_PC_ANGLE_0); - tetris_logic_setPreviewPiece(pLogic, pNextPiece); - - // insert new piece into playfield - tetris_piece_t *pOldPiece; - tetris_playfield_insertPiece(pPl, pPiece, &pOldPiece); - - // destruct old piece (if it exists) since we don't need it anymore - if (pOldPiece != NULL) +#ifdef GAME_BASTET + if (nBastet) { - tetris_piece_destruct(pOldPiece); - pOldPiece = NULL; + if (pPiece != NULL) + { + tetris_piece_destruct(pPiece); + } + if (pNextPiece != NULL) + { + tetris_piece_destruct(pNextPiece); + } + pPiece = tetris_bastet_choosePiece(pBastet); + pNextPiece = tetris_bastet_choosePreviewPiece(pBastet); + tetris_piece_t *pOldPiece; + tetris_playfield_insertPiece(pPl, pPiece, &pOldPiece); + tetris_logic_setPreviewPiece(pLogic, pNextPiece); } + else + { +#endif + // make preview piece the current piece and create new preview piece + pPiece = pNextPiece; + pNextPiece = tetris_piece_construct(random8() % 7, + TETRIS_PC_ANGLE_0); + tetris_logic_setPreviewPiece(pLogic, pNextPiece); + + // insert new piece into playfield + tetris_piece_t *pOldPiece; + tetris_playfield_insertPiece(pPl, pPiece, &pOldPiece); + + // destruct old piece (if it exists) since we don't need it anymore + if (pOldPiece != NULL) + { + tetris_piece_destruct(pOldPiece); + pOldPiece = NULL; + } +#ifdef GAME_BASTET + } +#endif break; // a piece is hovering and can be controlled by the player @@ -296,7 +373,6 @@ void tetris () // and whether the level gets changed tetris_logic_removedLines(pLogic, tetris_playfield_getRowMask(pPl)); tetris_input_setLevel(pIn, tetris_logic_getLevel(pLogic)); - break; // avoid compiler warnings @@ -320,6 +396,12 @@ void tetris () } // clean up +#ifdef GAME_BASTET + if (nBastet) + { + tetris_bastet_destruct(pBastet); + } +#endif tetris_view_destruct(pView); tetris_input_destruct(pIn); tetris_playfield_destruct(pPl); @@ -374,18 +456,18 @@ void tetris_logic_removedLines(tetris_logic_t *pLogic, switch (nLines) { - case 1: - pLogic->nScore += 50; - break; - case 2: - pLogic->nScore += 150; - break; - case 3: - pLogic->nScore += 250; - break; - case 4: - pLogic->nScore += 400; - break; + case 1: + pLogic->nScore += 50; + break; + case 2: + pLogic->nScore += 150; + break; + case 3: + pLogic->nScore += 250; + break; + case 4: + pLogic->nScore += 400; + break; } } diff --git a/games/tetris/logic.h b/games/tetris/logic.h index 67e9d06..caeed3a 100644 --- a/games/tetris/logic.h +++ b/games/tetris/logic.h @@ -46,6 +46,20 @@ void tetris_logic_destruct(tetris_logic_t *pLogic); void tetris(); +/* Function: tetris_bastet + * Description: runs the bastet game + * Return value: void + */ +void tetris_bastet(); + + +/* Function: tetris_main + * Description: runs the tetris game + * Argument nBastet: 0 for normal Tetris, 1 for Bastet + * Return value: void + */ +void tetris_main(int8_t nBastet); + /* Function: tetris_logic_singleDrop * Description: add points which result from single step dropping * Argument pLogic: the logic object we want to modify diff --git a/games/tetris/playfield.c b/games/tetris/playfield.c index 9c9d40b..b6ee5a0 100644 --- a/games/tetris/playfield.c +++ b/games/tetris/playfield.c @@ -2,9 +2,9 @@ #include #include #include +#include "../../autoconf.h" #include "playfield.h" #include "piece.h" -#include "bast.h" /*************************** @@ -58,6 +58,7 @@ tetris_playfield_t *tetris_playfield_construct(int8_t nWidth, if (pPlayfield->dump != NULL) { // setting desired attributes + pPlayfield->nFirstMatterRow = nHeight - 1; pPlayfield->nWidth = nWidth; pPlayfield->nHeight = nHeight; tetris_playfield_reset(pPlayfield); @@ -336,6 +337,20 @@ void tetris_playfield_advancePiece(tetris_playfield_t *pPl) pPl->dump[i] |= nPieceMap; } + // update value for the highest row with matter + int8_t nPieceRow = pPl->nRow; + uint16_t nMask = 0x000F; + for (int i = 0; i < 4; ++i, nMask <<= 4) + { + if ((nMask & nPiece) != 0) + { + nPieceRow += i; + break; + } + } + pPl->nFirstMatterRow = (pPl->nFirstMatterRow > nPieceRow) ? + nPieceRow : pPl->nFirstMatterRow; + // the piece has finally been docked pPl->status = TETRIS_PFS_DOCKED; } @@ -456,6 +471,9 @@ void tetris_playfield_removeCompleteLines(tetris_playfield_t *pPl) // is current row a full row? if ((nFullRow & pPl->dump[i]) == nFullRow) { + // adjust value for the highest row with matter + pPl->nFirstMatterRow++; + // set corresponding bit for the row mask // nRowMask |= 0x08 >> (nStartRow - i); nRowMask |= 0x01 << (i - pPl->nRow); @@ -602,6 +620,9 @@ uint16_t tetris_playfield_getDumpRow(tetris_playfield_t *pPl, return pPl->dump[nRow]; } + +#ifdef GAME_BASTET + /* Function: tetris_playfield_predictDeepestRow * Description: returns the deepest possible row of a given piece * Argument pPl: the playfield on which we want to test a piece @@ -621,10 +642,14 @@ int8_t tetris_playfield_predictDeepestRow(tetris_playfield_t *pPl, if (tetris_playfield_collision(pPl, (pPl->nWidth - 2) / 2, nRow) || (tetris_playfield_collision(pPl, nColumn, nRow))) { + // restore real piece + pPl->pPiece = pActualPiece; + return -4; } // determine deepest row + nRow = (nRow < pPl->nFirstMatterRow - 4) ? pPl->nFirstMatterRow - 4 : nRow; while ((nRow < pPl->nHeight) && (!tetris_playfield_collision(pPl, nColumn, nRow + 1))) { @@ -777,3 +802,5 @@ uint16_t* tetris_playfield_predictNextRow(tetris_playfield_iterator_t *pIt) return NULL; } } + +#endif /* GAME_BASTET */ diff --git a/games/tetris/playfield.h b/games/tetris/playfield.h index b5e4a89..cebf4dc 100644 --- a/games/tetris/playfield.h +++ b/games/tetris/playfield.h @@ -2,6 +2,7 @@ #define TETRIS_PLAYFIELD_H_ #include +#include "../../autoconf.h" #include "piece.h" @@ -40,6 +41,7 @@ typedef struct tetris_playfield_t int8_t nRow; // vert. piece pos. (0 is top) uint8_t nRowMask; // removed lines relative to nRow (bitmap) tetris_playfield_status_t status; // status + int8_t nFirstMatterRow; // first row (from top) which contains matter uint16_t *dump; // playfield itself } tetris_playfield_t; @@ -223,6 +225,8 @@ uint16_t tetris_playfield_getDumpRow(tetris_playfield_t *pPl, int8_t nRow); +#ifdef GAME_BASTET + /* Function: tetris_playfield_predictDeepestRow * Description: returns the deepest possible row of a given piece * Argument pPl: the playfield on which we want to test a piece @@ -287,6 +291,6 @@ uint16_t* tetris_playfield_predictBottomRow(tetris_playfield_iterator_t *pIt, */ uint16_t* tetris_playfield_predictNextRow(tetris_playfield_iterator_t *pIt); - +#endif /* GAME_BASTET */ #endif /*TETRIS_PLAYFIELD_H_*/ diff --git a/games/tetris/view.c b/games/tetris/view.c index 5ac86f2..a8b3696 100644 --- a/games/tetris/view.c +++ b/games/tetris/view.c @@ -30,10 +30,12 @@ #define TETRIS_VIEW_LINE_BLINK_DELAY 75 // colors of game elements -#define TETRIS_VIEW_COLORSPACE 0 -#define TETRIS_VIEW_COLORBORDER 1 -#define TETRIS_VIEW_COLORFADE 2 -#define TETRIS_VIEW_COLORPIECE 3 +#define TETRIS_VIEW_COLORSPACE 0 +#define TETRIS_VIEW_COLORBORDER 1 +#define TETRIS_VIEW_COLORFADE 2 +#define TETRIS_VIEW_COLORPIECE 3 +#define TETRIS_VIEW_COLORPAUSE 1 +#define TETRIS_VIEW_COLORCOUNTER 2 /*************************** @@ -53,7 +55,7 @@ uint8_t tetris_view_getPieceColor (tetris_view_t *pV) } else { - return TETRIS_VIEW_COLORBORDER; + return TETRIS_VIEW_COLORPAUSE; } } @@ -207,17 +209,18 @@ void tetris_view_drawBorders(uint8_t nColor) setpixel((pixel){4, y}, nColor); setpixel((pixel){15, y}, nColor); } + for (y = 0; y < 5; ++y) { - for (x = 0; x <= 3; ++x){ - - if ((y<1 || y>3) || (x<1 || y>3)){ - setpixel((pixel){x, y}, nColor); - setpixel((pixel){x, y + 11}, nColor); - } + for (x = 0; x <= 3; ++x) + { + if ((y < 1 || y > 3) || (x < 1 || y > 3)) + { + setpixel((pixel){x, y}, nColor); + setpixel((pixel){x, y + 11}, nColor); + } } } - } @@ -287,69 +290,39 @@ void tetris_view_blinkLines(tetris_playfield_t *pPl) /* Function: tetris_view_showLineNumbers * Description: displays completed Lines (0-99) * Argmument pV: pointer to the view - * Argument nColor: color * Return value: void */ -void tetris_view_showLineNumbers (tetris_view_t *pV, uint8_t nColor) +void tetris_view_showLineNumbers(tetris_view_t *pV) { - //Get number of completed lines - uint8_t Lines = tetris_logic_getLines(pV->pLogic); - uint8_t nPen; + // get number of completed lines + uint8_t nLines = tetris_logic_getLines(pV->pLogic); - int x=0, y=0, i; - int ones, tens; - - ones= Lines%10; - tens=(Lines/10)%10; + // get decimal places + int8_t nOnes = nLines % 10; + int8_t nTens = (nLines / 10) % 10; - //pick drawing color, dark if ones=0, faded otherwise (bright counter gets confused with piece preview) - if ((ones%10)!=0) - nPen=TETRIS_VIEW_COLORFADE; - else nPen=TETRIS_VIEW_COLORSPACE; - - //Draws ones in the upper part of the border as a 3x3 square with 0-9 pixels - //Start at column 1 - y=1; - for (i=1;i<=9;i++) - { - //Start at line 1, increase every loop cycle - x++; - - //the square is just three pixels wide, start over in next column once the row is full - if (x%4==0) + // draws the decimal places as 3x3 squares with 9 pixels + for (int i = 0, x = 1, y = 1; i < 9; ++i) { - y++; - x=1; + // pick drawing color + uint8_t nOnesPen = nOnes > i ? + TETRIS_VIEW_COLORCOUNTER : TETRIS_VIEW_COLORSPACE; + uint8_t nTensPen = nTens > i ? + TETRIS_VIEW_COLORCOUNTER : TETRIS_VIEW_COLORSPACE; + // wrap lines if required + if ((x % 4) == 0) + { + y++; + x = 1; + } + // ones + setpixel((pixel){x, y}, nOnesPen); + // tens (increment x, add vertical offset for lower part of the border) + setpixel((pixel){x++, y + 11}, nTensPen); } - setpixel((pixel){x,y}, nPen); - //only draw as many ones as there are, make the rest of the square dark. - if (i==ones) nPen=TETRIS_VIEW_COLORSPACE; - } - - //back to normal color, but only if tens is not divisible by 10 - if ((tens%10)!=0) - nPen=TETRIS_VIEW_COLORFADE; - else nPen=TETRIS_VIEW_COLORSPACE; - - //Draws ones in the lower part of the border as a 3x3 square with 0-9 pixels - x=0; - y=12; //offset for lower part of the border - for (i=1;i<=9;i++) - { - x++; //Start at line 1, increase every loop cycle - - //the square is just three pixels wide, start over in next column once the row is full - if (x%4==0) - { - y++; - x=1; - } - setpixel((pixel){x,y}, nPen); - //only draw as many ones as there are, make the rest of the square dark. - if (i==tens) nPen=TETRIS_VIEW_COLORSPACE; - } } + /**************************** * construction/destruction * ****************************/ @@ -441,7 +414,7 @@ void tetris_view_update(tetris_view_t *pV) if (tetris_playfield_getRowMask(pV->pPl) != 0) { tetris_view_blinkLines(pV->pPl); - tetris_view_showLineNumbers(pV, TETRIS_VIEW_COLORPIECE); + tetris_view_showLineNumbers(pV); } // draw preview piece