squeezed 216 bytes

This commit is contained in:
Christian Kroll 2011-03-07 00:32:38 +00:00
parent 28848358dd
commit a8d2f7b47b
11 changed files with 125 additions and 98 deletions

View File

@ -2,6 +2,7 @@
#define BUCKET_H_ #define BUCKET_H_
#include <stdint.h> #include <stdint.h>
#include <limits.h>
#include "../../config.h" #include "../../config.h"
#include "piece.h" #include "piece.h"
@ -11,6 +12,8 @@
***********/ ***********/
#define TETRIS_BUCKET_INVALIDROW -4 #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 * constructs a bucket with the given dimensions
* @param nWidth width of bucket (4 <= n <= 16) * @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 * @return pointer to a newly created bucket
*/ */
tetris_bucket_t *tetris_bucket_construct(int8_t nWidth, 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) * returns the given row of the dump (as bitmap)
* @param pBucket the bucket we want information from * @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) * @return bitmap of the requested row (LSB is leftmost column)
*/ */
inline static uint16_t tetris_bucket_getDumpRow(tetris_bucket_t *pBucket, inline static uint16_t tetris_bucket_getDumpRow(tetris_bucket_t *pBucket,

View File

@ -1,6 +1,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <limits.h>
#include "../../config.h" #include "../../config.h"
#include "../../scrolltext/scrolltext.h" #include "../../scrolltext/scrolltext.h"
#include "../../joystick/joystick.h" #include "../../joystick/joystick.h"
@ -24,7 +25,7 @@ uint16_t tetris_highscore_inputName(void)
while (1) while (1)
{ {
// we need our own blink interval // we need our own blink interval
nBlink = (nBlink + 1) % 4; nBlink = (nBlink + 1) % 4u;
// construct command for scrolltext and execute // construct command for scrolltext and execute
static uint8_t const nOffset[3] = {15, 19, 23}; 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]); eeprom_read_word(&tetris_highscore[nIndex]);
// a score of 65535 is most likely caused by uninitialized EEPROM addresses // a score of 65535 is most likely caused by uninitialized EEPROM addresses
if (nHighscore == 65535) return nHighscore == UINT16_MAX ? 0 : nHighscore;
{
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);
} }

View File

