diff --git a/games/tetris/bucket.c b/games/tetris/bucket.c index 517a210..5de7c77 100644 --- a/games/tetris/bucket.c +++ b/games/tetris/bucket.c @@ -17,7 +17,7 @@ * @param pBucket the bucket we want information from * @return TETRIS_BUS_HOVERING or TETRIS_BUS_GLIDING */ -tetris_bucket_status_t tetris_bucket_hoverStatus(tetris_bucket_t* pBucket) +static tetris_bucket_status_t tetris_bucket_hoverStatus(tetris_bucket_t* pBucket) { assert(pBucket != NULL); @@ -92,23 +92,6 @@ void tetris_bucket_destruct(tetris_bucket_t *pBucket) * bucket related functions * *******************************/ -uint8_t tetris_bucket_calculateLines(uint8_t nRowMask) -{ - uint8_t nMask = 0x0001; - uint8_t nLines = 0; - for (uint8_t i = 0; i < 4; ++i) - { - if ((nMask & nRowMask) != 0) - { - ++nLines; - } - nMask <<= 1; - } - - return nLines; -} - - void tetris_bucket_reset(tetris_bucket_t *pBucket) { assert(pBucket != NULL); @@ -520,7 +503,7 @@ uint16_t* tetris_bucket_predictNextRow(tetris_bucket_iterator_t *pIt) nTemp << pIt->nShift : nTemp >> -pIt->nShift; pIt->nPieceMap <<= 4; } - pIt->nCurrentRow = pIt->pBucket->dump[pIt->nCurrentRow--] | nTemp; + pIt->nRowBuffer = pIt->pBucket->dump[pIt->nCurrentRow--] | nTemp; // don't return full (and therefore removed) rows if (pIt->nRowBuffer == pIt->pBucket->nFullRow) { diff --git a/games/tetris/bucket.h b/games/tetris/bucket.h index 2502911..40cb8fa 100644 --- a/games/tetris/bucket.h +++ b/games/tetris/bucket.h @@ -100,7 +100,27 @@ void tetris_bucket_destruct(tetris_bucket_t *pBucket); * @param nRowMask row mask from which the no. of lines will be calculated * @return number of lines of the row mask */ -uint8_t tetris_bucket_calculateLines(uint8_t nRowMask); +inline static uint8_t tetris_bucket_calculateLines(uint8_t nRowMask) +{ + uint8_t nLines = 0; + if (nRowMask & 0x01) + { + ++nLines; + } + if (nRowMask & 0x02) + { + ++nLines; + } + if (nRowMask & 0x04) + { + ++nLines; + } + if (nRowMask & 0x08) + { + ++nLines; + } + return nLines; +} /** diff --git a/games/tetris/input.c b/games/tetris/input.c index 7aabfc6..693f519 100644 --- a/games/tetris/input.c +++ b/games/tetris/input.c @@ -78,8 +78,8 @@ * @param pIn pointer to an input object * @param cmd the command whose counter should be set */ -void tetris_input_chatterProtect(tetris_input_t *pIn, - tetris_input_command_t cmd) +static void tetris_input_chatterProtect(tetris_input_t *pIn, + tetris_input_command_t cmd) { // never exceed the index assert(cmd < TETRIS_INCMD_NONE); @@ -165,7 +165,7 @@ tetris_input_command_t tetris_input_mapCommand(tetris_bearing_t nBearing, * @return interpreted joystick command * @see tetris_input_command_t */ -tetris_input_command_t tetris_input_queryJoystick(tetris_input_t *pIn) +static tetris_input_command_t tetris_input_queryJoystick(tetris_input_t *pIn) { // map port input to a tetris command tetris_input_command_t cmdJoystick; diff --git a/games/tetris/variant_bastet.c b/games/tetris/variant_bastet.c index 4396b68..521971f 100644 --- a/games/tetris/variant_bastet.c +++ b/games/tetris/variant_bastet.c @@ -155,6 +155,105 @@ int tetris_bastet_qsortCompare(void const *pa, } +/** + * calculates a score for a piece at a given column + * @param pBastet the bastet instance of interest + * @param pPiece the piece to be tested + * @param nColum the column where the piece should be dropped + * @return score for the given move + */ +static int16_t tetris_bastet_evaluateMove(tetris_bastet_variant_t *pBastet, + tetris_piece_t *pPiece, + int8_t nColumn) +{ + // initial score of the given piece + int16_t nScore = -32000; + + // the row where the given piece collides + int8_t nDeepestRow = tetris_bucket_predictDeepestRow(pBastet->pBucket, + pPiece, pBastet->pStartingRow[nColumn + 3], nColumn); + + // in case the prediction fails we return the lowest possible score + if (nDeepestRow == TETRIS_BUCKET_INVALIDROW) + { + return -32766; + } + + // modify score based on complete lines + int8_t nLines = tetris_bucket_predictCompleteLines(pBastet->pBucket, + pPiece, nDeepestRow, nColumn); + nScore += 5000 * nLines; + + // determine a sane range of columns whose heights we want to predict + int8_t nWidth = tetris_bucket_getWidth(pBastet->pBucket); + int8_t nStartCol, nStopCol; + // if lines have been removed, we need to recalculate all column heights + if (nLines != 0) + { + nStartCol = 0; + nStopCol = nWidth - 1; + } + // if no lines were removed, we only need to recalculate a few columns + else + { + nStartCol = (nColumn < 0) ? 0 : nColumn; + nStopCol = (nColumn + 3) < nWidth ? nColumn + 3 : nWidth - 1; + } + + // predict column heights of this move + tetris_bastet_calcPredictedColHeights(pBastet, pPiece, nDeepestRow, nColumn, + nStartCol, nStopCol); + + // modify score based on predicted column heights + for (int x = 0; x < nWidth; ++x) + { + if ((x >= nStartCol) && (x <= nStopCol)) + { + nScore -= TETRIS_BASTET_HEIGHT_FACTOR * pBastet->pColHeights[x]; + } + else + { + nScore -= pBastet->pColScore[x]; + } + } + + return nScore; +} + + +/** + * calculates the best possible score for every piece + * @param pBastet the bastet instance of interest + */ +static void tetris_bastet_evaluatePieces(tetris_bastet_variant_t *pBastet) +{ + // precache actual column heights + tetris_bastet_doPreprocessing(pBastet); + int8_t nWidth = tetris_bucket_getWidth(pBastet->pBucket); + 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_setShape(pPiece, nBlock); + int8_t nAngleCount = tetris_piece_getAngleCount(pPiece); + for (int8_t nAngle = TETRIS_PC_ANGLE_0; nAngle < nAngleCount; ++nAngle) + { + tetris_piece_setAngle(pPiece, nAngle); + for (int8_t nCol = -3; nCol < nWidth; ++nCol) + { + int16_t nScore = tetris_bastet_evaluateMove(pBastet, + pPiece, nCol); + nMaxScore = nMaxScore > nScore ? nMaxScore : nScore; + } + } + pBastet->nPieceScore[nBlock].shape = nBlock; + pBastet->nPieceScore[nBlock].nScore = nMaxScore; + } + tetris_piece_destruct(pPiece); +} + + /*************** * entry point * ***************/ @@ -247,94 +346,6 @@ void tetris_bastet_destruct(void *pVariantData) * bastet related functions * ****************************/ -int16_t tetris_bastet_evaluateMove(tetris_bastet_variant_t *pBastet, - tetris_piece_t *pPiece, - int8_t nColumn) -{ - // initial score of the given piece - int16_t nScore = -32000; - - // the row where the given piece collides - int8_t nDeepestRow = tetris_bucket_predictDeepestRow(pBastet->pBucket, - pPiece, pBastet->pStartingRow[nColumn + 3], nColumn); - - // in case the prediction fails we return the lowest possible score - if (nDeepestRow == TETRIS_BUCKET_INVALIDROW) - { - return -32766; - } - - // modify score based on complete lines - int8_t nLines = tetris_bucket_predictCompleteLines(pBastet->pBucket, - pPiece, nDeepestRow, nColumn); - nScore += 5000 * nLines; - - // determine a sane range of columns whose heights we want to predict - int8_t nWidth = tetris_bucket_getWidth(pBastet->pBucket); - int8_t nStartCol, nStopCol; - // if lines have been removed, we need to recalculate all column heights - if (nLines != 0) - { - nStartCol = 0; - nStopCol = nWidth - 1; - } - // if no lines were removed, we only need to recalculate a few columns - else - { - nStartCol = (nColumn < 0) ? 0 : nColumn; - nStopCol = (nColumn + 3) < nWidth ? nColumn + 3 : nWidth - 1; - } - - // predict column heights of this move - tetris_bastet_calcPredictedColHeights(pBastet, pPiece, nDeepestRow, nColumn, - nStartCol, nStopCol); - - // modify score based on predicted column heights - for (int x = 0; x < nWidth; ++x) - { - if ((x >= nStartCol) && (x <= nStopCol)) - { - nScore -= TETRIS_BASTET_HEIGHT_FACTOR * pBastet->pColHeights[x]; - } - else - { - nScore -= pBastet->pColScore[x]; - } - } - - return nScore; -} - - -void tetris_bastet_evaluatePieces(tetris_bastet_variant_t *pBastet) -{ - // precache actual column heights - tetris_bastet_doPreprocessing(pBastet); - int8_t nWidth = tetris_bucket_getWidth(pBastet->pBucket); - 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_setShape(pPiece, nBlock); - int8_t nAngleCount = tetris_piece_getAngleCount(pPiece); - for (int8_t nAngle = TETRIS_PC_ANGLE_0; nAngle < nAngleCount; ++nAngle) - { - tetris_piece_setAngle(pPiece, nAngle); - for (int8_t nCol = -3; nCol < nWidth; ++nCol) - { - int16_t nScore = tetris_bastet_evaluateMove(pBastet, - pPiece, nCol); - nMaxScore = nMaxScore > nScore ? nMaxScore : nScore; - } - } - pBastet->nPieceScore[nBlock].shape = nBlock; - pBastet->nPieceScore[nBlock].nScore = nMaxScore; - } - tetris_piece_destruct(pPiece); -} - - tetris_piece_t* tetris_bastet_choosePiece(void *pVariantData) { assert(pVariantData != 0); diff --git a/games/tetris/variant_bastet.h b/games/tetris/variant_bastet.h index 523975e..a99f378 100644 --- a/games/tetris/variant_bastet.h +++ b/games/tetris/variant_bastet.h @@ -73,25 +73,6 @@ void tetris_bastet_destruct(void *pVariantData); * bastet related functions * ****************************/ -/** - * calculates a score for a piece at a given column - * @param pBastet the bastet instance of interest - * @param pPiece the piece to be tested - * @param nColum the column where the piece should be dropped - * @return score for the given move - */ -int16_t tetris_bastet_evaluateMove(tetris_bastet_variant_t *pBastet, - tetris_piece_t *pPiece, - int8_t nColumn); - - -/** - * calculates the best possible score for every piece - * @param pBastet the bastet instance of interest - */ -void tetris_bastet_evaluatePieces(tetris_bastet_variant_t *pBastet); - - /** * chooses a new worst possible piece * @param pVariantData the variant instance of interest diff --git a/games/tetris/view.c b/games/tetris/view.c index 2de3015..521cf77 100644 --- a/games/tetris/view.c +++ b/games/tetris/view.c @@ -122,28 +122,30 @@ * @param y y-coordinate of the pixel * @param nColor Color of the pixel */ -void tetris_view_setpixel(tetris_bearing_t nBearing, - uint8_t x, - uint8_t y, - uint8_t nColor) +static void tetris_view_setpixel(tetris_bearing_t nBearing, + uint8_t x, + uint8_t y, + uint8_t nColor) { x = VIEWCOLS - 1 - x; + pixel px; switch (nBearing) { case TETRIS_BEARING_0: - setpixel((pixel){x, y}, nColor); + px = (pixel){x, y}; break; case TETRIS_BEARING_90: - setpixel((pixel){y, VIEWCOLS - 1 - x}, nColor); + px = (pixel){y, VIEWCOLS - 1 - x}; break; case TETRIS_BEARING_180: - setpixel((pixel){VIEWCOLS - 1 - x, VIEWROWS - 1 - y}, nColor); + px = (pixel){VIEWCOLS - 1 - x, VIEWROWS - 1 - y}; break; case TETRIS_BEARING_270: - setpixel((pixel){VIEWROWS - 1 - y, x}, nColor); + px = (pixel){VIEWROWS - 1 - y, x}; break; } + setpixel(px, nColor); } @@ -155,7 +157,7 @@ void tetris_view_setpixel(tetris_bearing_t nBearing, * @param y y-coordinate of the line * @param nColor Color of the line */ -void tetris_view_drawHLine(tetris_bearing_t nBearing, +inline static void tetris_view_drawHLine(tetris_bearing_t nBearing, uint8_t x1, uint8_t x2, uint8_t y, @@ -178,11 +180,11 @@ void tetris_view_drawHLine(tetris_bearing_t nBearing, * @param y2 second y-coordinate of the line * @param nColor Color of the line */ -void tetris_view_drawVLine(tetris_bearing_t nBearing, - uint8_t x, - uint8_t y1, - uint8_t y2, - uint8_t nColor) +inline static void tetris_view_drawVLine(tetris_bearing_t nBearing, + uint8_t x, + uint8_t y1, + uint8_t y2, + uint8_t nColor) { assert(y1 <= y2); @@ -197,7 +199,7 @@ void tetris_view_drawVLine(tetris_bearing_t nBearing, * helper function to dim the piece color if game is paused * @param pV pointer to the view whose pause status is of interest */ -uint8_t tetris_view_getPieceColor(tetris_view_t *pV) +inline static uint8_t tetris_view_getPieceColor(tetris_view_t *pV) { if (pV->modeCurrent == TETRIS_VIMO_RUNNING) { @@ -214,7 +216,7 @@ uint8_t tetris_view_getPieceColor(tetris_view_t *pV) * redraws the dump and the falling piece (if necessary) * @param pV pointer to the view on which the dump should be drawn */ -void tetris_view_drawDump(tetris_view_t *pV) +static void tetris_view_drawDump(tetris_view_t *pV) { assert(pV->pBucket != NULL); if (tetris_bucket_getRow(pV->pBucket) <= -4) @@ -222,60 +224,36 @@ void tetris_view_drawDump(tetris_view_t *pV) return; } - tetris_bearing_t nBearing = - pV->pVariantMethods->getBearing(pV->pVariant); - - int8_t nPieceRow = tetris_bucket_getRow(pV->pBucket); - uint16_t nRowMap; - uint16_t nElementMask; - - tetris_bucket_status_t status = tetris_bucket_getStatus(pV->pBucket); for (int8_t nRow = TETRIS_VIEW_HEIGHT_DUMP - 1; nRow >= 0; --nRow) { - nRowMap = tetris_bucket_getDumpRow(pV->pBucket, nRow); + uint16_t nRowMap = tetris_bucket_getDumpRow(pV->pBucket, nRow); // if a piece is hovering or gliding it needs to be drawn - if ((status == TETRIS_BUS_HOVERING) || (status == TETRIS_BUS_GLIDING) || - (status == TETRIS_BUS_GAMEOVER)) + int8_t nPieceRow = tetris_bucket_getRow(pV->pBucket); + tetris_bucket_status_t status = tetris_bucket_getStatus(pV->pBucket); + if (((status == TETRIS_BUS_HOVERING) || (status == TETRIS_BUS_GLIDING) + || (status == TETRIS_BUS_GAMEOVER)) && (nRow >= nPieceRow) + && (nRow <= nPieceRow + 3)) { - if ((nRow >= nPieceRow) && (nRow <= nPieceRow + 3)) - { - int8_t y = nRow - nPieceRow; - int8_t nColumn = tetris_bucket_getColumn(pV->pBucket); - uint16_t nPieceMap = + int8_t nColumn = tetris_bucket_getColumn(pV->pBucket); + uint16_t nPieceMap = tetris_piece_getBitmap(tetris_bucket_getPiece(pV->pBucket)); - // clear all bits of the piece we are not interested in and - // align the remaining row to LSB - nPieceMap = (nPieceMap & (0x000F << (y << 2))) >> (y << 2); - // shift remaining part to current column - if (nColumn >= 0) - { - nPieceMap <<= nColumn; - } - else - { - nPieceMap >>= -nColumn; - } - // cut off unwanted stuff - // nPieceMap &= 0x03ff; - // finally embed piece into the view - nRowMap |= nPieceMap; - } + // clear all bits of the piece we are not interested in and + // align the remaining row to LSB + int8_t y = nRow - nPieceRow; + nPieceMap = (nPieceMap & (0x000F << (y << 2))) >> (y << 2); + // shift remaining part to current column and embed piece into view + nRowMap |= nColumn >= 0 ? + nPieceMap << nColumn : nPieceMap >> -nColumn; } - nElementMask = 0x0001; - + uint16_t nElementMask = 0x0001; for (int8_t x = 0; x < TETRIS_VIEW_WIDTH_DUMP; ++x) { - unsigned char nColor; - if ((nRowMap & nElementMask) != 0) - { - nColor = tetris_view_getPieceColor(pV); - } - else - { - nColor = TETRIS_VIEW_COLORSPACE; - } + unsigned char nColor = (nRowMap & nElementMask) ? + tetris_view_getPieceColor(pV) : TETRIS_VIEW_COLORSPACE; + tetris_bearing_t const nBearing = + pV->pVariantMethods->getBearing(pV->pVariant); tetris_view_setpixel(nBearing, TETRIS_VIEW_XOFFSET_DUMP + x, TETRIS_VIEW_YOFFSET_DUMP + nRow, nColor); nElementMask <<= 1; @@ -283,13 +261,14 @@ void tetris_view_drawDump(tetris_view_t *pV) } } + #ifdef TETRIS_VIEW_XOFFSET_PREVIEW /** * redraws the preview window * @param pV pointer to the view on which the piece should be drawn * @param pPc pointer to the piece for the preview window (may be NULL) */ -void tetris_view_drawPreviewPiece(tetris_view_t *pV, tetris_piece_t *pPc) +static void tetris_view_drawPreviewPiece(tetris_view_t *pV, tetris_piece_t *pPc) { tetris_bearing_t nBearing = pV->pVariantMethods->getBearing(pV->pVariant); @@ -350,7 +329,7 @@ void tetris_view_drawPreviewPiece(tetris_view_t *pV, tetris_piece_t *pPc) * @param pV pointer to the view on which the borders should be drawn * @param nColor the color for the border */ -void tetris_view_drawBorders(tetris_view_t *pV, +static void tetris_view_drawBorders(tetris_view_t *pV, uint8_t nColor) { tetris_bearing_t nBearing = @@ -453,7 +432,7 @@ void tetris_view_drawBorders(tetris_view_t *pV, * lets the borders blink to notify player of a level change * @param pV pointer to the view whose borders should blink */ -void tetris_view_blinkBorders(tetris_view_t *pV) +static void tetris_view_blinkBorders(tetris_view_t *pV) { for (uint8_t i = 0; i < TETRIS_VIEW_BORDER_BLINK_COUNT; ++i) { @@ -469,12 +448,13 @@ void tetris_view_blinkBorders(tetris_view_t *pV) * lets complete lines blink to emphasize their removal * @param pV pointer to the view whose complete lines should blink */ -void tetris_view_blinkLines(tetris_view_t *pV) +static void tetris_view_blinkLines(tetris_view_t *pV) { // reduce necessity of pointer arithmetic int8_t nRow = tetris_bucket_getRow(pV->pBucket); uint8_t nRowMask = tetris_bucket_getRowMask(pV->pBucket); + int8_t nMask = 0x01; tetris_bearing_t nBearing = pV->pVariantMethods->getBearing(pV->pVariant); @@ -493,7 +473,7 @@ void tetris_view_blinkLines(tetris_view_t *pV) for (uint8_t j = 0; j <= nDeepestRowOffset; ++j) { // is current line a complete line? - if ((nRowMask & (0x01 << j)) != 0) + if ((nRowMask & (nMask << j)) != 0) { // draw line in current color uint8_t y = nRow + j; @@ -502,7 +482,6 @@ void tetris_view_blinkLines(tetris_view_t *pV) uint8_t nColor = (nColIdx == 0 ? TETRIS_VIEW_COLORFADE : TETRIS_VIEW_COLORPIECE); - // setpixel((pixel){14 - x, y}, nColor); tetris_view_setpixel(nBearing, TETRIS_VIEW_XOFFSET_DUMP + x, TETRIS_VIEW_YOFFSET_DUMP + y, @@ -522,7 +501,7 @@ void tetris_view_blinkLines(tetris_view_t *pV) * displays completed Lines (0-99) * @param pV pointer to the view */ -void tetris_view_showLineNumbers(tetris_view_t *pV) +static void tetris_view_showLineNumbers(tetris_view_t *pV) { tetris_bearing_t nBearing = @@ -578,8 +557,8 @@ void tetris_view_showLineNumbers(tetris_view_t *pV) * @param nHighscoreName the champion's initials packed into a uint16_t * @param pszName pointer to an array of char for the unpacked initials */ -void tetris_view_formatHighscoreName(uint16_t nHighscoreName, - char *pszName) +static void tetris_view_formatHighscoreName(uint16_t nHighscoreName, + char *pszName) { pszName[0] = ((nHighscoreName >> 10) & 0x1F) + 65; if (pszName[0] == '_') @@ -653,13 +632,6 @@ void tetris_view_getDimensions(int8_t *w, } -void tetris_view_setViewMode(tetris_view_t *pV, tetris_view_mode_t vm) -{ - pV->modeOld = pV->modeCurrent; - pV->modeCurrent = vm; -} - - void tetris_view_update(tetris_view_t *pV) { assert(pV != NULL); diff --git a/games/tetris/view.h b/games/tetris/view.h index 1e21e37..7d62929 100644 --- a/games/tetris/view.h +++ b/games/tetris/view.h @@ -88,7 +88,12 @@ void tetris_view_getDimensions(int8_t *w, * @param pV pointer to the view whose mode should be set * @param vm see definition of tetris_view_mode_t */ -void tetris_view_setViewMode(tetris_view_t *pV, tetris_view_mode_t vm); +inline static void tetris_view_setViewMode(tetris_view_t *const pV, + tetris_view_mode_t const vm) +{ + pV->modeOld = pV->modeCurrent; + pV->modeCurrent = vm; +} /**