modified bastet algorithm to behave more like the original
This commit is contained in:
parent
e4186bd02b
commit
1d28b75a0a
|
@ -528,6 +528,13 @@ int8_t tetris_playfield_getRow(tetris_playfield_t *pPl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int8_t tetris_playfield_getFirstMatterRow(tetris_playfield_t *pPl)
|
||||||
|
{
|
||||||
|
assert(pPl != NULL);
|
||||||
|
return pPl->nFirstMatterRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
uint8_t tetris_playfield_getRowMask(tetris_playfield_t *pPl)
|
uint8_t tetris_playfield_getRowMask(tetris_playfield_t *pPl)
|
||||||
{
|
{
|
||||||
assert(pPl != NULL);
|
assert(pPl != NULL);
|
||||||
|
|
|
@ -203,6 +203,14 @@ int8_t tetris_playfield_getColumn(tetris_playfield_t *pPl);
|
||||||
int8_t tetris_playfield_getRow(tetris_playfield_t *pPl);
|
int8_t tetris_playfield_getRow(tetris_playfield_t *pPl);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the row of the currently falling piece
|
||||||
|
* @param pPl the playfield we want information from
|
||||||
|
* @return highest row with matter
|
||||||
|
*/
|
||||||
|
int8_t tetris_playfield_getFirstMatterRow(tetris_playfield_t *pPl);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the row mask relative to nRow
|
* returns the row mask relative to nRow
|
||||||
* @param pPl the playfield we want information from
|
* @param pPl the playfield we want information from
|
||||||
|
|
|
@ -37,6 +37,75 @@ void tetris_bastet_clearColHeights(tetris_bastet_variant_t *pBastet,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calculate the actual column heights (without any prediction)
|
||||||
|
* @param pBastet bastet instance whose column heights should be calculated
|
||||||
|
*/
|
||||||
|
void tetris_bastet_calcActualColHeights(tetris_bastet_variant_t *pBastet)
|
||||||
|
{
|
||||||
|
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield);
|
||||||
|
int8_t nStartRow = tetris_playfield_getHeight(pBastet->pPlayfield) - 1;
|
||||||
|
int8_t nStopRow = tetris_playfield_getFirstMatterRow(pBastet->pPlayfield);
|
||||||
|
for (int8_t y = nStartRow; y >= nStopRow; --y)
|
||||||
|
{
|
||||||
|
uint16_t nDumpRow = tetris_playfield_getDumpRow(pBastet->pPlayfield, y);
|
||||||
|
uint16_t nColMask = 0x0001;
|
||||||
|
for (int8_t x = 0; x < nWidth; ++x)
|
||||||
|
{
|
||||||
|
if ((nDumpRow & nColMask) != 0)
|
||||||
|
{
|
||||||
|
pBastet->pActualColHeights[x] = nStartRow - y + 1;
|
||||||
|
}
|
||||||
|
nColMask <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calculate the predicted column heights for a given column range
|
||||||
|
* @param pBastet bastet instance whose column heights should be predicted
|
||||||
|
* @param pPiece the piece to be tested
|
||||||
|
* @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,
|
||||||
|
tetris_piece_t *pPiece,
|
||||||
|
int8_t nDeepestRow,
|
||||||
|
int8_t nColumn,
|
||||||
|
int8_t nStartCol,
|
||||||
|
int8_t nStopCol)
|
||||||
|
{
|
||||||
|
// go through every row and calculate column heights
|
||||||
|
tetris_playfield_iterator_t iterator;
|
||||||
|
int8_t nHeight = 1;
|
||||||
|
uint16_t *pDump = tetris_playfield_predictBottomRow(&iterator,
|
||||||
|
pBastet->pPlayfield, 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;
|
||||||
|
for (int x = nStartCol; x <= nStopCol; ++x)
|
||||||
|
{
|
||||||
|
if ((*pDump & nColMask) != 0)
|
||||||
|
{
|
||||||
|
pBastet->pColHeights[x] = nHeight;
|
||||||
|
}
|
||||||
|
nColMask <<= 1;
|
||||||
|
}
|
||||||
|
pDump = tetris_playfield_predictNextRow(&iterator);
|
||||||
|
++nHeight;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* compare function for quick sorting the pieces by score
|
* compare function for quick sorting the pieces by score
|
||||||
* @param pa the first value to compare
|
* @param pa the first value to compare
|
||||||
|
@ -119,6 +188,7 @@ void *tetris_bastet_construct(tetris_playfield_t *pPl)
|
||||||
pBastet->pPlayfield = pPl;
|
pBastet->pPlayfield = pPl;
|
||||||
|
|
||||||
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield);
|
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield);
|
||||||
|
pBastet->pActualColHeights = (int8_t*) calloc(nWidth, sizeof(int8_t));
|
||||||
pBastet->pColHeights = (int8_t*) calloc(nWidth, sizeof(int8_t));
|
pBastet->pColHeights = (int8_t*) calloc(nWidth, sizeof(int8_t));
|
||||||
tetris_bastet_clearColHeights(pBastet, 0, nWidth - 1);
|
tetris_bastet_clearColHeights(pBastet, 0, nWidth - 1);
|
||||||
|
|
||||||
|
@ -131,6 +201,10 @@ void tetris_bastet_destruct(void *pVariantData)
|
||||||
assert(pVariantData != 0);
|
assert(pVariantData != 0);
|
||||||
tetris_bastet_variant_t *pBastetVariant =
|
tetris_bastet_variant_t *pBastetVariant =
|
||||||
(tetris_bastet_variant_t *)pVariantData;
|
(tetris_bastet_variant_t *)pVariantData;
|
||||||
|
if (pBastetVariant->pActualColHeights != NULL)
|
||||||
|
{
|
||||||
|
free(pBastetVariant->pActualColHeights);
|
||||||
|
}
|
||||||
if (pBastetVariant->pColHeights != NULL)
|
if (pBastetVariant->pColHeights != NULL)
|
||||||
{
|
{
|
||||||
free(pBastetVariant->pColHeights);
|
free(pBastetVariant->pColHeights);
|
||||||
|
@ -152,67 +226,54 @@ int16_t tetris_bastet_evaluateMove(tetris_bastet_variant_t *pBastet,
|
||||||
tetris_piece_t *pPiece,
|
tetris_piece_t *pPiece,
|
||||||
int8_t nColumn)
|
int8_t nColumn)
|
||||||
{
|
{
|
||||||
|
// initial score of the given piece
|
||||||
|
int16_t nScore = -32000;
|
||||||
|
|
||||||
// the row where the given piece collides
|
// the row where the given piece collides
|
||||||
int8_t nDeepestRow = tetris_playfield_predictDeepestRow(pBastet->pPlayfield,
|
int8_t nDeepestRow = tetris_playfield_predictDeepestRow(pBastet->pPlayfield,
|
||||||
pPiece, nColumn);
|
pPiece, nColumn);
|
||||||
|
|
||||||
// initial score of the given piece
|
|
||||||
int16_t nScore = -32000;
|
|
||||||
|
|
||||||
// modify score based on complete lines
|
// modify score based on complete lines
|
||||||
int8_t nLines = tetris_playfield_predictCompleteLines(pBastet->pPlayfield,
|
int8_t nLines = tetris_playfield_predictCompleteLines(pBastet->pPlayfield,
|
||||||
pPiece, nDeepestRow, nColumn);
|
pPiece, nDeepestRow, nColumn);
|
||||||
nScore += 5000 * nLines;
|
nScore += 5000 * nLines;
|
||||||
|
|
||||||
// determine sane start and stop columns whose heights we want to calculate
|
// determine a sane range of columns whose heights we want to predict
|
||||||
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield);
|
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield);
|
||||||
int8_t nStartCol = ((nColumn - 1) < 0) ? 0 : nColumn - 1;
|
int8_t nStartCol, nStopCol;
|
||||||
int8_t nStopCol;
|
// if lines have been removed, we need to recalculate all column heights
|
||||||
// Do we start at the left most position?
|
if (nLines != 0)
|
||||||
// If we do we MUST calculate the heights of ALL columns (initial step)
|
|
||||||
if (nColumn <= -3)
|
|
||||||
{
|
{
|
||||||
|
nStartCol = 0;
|
||||||
nStopCol = nWidth - 1;
|
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 moved piece.
|
// if no lines were removed, we only need to recalculate a few columns
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
nStartCol = (nColumn < 0) ? 0 : nColumn;
|
||||||
nStopCol = (nColumn + 3) < nWidth ? nColumn + 3 : nWidth - 1;
|
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
|
// predicted column heights
|
||||||
tetris_playfield_iterator_t iterator;
|
if (!tetris_bastet_calcPredictedColHeights(pBastet, pPiece, nDeepestRow,
|
||||||
int8_t nHeight = 1;
|
nColumn, nStartCol, nStopCol))
|
||||||
uint16_t *pDump = tetris_playfield_predictBottomRow(&iterator,
|
|
||||||
pBastet->pPlayfield, pPiece, nDeepestRow, nColumn);
|
|
||||||
if (pDump == NULL)
|
|
||||||
{
|
{
|
||||||
// an immediately returned NULL is caused by a full dump -> low score
|
// in case the prediction fails we return the lowest possible score
|
||||||
return -32766;
|
return -32766;
|
||||||
}
|
}
|
||||||
while (pDump != NULL)
|
|
||||||
{
|
|
||||||
uint16_t nColMask = 0x0001 << nStartCol;
|
|
||||||
for (int x = nStartCol; x <= nStopCol; ++x)
|
|
||||||
{
|
|
||||||
if ((*pDump & nColMask) != 0)
|
|
||||||
{
|
|
||||||
pBastet->pColHeights[x] = nHeight;
|
|
||||||
}
|
|
||||||
nColMask <<= 1;
|
|
||||||
}
|
|
||||||
pDump = tetris_playfield_predictNextRow(&iterator);
|
|
||||||
++nHeight;
|
|
||||||
}
|
|
||||||
// modify score based on predicted column heights
|
// modify score based on predicted column heights
|
||||||
for (int x = 0; x < nWidth; ++x)
|
for (int x = 0; x < nWidth; ++x)
|
||||||
|
{
|
||||||
|
if ((x >= nStartCol) && (x <= nStopCol))
|
||||||
{
|
{
|
||||||
nScore -= 5 * pBastet->pColHeights[x];
|
nScore -= 5 * pBastet->pColHeights[x];
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nScore -= 5 * pBastet->pActualColHeights[x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nScore;
|
return nScore;
|
||||||
}
|
}
|
||||||
|
@ -220,6 +281,8 @@ int16_t tetris_bastet_evaluateMove(tetris_bastet_variant_t *pBastet,
|
||||||
|
|
||||||
void tetris_bastet_evaluatePieces(tetris_bastet_variant_t *pBastet)
|
void tetris_bastet_evaluatePieces(tetris_bastet_variant_t *pBastet)
|
||||||
{
|
{
|
||||||
|
// precache actual column heights
|
||||||
|
tetris_bastet_calcActualColHeights(pBastet);
|
||||||
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield);
|
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield);
|
||||||
tetris_piece_t *pPiece = tetris_piece_construct(TETRIS_PC_LINE,
|
tetris_piece_t *pPiece = tetris_piece_construct(TETRIS_PC_LINE,
|
||||||
TETRIS_PC_ANGLE_0);
|
TETRIS_PC_ANGLE_0);
|
||||||
|
|
|
@ -39,7 +39,8 @@ typedef struct tetris_bastet_variant_t
|
||||||
uint16_t nLines; /** number of completed lines */
|
uint16_t nLines; /** number of completed lines */
|
||||||
tetris_piece_t *pPreviewPiece; /** the piece for the preview */
|
tetris_piece_t *pPreviewPiece; /** the piece for the preview */
|
||||||
tetris_playfield_t *pPlayfield; /** playfield to be examined */
|
tetris_playfield_t *pPlayfield; /** playfield to be examined */
|
||||||
int8_t *pColHeights; /** calculated heights */
|
int8_t *pActualColHeights; /** actual columns heights */
|
||||||
|
int8_t *pColHeights; /** predicted column heights */
|
||||||
tetris_bastet_scorepair_t nPieceScores[7]; /** score for every piece */
|
tetris_bastet_scorepair_t nPieceScores[7]; /** score for every piece */
|
||||||
}
|
}
|
||||||
tetris_bastet_variant_t;
|
tetris_bastet_variant_t;
|
||||||
|
@ -74,7 +75,7 @@ void tetris_bastet_destruct(void *pVariantData);
|
||||||
* calculates a score for a piece at a given column
|
* calculates a score for a piece at a given column
|
||||||
* @param pBastet the bastet instance of interest
|
* @param pBastet the bastet instance of interest
|
||||||
* @param pPiece the piece to be tested
|
* @param pPiece the piece to be tested
|
||||||
* @param pnColum the column where the piece should be dropped
|
* @param nColum the column where the piece should be dropped
|
||||||
* @return score for the given move
|
* @return score for the given move
|
||||||
*/
|
*/
|
||||||
int16_t tetris_bastet_evaluateMove(tetris_bastet_variant_t *pBastet,
|
int16_t tetris_bastet_evaluateMove(tetris_bastet_variant_t *pBastet,
|
||||||
|
|
Loading…
Reference in New Issue