@ -2,6 +2,8 @@
#define TETRIS_HIGHSCORE_H_ #define TETRIS_HIGHSCORE_H_
#include <stdint.h> #include <stdint.h>
#include "../../compat/eeprom.h"
/** /**
* indexes for different tetris variants * indexes for different tetris variants
@ -20,6 +22,13 @@ enum tetris_highscore_index
typedef enum tetris_highscore_index tetris_highscore_index_t; typedef enum tetris_highscore_index tetris_highscore_index_t;
#endif #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) * lets the user enter his initials (three characters)
* @return name packed into a uint16_t * @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) * 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 * @param nHighscoreName the high score
*/ */
inline static
void tetris_highscore_saveHighscore(tetris_highscore_index_t nIndex, 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 * @param nIdx the variant dependent index of the high score
* @return the initials of the champion packed into a uint16_t * @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 nIndex the variant dependent index of the high score
* @param nHighscoreName the initials of the champion packed into a uint16_t * @param nHighscoreName the initials of the champion packed into a uint16_t
*/ */
inline static
void tetris_highscore_saveHighscoreName(tetris_highscore_index_t nIndex, 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_*/ #endif /*TETRIS_HIGHSCORE_H_*/

View File

@ -140,23 +140,11 @@ static void tetris_input_chatterProtect(tetris_input_t *pIn,
* @return mapped tetris command * @return mapped tetris command
* @see tetris_input_command_t * @see tetris_input_command_t
*/ */
static
tetris_input_command_t tetris_input_mapCommand(tetris_bearing_t nBearing, tetris_input_command_t tetris_input_mapCommand(tetris_bearing_t nBearing,
tetris_input_command_t nCmd) tetris_input_command_t nCmd)
{ {
static tetris_input_command_t const nMapping[] PROGMEM = return (nCmd < TETRIS_INCMD_ROT_CCW) ? (nCmd - nBearing + 4) % 4u : nCmd;
{
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]));
} }

View File

@ -33,9 +33,9 @@
*/ */
enum tetris_input_command enum tetris_input_command
{ {
TETRIS_INCMD_LEFT, /**< move piece left */
TETRIS_INCMD_RIGHT, /**< move piece right */ TETRIS_INCMD_RIGHT, /**< move piece right */
TETRIS_INCMD_DOWN, /**< lower piece by one row */ TETRIS_INCMD_DOWN, /**< lower piece by one row */
TETRIS_INCMD_LEFT, /**< move piece left */
TETRIS_INCMD_ROT_CW, /**< rotate clockwise */ TETRIS_INCMD_ROT_CW, /**< rotate clockwise */
TETRIS_INCMD_ROT_CCW, /**< rotate counter clockwise */ TETRIS_INCMD_ROT_CCW, /**< rotate counter clockwise */
TETRIS_INCMD_DROP, /**< move piece to the ground immediately */ 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_PAUSE, /**< pause the game */
TETRIS_INCMD_NONE /**< idle (must alway be the last one) */ 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 #ifdef NDEBUG
typedef uint8_t tetris_input_command_t; typedef uint8_t tetris_input_command_t;
#else #else

View File

@ -2,6 +2,7 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <stdint.h> #include <stdint.h>
#include <limits.h>
#include "../../random/prng.h" #include "../../random/prng.h"
#include "../../compat/pgmspace.h" #include "../../compat/pgmspace.h"
#include "../../menu/menu.h" #include "../../menu/menu.h"
@ -21,6 +22,12 @@
#define TETRIS_BASTET_HEIGHT_FACTOR 5 #define TETRIS_BASTET_HEIGHT_FACTOR 5
#ifdef RANDOM_SUPPORT
#define RANDOM8() random8()
#else
#define RANDOM8() (rand() % (UINT8_MAX + 1))
#endif
/*************************** /***************************
* non-interface functions * * non-interface functions *
@ -34,21 +41,18 @@
static void tetris_bastet_doPreprocessing(tetris_bastet_variant_t *pBastet) static void tetris_bastet_doPreprocessing(tetris_bastet_variant_t *pBastet)
{ {
// retrieve sane start and stop values for the column and row indices // retrieve sane start and stop values for the column and row indices
int8_t nWidth = tetris_bucket_getWidth(pBastet->pBucket); int8_t const nWidth = tetris_bucket_getWidth(pBastet->pBucket);
int8_t nStartRow = tetris_bucket_getHeight(pBastet->pBucket) - 1; int8_t const nStartRow = tetris_bucket_getHeight(pBastet->pBucket) - 1;
int8_t nStopRow = tetris_bucket_getFirstTaintedRow(pBastet->pBucket); int8_t const nStopRow = tetris_bucket_getFirstTaintedRow(pBastet->pBucket);
// clear old precalculated scores // clear old precalculated scores (last three elements are always 0)
for (uint8_t i = 0; i < nWidth + 3; ++i) memset(pBastet->pColScore, 0, nWidth * sizeof(int16_t));
{
pBastet->pColScore[i] = 0;
}
// calculate the column heights of the actual bucket configuration // 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 // later it will contain the "score impact" of every unchanged column
for (int8_t y = nStartRow; y >= nStopRow; --y) 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; uint16_t nColMask = 0x0001;
for (uint8_t x = 0; x < nWidth; ++x) 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 // calculate the maxima of the 4-tuples from column 0 to width-1
for (uint8_t i = 0; i < nWidth; ++i) 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] ? 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] ? int8_t t1 = pBastet->pColScore[i + 2] > pBastet->pColScore[i + 3] ?
i + 2 : i + 3; pBastet->pColScore[i + 2] : pBastet->pColScore[i + 3];
pBastet->pStartingRow[i + 3] = pBastet->pStartingRow[i + 3] = t0 > t1 ? t0 : t1;
pBastet->pColScore[t0] > pBastet->pColScore[t1] ?
pBastet->pColScore[t0] : pBastet->pColScore[t1];
} }
// normalize to bucket geometry for (uint8_t i = nWidth + 3; i--;)
for (uint8_t i = 0; i < nWidth + 3; ++i)
{ {
// normalize to bucket geometry
pBastet->pStartingRow[i] = nStartRow - pBastet->pStartingRow[i]; pBastet->pStartingRow[i] = nStartRow - pBastet->pStartingRow[i];
} // finally calculate the score impact of every column
pBastet->pColScore[i] *= TETRIS_BASTET_HEIGHT_FACTOR;
// calculate the score impact of every column
for (uint8_t x = 0; x < nWidth; ++x)
{
pBastet->pColScore[x] *= TETRIS_BASTET_HEIGHT_FACTOR;
} }
} }
@ -309,7 +309,7 @@ void *tetris_bastet_construct(tetris_bucket_t *pBucket)
pBastet->pBucket = pBucket; pBastet->pBucket = pBucket;
int8_t nWidth = tetris_bucket_getWidth(pBastet->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->pStartingRow = (int8_t*) calloc(nWidth + 3, sizeof(int8_t));
pBastet->pColHeights = (int8_t*) calloc(nWidth, 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 // perturb score (-2 to +2) to avoid stupid tie handling
for (uint8_t i = 0; i < 7; ++i) 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 // 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; tetris_piece_t *pPiece = NULL;
uint8_t const nPercent[4] = {191, 235, 250, 255}; 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) for (uint8_t i = 0; i < 4; ++i)
{ {
if (nRnd <= nPercent[i]) if (nRnd <= nPercent[i])
@ -503,7 +503,8 @@ tetris_highscore_index_t tetris_bastet_getHighscoreIndex(void *pVariantData)
void tetris_bastet_setLastInput(void *pVariantData, void tetris_bastet_setLastInput(void *pVariantData,
tetris_input_command_t inCmd) tetris_input_command_t inCmd,
uint8_t bMoveOk)
{ {
return; return;
} }

View File

@ -40,7 +40,7 @@ typedef struct tetris_bastet_variant
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_bucket_t *pBucket; /** bucket to be examined */ 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 *pStartingRow; /** starting point for collision*/
int8_t *pColHeights; /** predicted column heights */ int8_t *pColHeights; /** predicted column heights */
tetris_bastet_scorepair_t nPieceScore[7]; /** score for every piece */ 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 * inform the Bastet instance about the player's last input
* @param pVariantData the variant data object we want to modify * @param pVariantData the Bastet object we want to modify
* @param inCmd player's last command * @param inCmd the last issued command
* @param bMoveOk 1 if the last move was possible, otherwise 0
*/ */
void tetris_bastet_setLastInput(void *pVariantData, void tetris_bastet_setLastInput(void *pVariantData,
tetris_input_command_t inCmd); tetris_input_command_t inCmd,
uint8_t bMoveOk);
/** /**

View File

@ -33,7 +33,14 @@ tetris_variant_t const tetrisFpVariant;
tetris_highscore_index_t tetris_fp_getHighscoreIndex(void *pVariantData); 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, void tetris_fp_setLastInput(void *pVariantData,
tetris_input_command_t inCmd); tetris_input_command_t inCmd,
uint8_t bMoveOk);
#endif /*VARIANT_FP_H_*/ #endif /*VARIANT_FP_H_*/

View File

@ -16,6 +16,17 @@
#include "variant_std.h" #include "variant_std.h"
/***********
* defines *
***********/
#ifdef RANDOM_SUPPORT
#define RANDOM8() random8()
#else
#define RANDOM8() rand()
#endif
/*************** /***************
* entry point * * entry point *
***************/ ***************/
@ -74,8 +85,9 @@ void *tetris_std_construct(tetris_bucket_t *pBucket)
malloc(sizeof(tetris_standard_variant_t)); malloc(sizeof(tetris_standard_variant_t));
assert(pStdVariant != NULL); assert(pStdVariant != NULL);
memset(pStdVariant, 0, sizeof(tetris_standard_variant_t)); memset(pStdVariant, 0, sizeof(tetris_standard_variant_t));
// don't begin with S and Z pieces according to official tetris guidelines
pStdVariant->pPreviewPiece = pStdVariant->pPreviewPiece =
tetris_piece_construct(random8() % 7, TETRIS_PC_ANGLE_0); tetris_piece_construct(RANDOM8() % 5, TETRIS_PC_ANGLE_0);
return pStdVariant; return pStdVariant;
} }
@ -103,7 +115,7 @@ tetris_piece_t* tetris_std_choosePiece(void *pVariantData)
(tetris_standard_variant_t *)pVariantData; (tetris_standard_variant_t *)pVariantData;
tetris_piece_t *pPiece = pStdVariant->pPreviewPiece; tetris_piece_t *pPiece = pStdVariant->pPreviewPiece;
pStdVariant->pPreviewPiece = pStdVariant->pPreviewPiece =
tetris_piece_construct(random8() % 7, TETRIS_PC_ANGLE_0); tetris_piece_construct(RANDOM8() % 7, TETRIS_PC_ANGLE_0);
return pPiece; return pPiece;
} }
@ -241,7 +253,8 @@ tetris_highscore_index_t tetris_std_getHighscoreIndex(void *pVariantData)
void tetris_std_setLastInput(void *pVariantData, void tetris_std_setLastInput(void *pVariantData,
tetris_input_command_t inCmd) tetris_input_command_t inCmd,
uint8_t bMoveOk)
{ {
} }

View File

@ -175,10 +175,22 @@ tetris_piece_t* tetris_std_getPreviewPiece(void *pVariantData);
tetris_highscore_index_t tetris_std_getHighscoreIndex(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, 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); tetris_bearing_t tetris_std_getBearing(void *pVariantData);
#endif /*VARIANT_STD_H_*/ #endif /*VARIANT_STD_H_*/

View File

@ -134,9 +134,11 @@ typedef struct tetris_variant
* inform the variant about the player's last input * inform the variant about the player's last input
* @param pVariantData the variant data object we want to modify * @param pVariantData the variant data object we want to modify
* @param inCmd the last issued command * @param inCmd the last issued command
* @param bMoveOk 1 if the last move was possible, otherwise 0
*/ */
void (*setLastInput)(void *pVariantData, 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 * retrieves the variant's preferred bearing of the bucket