squeezed 216 bytes
This commit is contained in:
parent
28848358dd
commit
a8d2f7b47b
|
@ -2,6 +2,7 @@
|
|||
#define BUCKET_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include "../../config.h"
|
||||
#include "piece.h"
|
||||
|
||||
|
@ -11,6 +12,8 @@
|
|||
***********/
|
||||
|
||||
#define TETRIS_BUCKET_INVALIDROW -4
|
||||
#define TETRIS_BUCKET_MAX_COLUMNS (INT8_MAX - 4)
|
||||
#define TETRIS_BUCKET_MAX_ROWS
|
||||
|
||||
|
||||
/*********
|
||||
|
@ -85,7 +88,7 @@ tetris_bucket_iterator_t;
|
|||
/**
|
||||
* constructs a bucket with the given dimensions
|
||||
* @param nWidth width of bucket (4 <= n <= 16)
|
||||
* @param nHeight height of bucket (4 <= n <= 124)
|
||||
* @param nHeight height of bucket (4 <= n <= TETRIS_BUCKET_MAX_COLUMNS)
|
||||
* @return pointer to a newly created bucket
|
||||
*/
|
||||
tetris_bucket_t *tetris_bucket_construct(int8_t nWidth,
|
||||
|
@ -291,7 +294,7 @@ inline static tetris_bucket_status_t tetris_bucket_getStatus(tetris_bucket_t *p)
|
|||
/**
|
||||
* returns the given row of the dump (as bitmap)
|
||||
* @param pBucket the bucket we want information from
|
||||
* @param nRow the number of the row (0 <= nRow <= 124)
|
||||
* @param nRow the number of the row (0 <= nRow <= TETRIS_BUCKET_MAX_COLUMNS)
|
||||
* @return bitmap of the requested row (LSB is leftmost column)
|
||||
*/
|
||||
inline static uint16_t tetris_bucket_getDumpRow(tetris_bucket_t *pBucket,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include "../../config.h"
|
||||
#include "../../scrolltext/scrolltext.h"
|
||||
#include "../../joystick/joystick.h"
|
||||
|
@ -24,7 +25,7 @@ uint16_t tetris_highscore_inputName(void)
|
|||
while (1)
|
||||
{
|
||||
// we need our own blink interval
|
||||
nBlink = (nBlink + 1) % 4;
|
||||
nBlink = (nBlink + 1) % 4u;
|
||||
|
||||
// construct command for scrolltext and execute
|
||||
static uint8_t const nOffset[3] = {15, 19, 23};
|
||||
|
@ -100,42 +101,5 @@ uint16_t tetris_highscore_retrieveHighscore(tetris_highscore_index_t nIndex)
|
|||
eeprom_read_word(&tetris_highscore[nIndex]);
|
||||
|
||||
// a score of 65535 is most likely caused by uninitialized EEPROM addresses
|
||||
if (nHighscore == 65535)
|
||||
{
|
||||
nHighscore = 0;
|
||||
}
|
||||
|
||||
return nHighscore;
|
||||
}
|
||||
|
||||
|
||||
void tetris_highscore_saveHighscore(tetris_highscore_index_t nIndex,
|
||||
uint16_t nHighscore)
|
||||
{
|
||||
if (nHighscore > tetris_highscore_retrieveHighscore(nIndex))
|
||||
{
|
||||
eeprom_write_word(&tetris_highscore[nIndex], nHighscore);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint16_t tetris_highscore_retrieveHighscoreName(tetris_highscore_index_t nIdx)
|
||||
{
|
||||
uint16_t nHighscoreName =
|
||||
eeprom_read_word(&tetris_highscore_name[nIdx]);
|
||||
|
||||
// a value of 65535 is most likely caused by uninitialized EEPROM addresses
|
||||
if (nHighscoreName == 65535)
|
||||
{
|
||||
nHighscoreName = 0;
|
||||
}
|
||||
|
||||
return nHighscoreName;
|
||||
}
|
||||
|
||||
|
||||
void tetris_highscore_saveHighscoreName(tetris_highscore_index_t nIndex,
|
||||
uint16_t nHighscoreName)
|
||||
{
|
||||
eeprom_write_word(&tetris_highscore_name[nIndex], nHighscoreName);
|
||||
return nHighscore == UINT16_MAX ? 0 : nHighscore;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#define TETRIS_HIGHSCORE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../../compat/eeprom.h"
|
||||
|
||||
|
||||
/**
|
||||
* indexes for different tetris variants
|
||||
|
@ -20,6 +22,13 @@ enum tetris_highscore_index
|
|||
typedef enum tetris_highscore_index tetris_highscore_index_t;
|
||||
#endif
|
||||
|
||||
|
||||
// global array for the high score
|
||||
extern uint16_t tetris_highscore[TETRIS_HISCORE_END] EEMEM;
|
||||
// global array for the champion's initials
|
||||
extern uint16_t tetris_highscore_name[TETRIS_HISCORE_END] EEMEM;
|
||||
|
||||
|
||||
/**
|
||||
* lets the user enter his initials (three characters)
|
||||
* @return name packed into a uint16_t
|
||||
|
@ -37,11 +46,18 @@ uint16_t tetris_highscore_retrieveHighscore(tetris_highscore_index_t nIndex);
|
|||
|
||||
/**
|
||||
* saves the high score into the storage (EEPROM)
|
||||
* @param nIndex the variant dependent index of the high score
|
||||
* @param nIdx the variant dependent index of the high score
|
||||
* @param nHighscoreName the high score
|
||||
*/
|
||||
inline static
|
||||
void tetris_highscore_saveHighscore(tetris_highscore_index_t nIndex,
|
||||
uint16_t nHighscore);
|
||||
uint16_t nHighscore)
|
||||
{
|
||||
if (nHighscore > tetris_highscore_retrieveHighscore(nIndex))
|
||||
{
|
||||
eeprom_write_word(&tetris_highscore[nIndex], nHighscore);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -49,7 +65,14 @@ void tetris_highscore_saveHighscore(tetris_highscore_index_t nIndex,
|
|||
* @param nIdx the variant dependent index of the high score
|
||||
* @return the initials of the champion packed into a uint16_t
|
||||
*/
|
||||
uint16_t tetris_highscore_retrieveHighscoreName(tetris_highscore_index_t nIdx);
|
||||
inline static
|
||||
uint16_t tetris_highscore_retrieveHighscoreName(tetris_highscore_index_t nIdx)
|
||||
{
|
||||
uint16_t nHighscoreName =
|
||||
eeprom_read_word(&tetris_highscore_name[nIdx]);
|
||||
|
||||
return nHighscoreName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -57,7 +80,12 @@ uint16_t tetris_highscore_retrieveHighscoreName(tetris_highscore_index_t nIdx);
|
|||
* @param nIndex the variant dependent index of the high score
|
||||
* @param nHighscoreName the initials of the champion packed into a uint16_t
|
||||
*/
|
||||
inline static
|
||||
void tetris_highscore_saveHighscoreName(tetris_highscore_index_t nIndex,
|
||||
uint16_t nHighscoreName);
|
||||
uint16_t nHighscoreName)
|
||||
{
|
||||
eeprom_write_word(&tetris_highscore_name[nIndex], nHighscoreName);
|
||||
}
|
||||
|
||||
|
||||
#endif /*TETRIS_HIGHSCORE_H_*/
|
||||
|
|
|
@ -140,23 +140,11 @@ static void tetris_input_chatterProtect(tetris_input_t *pIn,
|
|||
* @return mapped tetris command
|
||||
* @see tetris_input_command_t
|
||||
*/
|
||||
static
|
||||
tetris_input_command_t tetris_input_mapCommand(tetris_bearing_t nBearing,
|
||||
tetris_input_command_t nCmd)
|
||||
{
|
||||
static tetris_input_command_t const nMapping[] PROGMEM =
|
||||
{
|
||||
TETRIS_INCMD_DOWN, TETRIS_INCMD_ROT_CW, TETRIS_INCMD_RIGHT,
|
||||
TETRIS_INCMD_LEFT,
|
||||
|
||||
TETRIS_INCMD_RIGHT, TETRIS_INCMD_LEFT, TETRIS_INCMD_ROT_CW,
|
||||
TETRIS_INCMD_DOWN,
|
||||
|
||||
TETRIS_INCMD_ROT_CW, TETRIS_INCMD_DOWN, TETRIS_INCMD_LEFT,
|
||||
TETRIS_INCMD_RIGHT
|
||||
};
|
||||
|
||||
return (nBearing == TETRIS_BEARING_0) || (nCmd >= TETRIS_INCMD_ROT_CCW) ?
|
||||
nCmd : (PM(nMapping[(nBearing - 1) * 4 + nCmd]));
|
||||
return (nCmd < TETRIS_INCMD_ROT_CCW) ? (nCmd - nBearing + 4) % 4u : nCmd;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -33,9 +33,9 @@
|
|||
*/
|
||||
enum tetris_input_command
|
||||
{
|
||||
TETRIS_INCMD_LEFT, /**< move piece left */
|
||||
TETRIS_INCMD_RIGHT, /**< move piece right */
|
||||
TETRIS_INCMD_DOWN, /**< lower piece by one row */
|
||||
TETRIS_INCMD_LEFT, /**< move piece left */
|
||||
TETRIS_INCMD_ROT_CW, /**< rotate clockwise */
|
||||
TETRIS_INCMD_ROT_CCW, /**< rotate counter clockwise */
|
||||
TETRIS_INCMD_DROP, /**< move piece to the ground immediately */
|
||||
|
@ -43,6 +43,13 @@ enum tetris_input_command
|
|||
TETRIS_INCMD_PAUSE, /**< pause the game */
|
||||
TETRIS_INCMD_NONE /**< idle (must alway be the last one) */
|
||||
};
|
||||
/* R D L C
|
||||
* RDLC 0 1 2 3
|
||||
* DLCR -1 -1 -1 -1
|
||||
* LCRD -2 -2 -2 -2
|
||||
* CRDL -3 -3 -3 -3
|
||||
*/
|
||||
|
||||
#ifdef NDEBUG
|
||||
typedef uint8_t tetris_input_command_t;
|
||||
#else
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include "../../random/prng.h"
|
||||
#include "../../compat/pgmspace.h"
|
||||
#include "../../menu/menu.h"
|
||||
|
@ -21,6 +22,12 @@
|
|||
|
||||
#define TETRIS_BASTET_HEIGHT_FACTOR 5
|
||||
|
||||
#ifdef RANDOM_SUPPORT
|
||||
#define RANDOM8() random8()
|
||||
#else
|
||||
#define RANDOM8() (rand() % (UINT8_MAX + 1))
|
||||
#endif
|
||||
|
||||
|
||||
/***************************
|
||||
* non-interface functions *
|
||||
|
@ -34,21 +41,18 @@
|
|||
static 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_getFirstTaintedRow(pBastet->pBucket);
|
||||
int8_t const nWidth = tetris_bucket_getWidth(pBastet->pBucket);
|
||||
int8_t const nStartRow = tetris_bucket_getHeight(pBastet->pBucket) - 1;
|
||||
int8_t const nStopRow = tetris_bucket_getFirstTaintedRow(pBastet->pBucket);
|
||||
|
||||
// clear old precalculated scores
|
||||
for (uint8_t i = 0; i < nWidth + 3; ++i)
|
||||
{
|
||||
pBastet->pColScore[i] = 0;
|
||||
}
|
||||
// clear old precalculated scores (last three elements are always 0)
|
||||
memset(pBastet->pColScore, 0, nWidth * sizeof(int16_t));
|
||||
// calculate the column heights of the actual bucket configuration
|
||||
// NOTE: in this loop, pColScore contains the actual column heights,
|
||||
// NOTE: in this loop, pColScore stores 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);
|
||||
uint16_t const nDumpRow = tetris_bucket_getDumpRow(pBastet->pBucket, y);
|
||||
uint16_t nColMask = 0x0001;
|
||||
for (uint8_t x = 0; x < nWidth; ++x)
|
||||
{
|
||||
|
@ -70,25 +74,21 @@ static void tetris_bastet_doPreprocessing(tetris_bastet_variant_t *pBastet)
|
|||
// calculate the maxima of the 4-tuples from column 0 to width-1
|
||||
for (uint8_t i = 0; i < nWidth; ++i)
|
||||
{
|
||||
// casting from int16_t to int8_t is safe here, since at this point
|
||||
// pColScore only contains column heights which never exceed INT8_MAX-4
|
||||
int8_t t0 = pBastet->pColScore[i] > pBastet->pColScore[i + 1] ?
|
||||
i : i + 1;
|
||||
pBastet->pColScore[i] : pBastet->pColScore[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];
|
||||
pBastet->pColScore[i + 2] : pBastet->pColScore[i + 3];
|
||||
pBastet->pStartingRow[i + 3] = t0 > t1 ? t0 : t1;
|
||||
}
|
||||
|
||||
// normalize to bucket geometry
|
||||
for (uint8_t i = 0; i < nWidth + 3; ++i)
|
||||
for (uint8_t i = nWidth + 3; i--;)
|
||||
{
|
||||
// normalize to bucket geometry
|
||||
pBastet->pStartingRow[i] = nStartRow - pBastet->pStartingRow[i];
|
||||
}
|
||||
|
||||
// calculate the score impact of every column
|
||||
for (uint8_t x = 0; x < nWidth; ++x)
|
||||
{
|
||||
pBastet->pColScore[x] *= TETRIS_BASTET_HEIGHT_FACTOR;
|
||||
// finally calculate the score impact of every column
|
||||
pBastet->pColScore[i] *= TETRIS_BASTET_HEIGHT_FACTOR;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -309,7 +309,7 @@ void *tetris_bastet_construct(tetris_bucket_t *pBucket)
|
|||
pBastet->pBucket = pBucket;
|
||||
|
||||
int8_t nWidth = tetris_bucket_getWidth(pBastet->pBucket);
|
||||
pBastet->pColScore = (uint16_t*) calloc(nWidth + 3, sizeof(uint16_t));
|
||||
pBastet->pColScore = (int16_t*) calloc(nWidth + 3, sizeof(int16_t));
|
||||
pBastet->pStartingRow = (int8_t*) calloc(nWidth + 3, sizeof(int8_t));
|
||||
pBastet->pColHeights = (int8_t*) calloc(nWidth, sizeof(int8_t));
|
||||
|
||||
|
@ -349,7 +349,7 @@ 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->nPieceScore[i].nScore += random8() % 5 - 2;
|
||||
pBastet->nPieceScore[i].nScore += RANDOM8() % 5 - 2;
|
||||
}
|
||||
|
||||
// sort pieces by their score in ascending order
|
||||
|
@ -366,7 +366,7 @@ tetris_piece_t* tetris_bastet_choosePiece(void *pVariantData)
|
|||
|
||||
tetris_piece_t *pPiece = NULL;
|
||||
uint8_t const nPercent[4] = {191, 235, 250, 255};
|
||||
uint8_t const nRnd = random8();
|
||||
uint8_t const nRnd = RANDOM8();
|
||||
for (uint8_t i = 0; i < 4; ++i)
|
||||
{
|
||||
if (nRnd <= nPercent[i])
|
||||
|
@ -503,7 +503,8 @@ tetris_highscore_index_t tetris_bastet_getHighscoreIndex(void *pVariantData)
|
|||
|
||||
|
||||
void tetris_bastet_setLastInput(void *pVariantData,
|
||||
tetris_input_command_t inCmd)
|
||||
tetris_input_command_t inCmd,
|
||||
uint8_t bMoveOk)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ typedef struct tetris_bastet_variant
|
|||
uint16_t nLines; /** number of completed lines */
|
||||
tetris_piece_t *pPreviewPiece; /** the piece for the preview */
|
||||
tetris_bucket_t *pBucket; /** bucket to be examined */
|
||||
uint16_t *pColScore; /** score impact of every column*/
|
||||
int16_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 */
|
||||
|
@ -192,12 +192,14 @@ tetris_highscore_index_t tetris_bastet_getHighscoreIndex(void *pVariantData);
|
|||
|
||||
|
||||
/**
|
||||
* informs the bastet instance about the player's last move
|
||||
* @param pVariantData the variant data object we want to modify
|
||||
* @param inCmd player's last command
|
||||
* inform the Bastet instance about the player's last input
|
||||
* @param pVariantData the Bastet object we want to modify
|
||||
* @param inCmd the last issued command
|
||||
* @param bMoveOk 1 if the last move was possible, otherwise 0
|
||||
*/
|
||||
void tetris_bastet_setLastInput(void *pVariantData,
|
||||
tetris_input_command_t inCmd);
|
||||
tetris_input_command_t inCmd,
|
||||
uint8_t bMoveOk);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,7 +33,14 @@ tetris_variant_t const tetrisFpVariant;
|
|||
tetris_highscore_index_t tetris_fp_getHighscoreIndex(void *pVariantData);
|
||||
|
||||
|
||||
/**
|
||||
* inform the First Person Tetris instance about the player's last input
|
||||
* @param pVariantData the First Person Tetris data object we want to modify
|
||||
* @param inCmd the last issued command
|
||||
* @param bMoveOk 1 if the last move was possible, otherwise 0
|
||||
*/
|
||||
void tetris_fp_setLastInput(void *pVariantData,
|
||||
tetris_input_command_t inCmd);
|
||||
tetris_input_command_t inCmd,
|
||||
uint8_t bMoveOk);
|
||||
|
||||
#endif /*VARIANT_FP_H_*/
|
||||
|
|
|
@ -16,6 +16,17 @@
|
|||
#include "variant_std.h"
|
||||
|
||||
|
||||
/***********
|
||||
* defines *
|
||||
***********/
|
||||
|
||||
#ifdef RANDOM_SUPPORT
|
||||
#define RANDOM8() random8()
|
||||
#else
|
||||
#define RANDOM8() rand()
|
||||
#endif
|
||||
|
||||
|
||||
/***************
|
||||
* entry point *
|
||||
***************/
|
||||
|
@ -74,8 +85,9 @@ void *tetris_std_construct(tetris_bucket_t *pBucket)
|
|||
malloc(sizeof(tetris_standard_variant_t));
|
||||
assert(pStdVariant != NULL);
|
||||
memset(pStdVariant, 0, sizeof(tetris_standard_variant_t));
|
||||
// don't begin with S and Z pieces according to official tetris guidelines
|
||||
pStdVariant->pPreviewPiece =
|
||||
tetris_piece_construct(random8() % 7, TETRIS_PC_ANGLE_0);
|
||||
tetris_piece_construct(RANDOM8() % 5, TETRIS_PC_ANGLE_0);
|
||||
|
||||
return pStdVariant;
|
||||
}
|
||||
|
@ -103,7 +115,7 @@ tetris_piece_t* tetris_std_choosePiece(void *pVariantData)
|
|||
(tetris_standard_variant_t *)pVariantData;
|
||||
tetris_piece_t *pPiece = pStdVariant->pPreviewPiece;
|
||||
pStdVariant->pPreviewPiece =
|
||||
tetris_piece_construct(random8() % 7, TETRIS_PC_ANGLE_0);
|
||||
tetris_piece_construct(RANDOM8() % 7, TETRIS_PC_ANGLE_0);
|
||||
return pPiece;
|
||||
}
|
||||
|
||||
|
@ -241,7 +253,8 @@ tetris_highscore_index_t tetris_std_getHighscoreIndex(void *pVariantData)
|
|||
|
||||
|
||||
void tetris_std_setLastInput(void *pVariantData,
|
||||
tetris_input_command_t inCmd)
|
||||
tetris_input_command_t inCmd,
|
||||
uint8_t bMoveOk)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -175,10 +175,22 @@ tetris_piece_t* tetris_std_getPreviewPiece(void *pVariantData);
|
|||
tetris_highscore_index_t tetris_std_getHighscoreIndex(void *pVariantData);
|
||||
|
||||
|
||||
/**
|
||||
* inform the Tetris instance about the player's last input
|
||||
* @param pVariantData the Tetris data object we want to modify
|
||||
* @param inCmd the last issued command
|
||||
* @param bMoveOk 1 if the last move was possible, otherwise 0
|
||||
*/
|
||||
void tetris_std_setLastInput(void *pVariantData,
|
||||
tetris_input_command_t inCmd);
|
||||
tetris_input_command_t inCmd,
|
||||
uint8_t bMoveOk);
|
||||
|
||||
|
||||
/**
|
||||
* returns the bearing which is requested by the Tetris instance
|
||||
* @param pVariantData the variant data object we want information from
|
||||
* @return always TETRIS_BEARING_0 as we don't change the bearing in Bastet
|
||||
*/
|
||||
tetris_bearing_t tetris_std_getBearing(void *pVariantData);
|
||||
|
||||
#endif /*VARIANT_STD_H_*/
|
||||
|
|
|
@ -134,9 +134,11 @@ typedef struct tetris_variant
|
|||
* inform the variant about the player's last input
|
||||
* @param pVariantData the variant data object we want to modify
|
||||
* @param inCmd the last issued command
|
||||
* @param bMoveOk 1 if the last move was possible, otherwise 0
|
||||
*/
|
||||
void (*setLastInput)(void *pVariantData,
|
||||
tetris_input_command_t inCmd);
|
||||
tetris_input_command_t inCmd,
|
||||
uint8_t bMoveOk);
|
||||
|
||||
/**
|
||||
* retrieves the variant's preferred bearing of the bucket
|
||||
|
|
Loading…
Reference in New Issue