optimized collision detection and better preprocessing for bastet (bastet algorithm almost twice as fast)
This commit is contained in:
parent
a246779eff
commit
7deb41c236
|
@ -2,6 +2,7 @@
|
|||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include "../../compat/pgmspace.h"
|
||||
#include "../../config.h"
|
||||
#include "bucket.h"
|
||||
#include "piece.h"
|
||||
|
@ -14,10 +15,12 @@
|
|||
/**
|
||||
* determines if piece is either hovering or gliding
|
||||
* @param pBucket the bucket we want information from
|
||||
* @return TETRIS_PFS_HOVERING or TETRIS_PFS_GLIDING
|
||||
* @return TETRIS_BUS_HOVERING or TETRIS_BUS_GLIDING
|
||||
*/
|
||||
tetris_bucket_status_t tetris_bucket_hoverStatus(tetris_bucket_t* pBucket)
|
||||
{
|
||||
assert(pBucket != NULL);
|
||||
|
||||
// if the piece touches the dump we ensure that the status is "gliding"
|
||||
if (tetris_bucket_collision(pBucket, pBucket->nColumn, pBucket->nRow + 1))
|
||||
{
|
||||
|
@ -115,7 +118,7 @@ void tetris_bucket_reset(tetris_bucket_t *pBucket)
|
|||
// clear dump if it has been allocated in memory
|
||||
if (pBucket->dump != NULL)
|
||||
{
|
||||
memset(pBucket->dump, 0, pBucket->nHeight);
|
||||
memset(pBucket->dump, 0, pBucket->nHeight * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
pBucket->status = TETRIS_BUS_READY;
|
||||
|
@ -148,7 +151,7 @@ void tetris_bucket_insertPiece(tetris_bucket_t *pBucket,
|
|||
{
|
||||
assert((pBucket != NULL) && (pPiece != NULL) && (ppOldPiece != NULL));
|
||||
|
||||
// a piece can only be inserted in state TETRIS_PFS_READY
|
||||
// a piece can only be inserted in state TETRIS_BUS_READY
|
||||
assert(pBucket->status == TETRIS_BUS_READY);
|
||||
|
||||
// row mask is now meaningless
|
||||
|
@ -182,94 +185,50 @@ uint8_t tetris_bucket_collision(tetris_bucket_t *pBucket,
|
|||
int8_t nColumn,
|
||||
int8_t nRow)
|
||||
{
|
||||
assert(pBucket != NULL);
|
||||
// A piece is represented by 16 bits (4 bits per row where the LSB marks the
|
||||
// left most position). The part of the bucket which is covered by the piece
|
||||
// is converted to this format (including the bucket borders) so that a
|
||||
// simple bitwise 'AND' tells us if the piece and the dump overlap.
|
||||
|
||||
// only allow coordinates which are within sane ranges
|
||||
assert(pBucket != NULL);
|
||||
assert((nColumn > -4) && (nColumn < pBucket->nWidth));
|
||||
assert((nRow > -4) && (nRow < pBucket->nHeight));
|
||||
|
||||
// The rows of a piece get compared with the background one by one
|
||||
// until either a collision occures or all rows are compared. Both the
|
||||
// piece row and the part of the bucket it covers are represented in
|
||||
// 4 bits which were singled out from their corresponding uint16_t
|
||||
// values and are aligned to LSB. In case where a piece overlaps with
|
||||
// either the left or the right border we "enhance" the bucket part
|
||||
// via bit shifting and set all bits representing the border to 1.
|
||||
//
|
||||
// NOTE: LSB represents the left most position.
|
||||
uint16_t nPieceMap = tetris_piece_getBitmap(pBucket->pPiece);
|
||||
uint16_t nBucketPart;
|
||||
uint16_t nPieceRowMap;
|
||||
|
||||
// negative nRow values indicate that the piece hasn't fully entered the
|
||||
// bucket yet which requires special treatment if the piece overlaps
|
||||
// with either the left or the right border
|
||||
if (nRow < 0)
|
||||
// left and right borders
|
||||
uint16_t nBucketPart = 0;
|
||||
if (nColumn < 0)
|
||||
{
|
||||
uint16_t nBorderMask = 0x0000;
|
||||
// piece overlaps with left border
|
||||
if (nColumn < 0)
|
||||
{
|
||||
nBorderMask = 0x1111 << (-nColumn - 1);
|
||||
}
|
||||
// piece overlaps with right border
|
||||
else if ((nColumn + 3) >= pBucket->nWidth)
|
||||
{
|
||||
nBorderMask = 0x8888 >> ((nColumn + 3) - pBucket->nWidth);
|
||||
}
|
||||
// return if piece collides with border
|
||||
if ((nPieceMap & nBorderMask) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
static uint16_t const nLeftPart[] PROGMEM = {0x7777, 0x3333, 0x1111};
|
||||
nBucketPart = pgm_read_word(&nLeftPart[nColumn + 3]);
|
||||
}
|
||||
else if (nColumn >= pBucket->nWidth - 3)
|
||||
{
|
||||
static uint16_t const nRightPart[] PROGMEM = {0xEEEE, 0xCCCC, 0x8888};
|
||||
nBucketPart = pgm_read_word(&nRightPart[pBucket->nWidth - nColumn - 1]);
|
||||
}
|
||||
// lower border
|
||||
if (nRow > pBucket->nHeight - 4)
|
||||
{
|
||||
nBucketPart |= 0xFFFF << ((pBucket->nHeight - nRow) * 4);
|
||||
}
|
||||
|
||||
// here we check the part which has already entered the bucket
|
||||
for (int8_t y = (nRow < 0) ? -nRow : 0; y < 4; ++y)
|
||||
int8_t const nStop = (nRow + 3) < pBucket->nHeight ?
|
||||
nRow + 3 : pBucket->nHeight - 1;
|
||||
// mask those blocks which are not covered by the piece
|
||||
uint16_t nDumpMask = nColumn >= 0 ? 0x000F << nColumn : 0x000F >> -nColumn;
|
||||
// value for shifting blocks to the corresponding part of the piece
|
||||
int8_t nShift = -nColumn + (nRow < 0 ? 4 * -nRow : 0);
|
||||
for (int8_t y = nRow >= 0 ? nRow : 0; y <= nStop; ++y)
|
||||
{
|
||||
// current piece row overlaps with lower border
|
||||
if ((y + nRow) >= pBucket->nHeight)
|
||||
{
|
||||
// all 4 bits represent the lower border
|
||||
nBucketPart = 0x000F;
|
||||
}
|
||||
// piece overlaps with left border
|
||||
else if (nColumn < 0)
|
||||
{
|
||||
// clear all bits we are not interested in
|
||||
nBucketPart = (pBucket->dump[y + nRow] & (0x000F >> -nColumn));
|
||||
// add zeros to the left (the bits "behind" the left border)
|
||||
nBucketPart <<= -nColumn;
|
||||
// set bits beyond left border to 1
|
||||
nBucketPart |= 0x000F >> (4 + nColumn);
|
||||
}
|
||||
// piece overlaps with right border
|
||||
else if ((nColumn + 3) >= pBucket->nWidth)
|
||||
{
|
||||
// align the bits we are interested in to LSB
|
||||
// (thereby clearing the rest)
|
||||
nBucketPart = pBucket->dump[y + nRow] >> nColumn;
|
||||
// set bits beyond right border to 1
|
||||
nBucketPart |= 0xFFF8 >> (nColumn + 3 - pBucket->nWidth);
|
||||
}
|
||||
// current row neither overlaps with left, right nor lower border
|
||||
else
|
||||
{
|
||||
// clear all bits we are not interested in and align the
|
||||
// remaing row to LSB
|
||||
nBucketPart =
|
||||
(pBucket->dump[y + nRow] & (0x000F << nColumn)) >> nColumn;
|
||||
}
|
||||
|
||||
// clear all bits of the piece we are not interested in and
|
||||
// align the remaing row to LSB
|
||||
nPieceRowMap = (nPieceMap & (0x000F << (y << 2))) >> (y << 2);
|
||||
|
||||
// finally check for a collision
|
||||
if ((nBucketPart & nPieceRowMap) != 0)
|
||||
uint16_t nTemp = pBucket->dump[y] & nDumpMask;
|
||||
nBucketPart |= nShift >= 0 ? nTemp << nShift : nTemp >> -nShift;
|
||||
if ((tetris_piece_getBitmap(pBucket->pPiece) & nBucketPart) != 0)
|
||||
{
|
||||
// collision
|
||||
return 1;
|
||||
}
|
||||
nShift += 4;
|
||||
}
|
||||
|
||||
// if we reach here, no collision was detected
|
||||
|
@ -412,7 +371,7 @@ void tetris_bucket_removeCompleteLines(tetris_bucket_t *pBucket)
|
|||
{
|
||||
assert(pBucket != NULL);
|
||||
|
||||
// rows can only be removed if we are in state TETRIS_PFS_DOCKED
|
||||
// rows can only be removed if we are in state TETRIS_BUS_DOCKED
|
||||
assert(pBucket->status == TETRIS_BUS_DOCKED);
|
||||
|
||||
// bit mask of a full row
|
||||
|
@ -560,32 +519,49 @@ uint16_t tetris_bucket_getDumpRow(tetris_bucket_t *pBucket,
|
|||
|
||||
int8_t tetris_bucket_predictDeepestRow(tetris_bucket_t *pBucket,
|
||||
tetris_piece_t *pPiece,
|
||||
int8_t nStartingRow,
|
||||
int8_t nColumn)
|
||||
{
|
||||
int8_t nRow = tetris_bucket_getPieceStartPos(pPiece);
|
||||
assert(pBucket != NULL);
|
||||
assert(pPiece != NULL);
|
||||
assert(nStartingRow >= -1 && nStartingRow < pBucket->nHeight);
|
||||
assert(nColumn >= -3 && nColumn < pBucket->nWidth);
|
||||
|
||||
// exchange current piece of the bucket (to use its collision detection)
|
||||
tetris_piece_t *pActualPiece = pBucket->pPiece;
|
||||
pBucket->pPiece = pPiece;
|
||||
|
||||
// is it actually possible to use this piece?
|
||||
if (tetris_bucket_collision(pBucket, (pBucket->nWidth - 2) / 2, nRow) ||
|
||||
(tetris_bucket_collision(pBucket, nColumn, nRow)))
|
||||
// determine empty rows of the bottom of piece which may overlap the dump
|
||||
uint16_t nMap = tetris_piece_getBitmap(pPiece);
|
||||
int8_t nOffset = 0;
|
||||
if ((nMap & 0xF000) != 0)
|
||||
nOffset = 3;
|
||||
else if ((nMap & 0xFF00) != 0)
|
||||
nOffset = 2;
|
||||
else if ((nMap & 0xFFF0) != 0)
|
||||
nOffset = 1;
|
||||
int8_t nRow = nStartingRow - nOffset;
|
||||
|
||||
// check if the piece collides with the left or the right wall
|
||||
if ((nRow < -3) || (((nColumn < 0) || (nColumn >= pBucket->nWidth - 3)) &&
|
||||
tetris_bucket_collision(pBucket, nColumn, nRow)))
|
||||
{
|
||||
// restore real piece
|
||||
pBucket->pPiece = pActualPiece;
|
||||
|
||||
return -4;
|
||||
nRow = TETRIS_BUCKET_INVALIDROW;
|
||||
}
|
||||
|
||||
// determine deepest row
|
||||
nRow = (nRow < pBucket->nFirstMatterRow - 4) ?
|
||||
pBucket->nFirstMatterRow - 4 : nRow;
|
||||
while ((nRow < pBucket->nHeight) &&
|
||||
(!tetris_bucket_collision(pBucket, nColumn, nRow + 1)))
|
||||
else
|
||||
{
|
||||
while (!tetris_bucket_collision(pBucket, nColumn, nRow + 1))
|
||||
{
|
||||
++nRow;
|
||||
}
|
||||
if ((nRow < 0) && (((nRow + 4) * 4) << nMap))
|
||||
{
|
||||
nRow = TETRIS_BUCKET_INVALIDROW;
|
||||
}
|
||||
}
|
||||
|
||||
// restore real piece
|
||||
// restore actual bucket piece
|
||||
pBucket->pPiece = pActualPiece;
|
||||
|
||||
return nRow;
|
||||
|
@ -597,44 +573,42 @@ int8_t tetris_bucket_predictCompleteLines(tetris_bucket_t *pBucket,
|
|||
int8_t nRow,
|
||||
int8_t nColumn)
|
||||
{
|
||||
assert(nRow > -4);
|
||||
int8_t nCompleteRows = 0;
|
||||
|
||||
// bit mask of a full row
|
||||
uint16_t nFullRow = 0xFFFF >> (16 - pBucket->nWidth);
|
||||
|
||||
if (nRow > -4)
|
||||
// determine sane start and stop values for the dump's index
|
||||
int8_t nStartRow = ((nRow + 3) >= pBucket->nHeight) ?
|
||||
pBucket->nHeight - 1 : nRow + 3;
|
||||
int8_t nStopRow = (nRow < 0) ? 0 : nRow;
|
||||
|
||||
uint16_t nPiece = tetris_piece_getBitmap(pPiece);
|
||||
|
||||
for (int8_t i = nStartRow; i >= nStopRow; --i)
|
||||
{
|
||||
// determine sane start and stop values for the dump's index
|
||||
int8_t nStartRow =
|
||||
((nRow + 3) >= pBucket->nHeight) ? pBucket->nHeight - 1 : nRow + 3;
|
||||
int8_t nStopRow = (nRow < 0) ? 0 : nRow;
|
||||
int8_t y = i - nRow;
|
||||
|
||||
uint16_t nPiece = tetris_piece_getBitmap(pPiece);
|
||||
|
||||
for (int8_t i = nStartRow; i >= nStopRow; --i)
|
||||
// clear all bits of the piece we are not interested in and align the
|
||||
// rest to LSB
|
||||
uint16_t nPieceMap = (nPiece & (0x000F << (y << 2))) >> (y << 2);
|
||||
// shift the remaining content to the current column
|
||||
if (nColumn >= 0)
|
||||
{
|
||||
int8_t y = i - nRow;
|
||||
nPieceMap <<= nColumn;
|
||||
}
|
||||
else
|
||||
{
|
||||
nPieceMap >>= -nColumn;
|
||||
}
|
||||
// embed piece in dump map
|
||||
uint16_t nDumpMap = pBucket->dump[i] | nPieceMap;
|
||||
|
||||
// clear all bits of the piece we are not interested in and
|
||||
// align the rest to LSB
|
||||
uint16_t nPieceMap = (nPiece & (0x000F << (y << 2))) >> (y << 2);
|
||||
// shift the remaining content to the current column
|
||||
if (nColumn >= 0)
|
||||
{
|
||||
nPieceMap <<= nColumn;
|
||||
}
|
||||
else
|
||||
{
|
||||
nPieceMap >>= -nColumn;
|
||||
}
|
||||
// embed piece in dump map
|
||||
uint16_t nDumpMap = pBucket->dump[i] | nPieceMap;
|
||||
|
||||
// is current row a full row?
|
||||
if ((nFullRow & nDumpMap) == nFullRow)
|
||||
{
|
||||
++nCompleteRows;
|
||||
}
|
||||
// is current row a full row?
|
||||
if ((nFullRow & nDumpMap) == nFullRow)
|
||||
{
|
||||
++nCompleteRows;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,13 @@
|
|||
#include "piece.h"
|
||||
|
||||
|
||||
/***********
|
||||
* defines *
|
||||
***********/
|
||||
|
||||
#define TETRIS_BUCKET_INVALIDROW -4
|
||||
|
||||
|
||||
/*********
|
||||
* types *
|
||||
*********/
|
||||
|
@ -245,11 +252,13 @@ uint16_t tetris_bucket_getDumpRow(tetris_bucket_t *pBucket,
|
|||
* returns the deepest possible row for a given piece
|
||||
* @param pBucket the bucket on which we want to test a piece
|
||||
* @param pPiece the piece which should be tested
|
||||
* @param nStartingRow the row where the collision detection should start
|
||||
* @param nColumn the column where the piece should be dropped
|
||||
* @return the row of the piece (bucket compliant coordinates)
|
||||
*/
|
||||
int8_t tetris_bucket_predictDeepestRow(tetris_bucket_t *pBucket,
|
||||
tetris_piece_t *pPiece,
|
||||
int8_t nStartingRow,
|
||||
int8_t nColumn);
|
||||
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "tetris_main.h"
|
||||
#include "variants.h"
|
||||
#include "bearing.h"
|
||||
#include "piece.h"
|
||||
#include "bucket.h"
|
||||
#include "view.h"
|
||||
#include "input.h"
|
||||
#include "highscore.h"
|
||||
#include "bucket.h"
|
||||
#include "input.h"
|
||||
#include "variants.h"
|
||||
#include "view.h"
|
||||
#include "tetris_main.h"
|
||||
|
||||
|
||||
void tetris_main(tetris_variant_t const *const pVariantMethods)
|
||||
|
|
|
@ -27,17 +27,21 @@
|
|||
***************************/
|
||||
|
||||
/**
|
||||
* calculate the score impact of every column (without any prediction)
|
||||
* @param pBastet bastet instance whose column heights should be calculated
|
||||
* Preprocess values like sane starting points for the collision detection or
|
||||
* the score impact of every unchanged column to speed up prediction routines.
|
||||
* @param pBastet bastet instance which should be preprocessed
|
||||
*/
|
||||
void tetris_bastet_calcActualColumnsScoreImpact(tetris_bastet_variant_t *pBastet)
|
||||
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_getFirstMatterRow(pBastet->pBucket);
|
||||
// printf("%d ", nStopRow);
|
||||
|
||||
// calculate the column heights of the actual bucket configuration
|
||||
// NOTE: in this loop, pColScore contains 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);
|
||||
|
@ -46,16 +50,65 @@ void tetris_bastet_calcActualColumnsScoreImpact(tetris_bastet_variant_t *pBastet
|
|||
{
|
||||
if ((nDumpRow & nColMask) != 0)
|
||||
{
|
||||
pBastet->pActualColScoreImpact[x] = nStartRow - y + 1;
|
||||
pBastet->pColScore[x] = nStartRow - y + 1;
|
||||
}
|
||||
nColMask <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// printf("-------------------------------------------\n ");
|
||||
// for (int i = 0; i < nWidth; ++i)
|
||||
// {
|
||||
// printf("%2d ", pBastet->pColScore[i]);
|
||||
// }
|
||||
// printf("\n");
|
||||
|
||||
|
||||
// starting points for collision detection (to speedup things)
|
||||
// calculate the maxima of the 4-tuples from column -3 to -1
|
||||
pBastet->pStartingRow[0] = pBastet->pColScore[0];
|
||||
pBastet->pStartingRow[1] = pBastet->pColScore[0] > pBastet->pColScore[1] ?
|
||||
pBastet->pColScore[0] : pBastet->pColScore[1];
|
||||
pBastet->pStartingRow[2] = pBastet->pStartingRow[1] > pBastet->pColScore[2]?
|
||||
pBastet->pStartingRow[1] : pBastet->pColScore[2];
|
||||
// calculate the maxima of the 4-tuples from column 0 to width-1
|
||||
for (int8_t i = 0; i < nWidth; ++i)
|
||||
{
|
||||
int8_t t0 = pBastet->pColScore[i] > pBastet->pColScore[i + 1] ?
|
||||
i : 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];
|
||||
}
|
||||
// for (int i = 0; i < nWidth + 3; ++i)
|
||||
// {
|
||||
// printf("%2d ", pBastet->pStartingRow[i]);
|
||||
// if (i == 2)
|
||||
// printf("| ");
|
||||
// }
|
||||
// printf("\n");
|
||||
// normalize to bucket geometry
|
||||
for (uint8_t i = 0; i < nWidth + 3; ++i)
|
||||
{
|
||||
pBastet->pStartingRow[i] = nStartRow - pBastet->pStartingRow[i];
|
||||
}
|
||||
|
||||
// calculate the score impact of every column
|
||||
for (int x = 0; x < nWidth; ++x)
|
||||
{
|
||||
pBastet->pActualColScoreImpact[x] *= TETRIS_BASTET_HEIGHT_FACTOR;
|
||||
pBastet->pColScore[x] *= TETRIS_BASTET_HEIGHT_FACTOR;
|
||||
}
|
||||
|
||||
// for (int i = 0; i < nWidth + 3; ++i)
|
||||
// {
|
||||
// printf("%2d ", pBastet->pStartingRow[i]);
|
||||
// if (i == 2)
|
||||
// printf("| ");
|
||||
// }
|
||||
// printf("\n");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -66,9 +119,8 @@ void tetris_bastet_calcActualColumnsScoreImpact(tetris_bastet_variant_t *pBastet
|
|||
* @param nColum the column where the piece should be dropped
|
||||
* @param nStartCol the first column of the range to be predicted
|
||||
* @param nStopCol the last column of the range to be predicted
|
||||
* @return 0 if dropped piece would cause an overflow, 1 if prediction succeeds
|
||||
*/
|
||||
uint8_t tetris_bastet_calcPredictedColHeights(tetris_bastet_variant_t *pBastet,
|
||||
void tetris_bastet_calcPredictedColHeights(tetris_bastet_variant_t *pBastet,
|
||||
tetris_piece_t *pPiece,
|
||||
int8_t nDeepestRow,
|
||||
int8_t nColumn,
|
||||
|
@ -80,11 +132,6 @@ uint8_t tetris_bastet_calcPredictedColHeights(tetris_bastet_variant_t *pBastet,
|
|||
int8_t nHeight = 1;
|
||||
uint16_t *pDump = tetris_bucket_predictBottomRow(&iterator,
|
||||
pBastet->pBucket, pPiece, nDeepestRow, nColumn);
|
||||
if (pDump == NULL)
|
||||
{
|
||||
// an immediately returned NULL is caused by a full dump -> low score
|
||||
return 0;
|
||||
}
|
||||
while (pDump != NULL)
|
||||
{
|
||||
uint16_t nColMask = 0x0001 << nStartCol;
|
||||
|
@ -99,7 +146,6 @@ uint8_t tetris_bastet_calcPredictedColHeights(tetris_bastet_variant_t *pBastet,
|
|||
pDump = tetris_bucket_predictNextRow(&iterator);
|
||||
++nHeight;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -186,7 +232,8 @@ void *tetris_bastet_construct(tetris_bucket_t *pBucket)
|
|||
pBastet->pBucket = pBucket;
|
||||
|
||||
int8_t nWidth = tetris_bucket_getWidth(pBastet->pBucket);
|
||||
pBastet->pActualColScoreImpact = (int8_t*) calloc(nWidth, sizeof(int8_t));
|
||||
pBastet->pColScore = (uint16_t*) calloc(nWidth + 3, sizeof(uint16_t));
|
||||
pBastet->pStartingRow = (int8_t*) calloc(nWidth + 3, sizeof(int8_t));
|
||||
pBastet->pColHeights = (int8_t*) calloc(nWidth, sizeof(int8_t));
|
||||
|
||||
return pBastet;
|
||||
|
@ -198,9 +245,9 @@ void tetris_bastet_destruct(void *pVariantData)
|
|||
assert(pVariantData != 0);
|
||||
tetris_bastet_variant_t *pBastetVariant =
|
||||
(tetris_bastet_variant_t *)pVariantData;
|
||||
if (pBastetVariant->pActualColScoreImpact != NULL)
|
||||
if (pBastetVariant->pColScore != NULL)
|
||||
{
|
||||
free(pBastetVariant->pActualColScoreImpact);
|
||||
free(pBastetVariant->pColScore);
|
||||
}
|
||||
if (pBastetVariant->pColHeights != NULL)
|
||||
{
|
||||
|
@ -228,7 +275,13 @@ int16_t tetris_bastet_evaluateMove(tetris_bastet_variant_t *pBastet,
|
|||
|
||||
// the row where the given piece collides
|
||||
int8_t nDeepestRow = tetris_bucket_predictDeepestRow(pBastet->pBucket,
|
||||
pPiece, nColumn);
|
||||
pPiece, pBastet->pStartingRow[nColumn], 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,
|
||||
|
@ -251,13 +304,9 @@ int16_t tetris_bastet_evaluateMove(tetris_bastet_variant_t *pBastet,
|
|||
nStopCol = (nColumn + 3) < nWidth ? nColumn + 3 : nWidth - 1;
|
||||
}
|
||||
|
||||
// predicted column heights
|
||||
if (!tetris_bastet_calcPredictedColHeights(pBastet, pPiece, nDeepestRow,
|
||||
nColumn, nStartCol, nStopCol))
|
||||
{
|
||||
// in case the prediction fails we return the lowest possible score
|
||||
return -32766;
|
||||
}
|
||||
// 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)
|
||||
|
@ -268,7 +317,7 @@ int16_t tetris_bastet_evaluateMove(tetris_bastet_variant_t *pBastet,
|
|||
}
|
||||
else
|
||||
{
|
||||
nScore -= pBastet->pActualColScoreImpact[x];
|
||||
nScore -= pBastet->pColScore[x];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,7 +328,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_calcActualColumnsScoreImpact(pBastet);
|
||||
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);
|
||||
|
|
|
@ -40,7 +40,8 @@ typedef struct tetris_bastet_variant_t
|
|||
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*/
|
||||
uint16_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 */
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue