synced with my personal Bastet tree

This commit is contained in:
Christian Kroll 2009-12-27 02:11:58 +00:00
parent 957457ef37
commit 903072815b
12 changed files with 406 additions and 149 deletions

View File

@ -19,7 +19,7 @@ export HOSTCC
# flags for the compiler # flags for the compiler
CFLAGS ?= -Wall -W -Wno-unused-parameter -Wno-sign-compare CFLAGS ?= -Wall -W -Wno-unused-parameter -Wno-sign-compare
CFLAGS += -g -Os -std=gnu99 -fgnu89-inline CFLAGS += -g -Os -std=gnu99 -fgnu89-inline -DNDEBUG
# flags for the linker # flags for the linker
LDFLAGS += -T ./avr5.x -mmcu=$(MCU) LDFLAGS += -T ./avr5.x -mmcu=$(MCU)
@ -33,7 +33,7 @@ MACHINE = $(shell uname -m)
#$(info $(OSTYPE)) #$(info $(OSTYPE))
ifeq ($(OSTYPE),cygwin) ifeq ($(OSTYPE),cygwin)
CFLAGS_SIM = -g -Wall -pedantic -std=c99 -O2 -D_WIN32 -mno-cygwin CFLAGS_SIM = -g -Wall -pedantic -std=c99 -O0 -D_WIN32 -mno-cygwin
LDFLAGS_SIM = -Wl -mno-cygwin -T simulator/i386pe.x LDFLAGS_SIM = -Wl -mno-cygwin -T simulator/i386pe.x
LIBS_SIM = -lglut32 -lglu32 -lopengl32 LIBS_SIM = -lglut32 -lglu32 -lopengl32
else else

View File

@ -110,9 +110,9 @@ void display_loop(){
break; break;
#endif #endif
#ifdef ANIMATION_MHERWEG #ifdef ANIMATION_MHERWEG
case 11: case 11:
flydots();
lines1(); lines1();
dots1(); dots1();
movinglines(); movinglines();
@ -141,10 +141,9 @@ void display_loop(){
break; break;
#endif #endif
case 42: case 42:
mode = 1; mode = 1;
break; break;
#ifdef MENU_SUPPORT #ifdef MENU_SUPPORT
case 43: case 43:

View File

@ -2,6 +2,7 @@ mainmenu_option next_comment
comment "Games" comment "Games"
dep_bool "tetris" GAME_TETRIS $JOYSTICK_SUPPORT $RANDOM_SUPPORT dep_bool "tetris" GAME_TETRIS $JOYSTICK_SUPPORT $RANDOM_SUPPORT
dep_bool "bastet" GAME_BASTET $GAME_TETRIS
dep_bool "space invaders" GAME_SPACE_INVADERS $JOYSTICK_SUPPORT $RANDOM_SUPPORT dep_bool "space invaders" GAME_SPACE_INVADERS $JOYSTICK_SUPPORT $RANDOM_SUPPORT
dep_bool "snake" GAME_SNAKE $JOYSTICK_SUPPORT $RANDOM_SUPPORT dep_bool "snake" GAME_SNAKE $JOYSTICK_SUPPORT $RANDOM_SUPPORT

View File

@ -3,6 +3,10 @@ TOPDIR = ../..
include $(TOPDIR)/defaults.mk include $(TOPDIR)/defaults.mk
SRC = piece.c playfield.c view.c logic.c input.c bast.c ifeq ($(GAME_BASTET),y)
SRC = piece.c playfield.c view.c logic.c input.c bast.c
else
SRC = piece.c playfield.c view.c logic.c input.c
endif
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk

View File

@ -1,6 +1,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "../../random/prng.h"
#include "piece.h" #include "piece.h"
#include "playfield.h" #include "playfield.h"
#include "bast.h" #include "bast.h"
@ -13,18 +14,46 @@
/* Function: tetris_bastet_clearColHeights; /* Function: tetris_bastet_clearColHeights;
* Description: resets the array for the column heights * Description: resets the array for the column heights
* Argument pBastet: bastet instance whose array should be reset * Argument pBastet: bastet instance whose array should be reset
* Argument nStart: start index
* Argument nStop: stop index
* Return value: void * Return value: void
*/ */
void tetris_bastet_clearColHeights(tetris_bastet_t *pBastet) void tetris_bastet_clearColHeights(tetris_bastet_t *pBastet,
int8_t nStart,
int8_t nStop)
{ {
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield); for (int i = nStart; i <= nStop; ++i)
for (int i = 0; i < nWidth; ++i)
{ {
pBastet->pColHeights[i] = 0; pBastet->pColHeights[i] = 0;
} }
} }
/* Function: tetris_bastet_qsortCompare
* Description: compare function for quick sorting the pieces by score
* Argument pa: the first value to compare
* Argument pb: the second value to compare
* Return value: void
*/
int tetris_bastet_qsortCompare(const void *pa, const void *pb)
{
tetris_bastet_scorepair_t *pScoreA = (tetris_bastet_scorepair_t *)pa;
tetris_bastet_scorepair_t *pScoreB = (tetris_bastet_scorepair_t *)pb;
if (pScoreA->nScore == pScoreB->nScore)
{
return 0;
}
else if (pScoreA->nScore < pScoreB->nScore)
{
return -1;
}
else
{
return 1;
}
}
/**************************** /****************************
* construction/destruction * * construction/destruction *
****************************/ ****************************/
@ -43,7 +72,7 @@ tetris_bastet_t* tetris_bastet_construct(tetris_playfield_t *pPl)
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield); int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield);
pBastet->pColHeights = (int8_t*) calloc(nWidth, sizeof(int8_t)); pBastet->pColHeights = (int8_t*) calloc(nWidth, sizeof(int8_t));
tetris_bastet_clearColHeights(pBastet); tetris_bastet_clearColHeights(pBastet, 0, nWidth - 1);
return pBastet; return pBastet;
} }
@ -87,20 +116,46 @@ int16_t tetris_bastet_evalPos(tetris_bastet_t *pBastet,
pPiece, nColumn); pPiece, nColumn);
nScore += 5000 * nLines; nScore += 5000 * nLines;
// determine sane start and stop columns whose heights we want to calculate
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield);
int8_t nStartCol = ((nColumn - 1) < 0) ? 0 : nColumn - 1;
int8_t nStopCol;
// do we start at the left most position?
if (nColumn <= -3)
{
// in case we start at the left most position we calculate all heights
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 piece
else
{
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 // go through every row and calculate column heights
tetris_playfield_iterator_t iterator; tetris_playfield_iterator_t iterator;
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield);
int8_t nHeight = 1; int8_t nHeight = 1;
uint16_t *pDump = tetris_playfield_predictBottomRow(&iterator, uint16_t *pDump = tetris_playfield_predictBottomRow(&iterator,
pBastet->pPlayfield, pPiece, nColumn); pBastet->pPlayfield, pPiece, nColumn);
if (pDump == NULL)
{
// an immediately returned NULL is caused by a full dump -> low score
return -32766;
}
while (pDump != NULL) while (pDump != NULL)
{ {
for (int x = 0; x < nWidth; ++x) uint16_t nColMask = 0x0001 << nStartCol;
for (int x = nStartCol; x <= nStopCol; ++x)
{ {
if ((*pDump & (0x0001 << x)) != 0) if ((*pDump & nColMask) != 0)
{ {
pBastet->pColHeights[x] = nHeight; pBastet->pColHeights[x] = nHeight;
} }
nColMask <<= 1;
} }
pDump = tetris_playfield_predictNextRow(&iterator); pDump = tetris_playfield_predictNextRow(&iterator);
++nHeight; ++nHeight;
@ -111,8 +166,84 @@ int16_t tetris_bastet_evalPos(tetris_bastet_t *pBastet,
nScore -= 5 * pBastet->pColHeights[x]; nScore -= 5 * pBastet->pColHeights[x];
} }
// reset column height array for later use
tetris_bastet_clearColHeights(pBastet);
return nScore; return nScore;
} }
/* Function: tetris_bastet_minimax
* Description: calculates the best possible score for every piece
* Argument pBastet: the bastet instance of interest
* Return value: void
*/
void tetris_bastet_minimax(tetris_bastet_t *pBastet)
{
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield);
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_changeShape(pPiece, nBlock);
int8_t nAngleCount = tetris_piece_angleCount(pPiece);
for (int8_t nAngle = TETRIS_PC_ANGLE_0; nAngle < nAngleCount; ++nAngle)
{
tetris_piece_changeAngle(pPiece, nAngle);
for (int8_t nCol = -3; nCol < nWidth; ++nCol)
{
int16_t nScore = tetris_bastet_evalPos(pBastet, pPiece, nCol);
nMaxScore = nMaxScore > nScore ? nMaxScore : nScore;
}
}
pBastet->nPieceScores[nBlock].shape = nBlock;
pBastet->nPieceScores[nBlock].nScore = nMaxScore;
}
tetris_piece_destruct(pPiece);
}
/* Function: tetris_bastet_choosePiece
* Description: calculates the worst possible piece
* Argument pBastet: the bastet instance of interest
* Return value: the worst possible piece
*/
tetris_piece_t* tetris_bastet_choosePiece(tetris_bastet_t *pBastet)
{
const uint8_t nPercent[7] = {75, 92, 98, 100, 100, 100, 100};
tetris_bastet_minimax(pBastet);
// perturb score (-2 to +2) to avoid stupid tie handling
for (uint8_t i = 0; i < 7; ++i)
{
pBastet->nPieceScores[i].nScore += random8() % 5 - 2;
}
qsort(pBastet->nPieceScores, 7, sizeof(tetris_bastet_scorepair_t),
&tetris_bastet_qsortCompare);
uint8_t rnd = rand() % 100;
for (uint8_t i = 0; i < 7; i++)
{
if (rnd < nPercent[i])
{
return tetris_piece_construct(pBastet->nPieceScores[i].shape,
TETRIS_PC_ANGLE_0);
}
}
//should not arrive here
return tetris_piece_construct(pBastet->nPieceScores[0].shape,
TETRIS_PC_ANGLE_0);
}
/* Function: tetris_bastet_choosePreviewPiece
* Description: returns the best possible piece
* (run tetris_bastet_choosePiece first!)
* Argument pBastet: the bastet instance of interest
* Return value: the worst possible piece
*/
tetris_piece_t* tetris_bastet_choosePreviewPiece(tetris_bastet_t *pBastet)
{
return tetris_piece_construct(pBastet->nPieceScores[6].shape,
TETRIS_PC_ANGLE_0);
}

View File

@ -9,10 +9,19 @@
* types * * types *
*********/ *********/
typedef struct tetris_bastet_scorepair_t
{
tetris_piece_shape_t shape;
int16_t nScore;
}
tetris_bastet_scorepair_t;
typedef struct tetris_bastet_t typedef struct tetris_bastet_t
{ {
tetris_playfield_t *pPlayfield; // the playfield to be examined tetris_playfield_t *pPlayfield; // the playfield to be examined
int8_t *pColHeights; // array of calculated column heights int8_t *pColHeights; // array of calculated heights
tetris_bastet_scorepair_t nPieceScores[7]; // score for every piece
} }
tetris_bastet_t; tetris_bastet_t;
@ -52,4 +61,17 @@ int16_t tetris_bastet_evalPos(tetris_bastet_t *pBastet,
tetris_piece_t *pPiece, tetris_piece_t *pPiece,
int8_t nColumn); int8_t nColumn);
/* Function: tetris_bastet_minimax
* Description: calculates the best possible score for every piece
* Argument pBastet: the bastet instance of interest
* Return value: void
*/
void tetris_bastet_minimax();
tetris_piece_t* tetris_bastet_choosePiece(tetris_bastet_t *pBastet);
tetris_piece_t* tetris_bastet_choosePreviewPiece(tetris_bastet_t *pBastet);
#endif /* BAST_H_ */ #endif /* BAST_H_ */

View File

@ -8,37 +8,54 @@
#include <assert.h> #include <assert.h>
#include <inttypes.h> #include <inttypes.h>
#include "../../autoconf.h"
#include "../../compat/eeprom.h" #include "../../compat/eeprom.h"
#include "../../compat/pgmspace.h" #include "../../compat/pgmspace.h"
#include "../../menu/menu.h" #include "../../menu/menu.h"
#include "../../random/prng.h"
#include "logic.h" #include "logic.h"
#include "piece.h" #include "piece.h"
#include "playfield.h" #include "playfield.h"
#include "view.h" #include "view.h"
#include "input.h" #include "input.h"
#include "../../random/prng.h"
#ifdef GAME_BASTET
#include "bast.h"
#endif
#ifdef EEMEM #ifdef EEMEM
/*********************** /***********************
* Highscore in EEPROM * * Highscore in EEPROM *
***********************/ ***********************/
uint16_t tetris_logic_nHighscore EEMEM; uint16_t tetris_logic_nHighscore EEMEM;
#endif #endif
// MSB is leftmost pixel // Tetris icon, MSB is leftmost pixel
static uint8_t icon[8] PROGMEM =
{0x0f, 0x0f, 0xc3, 0xdb, 0xdb, 0xc3, 0xf0, 0xf0}; // Tetris icon
void tetris(); void tetris();
static uint8_t tetris_icon[8] PROGMEM =
game_descriptor_t tetris_game_descriptor __attribute__((section(".game_descriptors"))) ={ { 0x0f, 0x0f, 0xc3, 0xdb, 0xdb, 0xc3, 0xf0, 0xf0 };
&tetris, game_descriptor_t tetris_game_descriptor
icon, __attribute__((section(".game_descriptors"))) =
{
&tetris,
tetris_icon,
}; };
#ifdef GAME_BASTET
// Bastet icon, MSB is leftmost pixel
static uint8_t bastet_icon[8] PROGMEM =
{ 0x81, 0xc3, 0xff, 0x99, 0xff, 0xff, 0x66, 0x3c };
game_descriptor_t bastet_game_descriptor
__attribute__((section(".game_descriptors"))) =
{
&tetris_bastet,
bastet_icon,
};
#endif
/*************************** /***************************
* non-interface functions * * non-interface functions *
@ -104,7 +121,7 @@ void tetris_logic_saveHighscore(uint16_t nHighscore)
*/ */
tetris_logic_t *tetris_logic_construct() tetris_logic_t *tetris_logic_construct()
{ {
tetris_logic_t *pLogic = (tetris_logic_t *)malloc(sizeof(tetris_logic_t)); tetris_logic_t *pLogic = (tetris_logic_t *) malloc(sizeof(tetris_logic_t));
assert(pLogic != NULL); assert(pLogic != NULL);
memset(pLogic, 0, sizeof(tetris_logic_t)); memset(pLogic, 0, sizeof(tetris_logic_t));
return pLogic; return pLogic;
@ -130,7 +147,28 @@ void tetris_logic_destruct(tetris_logic_t *pLogic)
* Description: runs the tetris game * Description: runs the tetris game
* Return value: void * Return value: void
*/ */
void tetris () void tetris()
{
tetris_main(0);
}
/* Function: tetris_bastet
* Description: runs the bastet game
* Return value: void
*/
void tetris_bastet()
{
tetris_main(1);
}
/* Function: tetris_main
* Description: runs the tetris game
* Argument nBastet: 0 for normal Tetris, 1 for Bastet
* Return value: void
*/
void tetris_main(int8_t nBastet)
{ {
// get view dependent dimensions of the playfield // get view dependent dimensions of the playfield
int8_t nWidth; int8_t nWidth;
@ -145,6 +183,9 @@ void tetris ()
tetris_playfield_t *pPl = tetris_playfield_construct(nWidth, nHeight); tetris_playfield_t *pPl = tetris_playfield_construct(nWidth, nHeight);
tetris_input_t *pIn = tetris_input_construct(); tetris_input_t *pIn = tetris_input_construct();
tetris_view_t *pView = tetris_view_construct(pLogic, pPl); tetris_view_t *pView = tetris_view_construct(pLogic, pPl);
#ifdef GAME_BASTET
tetris_bastet_t *pBastet;
#endif
// runtime variable // runtime variable
int8_t nPieceRow; int8_t nPieceRow;
@ -157,15 +198,28 @@ void tetris ()
} }
// initialize current and next piece // initialize current and next piece
tetris_piece_t *pPiece = NULL; tetris_piece_t *pPiece;
tetris_piece_t *pNextPiece = pPiece = tetris_piece_t *pNextPiece;
tetris_piece_construct(random8() % 7, TETRIS_PC_ANGLE_0); #ifdef GAME_BASTET
if (nBastet)
{
pBastet = tetris_bastet_construct(pPl);
pNextPiece = pPiece = NULL;
}
else
{
#endif
pNextPiece = pPiece =
tetris_piece_construct(random8() % 7, TETRIS_PC_ANGLE_0);
tetris_logic_setPreviewPiece(pLogic, pNextPiece);
#ifdef GAME_BASTET
}
#endif
// the view only monitors the logic and the playfield object for the game // the view only monitors the logic and the playfield object for the game
// status so we must put information like the next piece or the current // status so we must put information like the next piece or the current
// highscore to a place where the view can find it // highscore to a place where the view can find it
tetris_logic_setHighscore(pLogic, nHighscore); tetris_logic_setHighscore(pLogic, nHighscore);
tetris_logic_setPreviewPiece(pLogic, pNextPiece);
// pace flag // pace flag
tetris_input_pace_t inPace; tetris_input_pace_t inPace;
@ -178,22 +232,45 @@ void tetris ()
{ {
// the playfield awaits a new piece // the playfield awaits a new piece
case TETRIS_PFS_READY: case TETRIS_PFS_READY:
// make preview piece the current piece and create new preview piece #ifdef GAME_BASTET
pPiece = pNextPiece; if (nBastet)
pNextPiece =
tetris_piece_construct(random8() % 7, TETRIS_PC_ANGLE_0);
tetris_logic_setPreviewPiece(pLogic, pNextPiece);
// insert new piece into playfield
tetris_piece_t *pOldPiece;
tetris_playfield_insertPiece(pPl, pPiece, &pOldPiece);
// destruct old piece (if it exists) since we don't need it anymore
if (pOldPiece != NULL)
{ {
tetris_piece_destruct(pOldPiece); if (pPiece != NULL)
pOldPiece = NULL; {
tetris_piece_destruct(pPiece);
}
if (pNextPiece != NULL)
{
tetris_piece_destruct(pNextPiece);
}
pPiece = tetris_bastet_choosePiece(pBastet);
pNextPiece = tetris_bastet_choosePreviewPiece(pBastet);
tetris_piece_t *pOldPiece;
tetris_playfield_insertPiece(pPl, pPiece, &pOldPiece);
tetris_logic_setPreviewPiece(pLogic, pNextPiece);
} }
else
{
#endif
// make preview piece the current piece and create new preview piece
pPiece = pNextPiece;
pNextPiece = tetris_piece_construct(random8() % 7,
TETRIS_PC_ANGLE_0);
tetris_logic_setPreviewPiece(pLogic, pNextPiece);
// insert new piece into playfield
tetris_piece_t *pOldPiece;
tetris_playfield_insertPiece(pPl, pPiece, &pOldPiece);
// destruct old piece (if it exists) since we don't need it anymore
if (pOldPiece != NULL)
{
tetris_piece_destruct(pOldPiece);
pOldPiece = NULL;
}
#ifdef GAME_BASTET
}
#endif
break; break;
// a piece is hovering and can be controlled by the player // a piece is hovering and can be controlled by the player
@ -296,7 +373,6 @@ void tetris ()
// and whether the level gets changed // and whether the level gets changed
tetris_logic_removedLines(pLogic, tetris_playfield_getRowMask(pPl)); tetris_logic_removedLines(pLogic, tetris_playfield_getRowMask(pPl));
tetris_input_setLevel(pIn, tetris_logic_getLevel(pLogic)); tetris_input_setLevel(pIn, tetris_logic_getLevel(pLogic));
break; break;
// avoid compiler warnings // avoid compiler warnings
@ -320,6 +396,12 @@ void tetris ()
} }
// clean up // clean up
#ifdef GAME_BASTET
if (nBastet)
{
tetris_bastet_destruct(pBastet);
}
#endif
tetris_view_destruct(pView); tetris_view_destruct(pView);
tetris_input_destruct(pIn); tetris_input_destruct(pIn);
tetris_playfield_destruct(pPl); tetris_playfield_destruct(pPl);
@ -374,18 +456,18 @@ void tetris_logic_removedLines(tetris_logic_t *pLogic,
switch (nLines) switch (nLines)
{ {
case 1: case 1:
pLogic->nScore += 50; pLogic->nScore += 50;
break; break;
case 2: case 2:
pLogic->nScore += 150; pLogic->nScore += 150;
break; break;
case 3: case 3:
pLogic->nScore += 250; pLogic->nScore += 250;
break; break;
case 4: case 4:
pLogic->nScore += 400; pLogic->nScore += 400;
break; break;
} }
} }

View File

@ -46,6 +46,20 @@ void tetris_logic_destruct(tetris_logic_t *pLogic);
void tetris(); void tetris();
/* Function: tetris_bastet
* Description: runs the bastet game
* Return value: void
*/
void tetris_bastet();
/* Function: tetris_main
* Description: runs the tetris game
* Argument nBastet: 0 for normal Tetris, 1 for Bastet
* Return value: void
*/
void tetris_main(int8_t nBastet);
/* Function: tetris_logic_singleDrop /* Function: tetris_logic_singleDrop
* Description: add points which result from single step dropping * Description: add points which result from single step dropping
* Argument pLogic: the logic object we want to modify * Argument pLogic: the logic object we want to modify

View File

@ -2,9 +2,9 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <inttypes.h> #include <inttypes.h>
#include "../../autoconf.h"
#include "playfield.h" #include "playfield.h"
#include "piece.h" #include "piece.h"
#include "bast.h"
/*************************** /***************************
@ -58,6 +58,7 @@ tetris_playfield_t *tetris_playfield_construct(int8_t nWidth,
if (pPlayfield->dump != NULL) if (pPlayfield->dump != NULL)
{ {
// setting desired attributes // setting desired attributes
pPlayfield->nFirstMatterRow = nHeight - 1;
pPlayfield->nWidth = nWidth; pPlayfield->nWidth = nWidth;
pPlayfield->nHeight = nHeight; pPlayfield->nHeight = nHeight;
tetris_playfield_reset(pPlayfield); tetris_playfield_reset(pPlayfield);
@ -336,6 +337,20 @@ void tetris_playfield_advancePiece(tetris_playfield_t *pPl)
pPl->dump[i] |= nPieceMap; pPl->dump[i] |= nPieceMap;
} }
// update value for the highest row with matter
int8_t nPieceRow = pPl->nRow;
uint16_t nMask = 0x000F;
for (int i = 0; i < 4; ++i, nMask <<= 4)
{
if ((nMask & nPiece) != 0)
{
nPieceRow += i;
break;
}
}
pPl->nFirstMatterRow = (pPl->nFirstMatterRow > nPieceRow) ?
nPieceRow : pPl->nFirstMatterRow;
// the piece has finally been docked // the piece has finally been docked
pPl->status = TETRIS_PFS_DOCKED; pPl->status = TETRIS_PFS_DOCKED;
} }
@ -456,6 +471,9 @@ void tetris_playfield_removeCompleteLines(tetris_playfield_t *pPl)
// is current row a full row? // is current row a full row?
if ((nFullRow & pPl->dump[i]) == nFullRow) if ((nFullRow & pPl->dump[i]) == nFullRow)
{ {
// adjust value for the highest row with matter
pPl->nFirstMatterRow++;
// set corresponding bit for the row mask // set corresponding bit for the row mask
// nRowMask |= 0x08 >> (nStartRow - i); // nRowMask |= 0x08 >> (nStartRow - i);
nRowMask |= 0x01 << (i - pPl->nRow); nRowMask |= 0x01 << (i - pPl->nRow);
@ -602,6 +620,9 @@ uint16_t tetris_playfield_getDumpRow(tetris_playfield_t *pPl,
return pPl->dump[nRow]; return pPl->dump[nRow];
} }
#ifdef GAME_BASTET
/* Function: tetris_playfield_predictDeepestRow /* Function: tetris_playfield_predictDeepestRow
* Description: returns the deepest possible row of a given piece * Description: returns the deepest possible row of a given piece
* Argument pPl: the playfield on which we want to test a piece * Argument pPl: the playfield on which we want to test a piece
@ -621,10 +642,14 @@ int8_t tetris_playfield_predictDeepestRow(tetris_playfield_t *pPl,
if (tetris_playfield_collision(pPl, (pPl->nWidth - 2) / 2, nRow) || if (tetris_playfield_collision(pPl, (pPl->nWidth - 2) / 2, nRow) ||
(tetris_playfield_collision(pPl, nColumn, nRow))) (tetris_playfield_collision(pPl, nColumn, nRow)))
{ {
// restore real piece
pPl->pPiece = pActualPiece;
return -4; return -4;
} }
// determine deepest row // determine deepest row
nRow = (nRow < pPl->nFirstMatterRow - 4) ? pPl->nFirstMatterRow - 4 : nRow;
while ((nRow < pPl->nHeight) && while ((nRow < pPl->nHeight) &&
(!tetris_playfield_collision(pPl, nColumn, nRow + 1))) (!tetris_playfield_collision(pPl, nColumn, nRow + 1)))
{ {
@ -777,3 +802,5 @@ uint16_t* tetris_playfield_predictNextRow(tetris_playfield_iterator_t *pIt)
return NULL; return NULL;
} }
} }
#endif /* GAME_BASTET */

View File

@ -2,6 +2,7 @@
#define TETRIS_PLAYFIELD_H_ #define TETRIS_PLAYFIELD_H_
#include <inttypes.h> #include <inttypes.h>
#include "../../autoconf.h"
#include "piece.h" #include "piece.h"
@ -40,6 +41,7 @@ typedef struct tetris_playfield_t
int8_t nRow; // vert. piece pos. (0 is top) int8_t nRow; // vert. piece pos. (0 is top)
uint8_t nRowMask; // removed lines relative to nRow (bitmap) uint8_t nRowMask; // removed lines relative to nRow (bitmap)
tetris_playfield_status_t status; // status tetris_playfield_status_t status; // status
int8_t nFirstMatterRow; // first row (from top) which contains matter
uint16_t *dump; // playfield itself uint16_t *dump; // playfield itself
} }
tetris_playfield_t; tetris_playfield_t;
@ -223,6 +225,8 @@ uint16_t tetris_playfield_getDumpRow(tetris_playfield_t *pPl,
int8_t nRow); int8_t nRow);
#ifdef GAME_BASTET
/* Function: tetris_playfield_predictDeepestRow /* Function: tetris_playfield_predictDeepestRow
* Description: returns the deepest possible row of a given piece * Description: returns the deepest possible row of a given piece
* Argument pPl: the playfield on which we want to test a piece * Argument pPl: the playfield on which we want to test a piece
@ -287,6 +291,6 @@ uint16_t* tetris_playfield_predictBottomRow(tetris_playfield_iterator_t *pIt,
*/ */
uint16_t* tetris_playfield_predictNextRow(tetris_playfield_iterator_t *pIt); uint16_t* tetris_playfield_predictNextRow(tetris_playfield_iterator_t *pIt);
#endif /* GAME_BASTET */
#endif /*TETRIS_PLAYFIELD_H_*/ #endif /*TETRIS_PLAYFIELD_H_*/

View File

@ -30,10 +30,12 @@
#define TETRIS_VIEW_LINE_BLINK_DELAY 75 #define TETRIS_VIEW_LINE_BLINK_DELAY 75
// colors of game elements // colors of game elements
#define TETRIS_VIEW_COLORSPACE 0 #define TETRIS_VIEW_COLORSPACE 0
#define TETRIS_VIEW_COLORBORDER 1 #define TETRIS_VIEW_COLORBORDER 1
#define TETRIS_VIEW_COLORFADE 2 #define TETRIS_VIEW_COLORFADE 2
#define TETRIS_VIEW_COLORPIECE 3 #define TETRIS_VIEW_COLORPIECE 3
#define TETRIS_VIEW_COLORPAUSE 1
#define TETRIS_VIEW_COLORCOUNTER 2
/*************************** /***************************
@ -53,7 +55,7 @@ uint8_t tetris_view_getPieceColor (tetris_view_t *pV)
} }
else else
{ {
return TETRIS_VIEW_COLORBORDER; return TETRIS_VIEW_COLORPAUSE;
} }
} }
@ -207,17 +209,18 @@ void tetris_view_drawBorders(uint8_t nColor)
setpixel((pixel){4, y}, nColor); setpixel((pixel){4, y}, nColor);
setpixel((pixel){15, y}, nColor); setpixel((pixel){15, y}, nColor);
} }
for (y = 0; y < 5; ++y) for (y = 0; y < 5; ++y)
{ {
for (x = 0; x <= 3; ++x){ for (x = 0; x <= 3; ++x)
{
if ((y<1 || y>3) || (x<1 || y>3)){ if ((y < 1 || y > 3) || (x < 1 || y > 3))
setpixel((pixel){x, y}, nColor); {
setpixel((pixel){x, y + 11}, nColor); setpixel((pixel){x, y}, nColor);
} setpixel((pixel){x, y + 11}, nColor);
}
} }
} }
} }
@ -287,69 +290,39 @@ void tetris_view_blinkLines(tetris_playfield_t *pPl)
/* Function: tetris_view_showLineNumbers /* Function: tetris_view_showLineNumbers
* Description: displays completed Lines (0-99) * Description: displays completed Lines (0-99)
* Argmument pV: pointer to the view * Argmument pV: pointer to the view
* Argument nColor: color
* Return value: void * Return value: void
*/ */
void tetris_view_showLineNumbers (tetris_view_t *pV, uint8_t nColor) void tetris_view_showLineNumbers(tetris_view_t *pV)
{ {
//Get number of completed lines // get number of completed lines
uint8_t Lines = tetris_logic_getLines(pV->pLogic); uint8_t nLines = tetris_logic_getLines(pV->pLogic);
uint8_t nPen;
int x=0, y=0, i; // get decimal places
int ones, tens; int8_t nOnes = nLines % 10;
int8_t nTens = (nLines / 10) % 10;
ones= Lines%10; // draws the decimal places as 3x3 squares with 9 pixels
tens=(Lines/10)%10; for (int i = 0, x = 1, y = 1; i < 9; ++i)
//pick drawing color, dark if ones=0, faded otherwise (bright counter gets confused with piece preview)
if ((ones%10)!=0)
nPen=TETRIS_VIEW_COLORFADE;
else nPen=TETRIS_VIEW_COLORSPACE;
//Draws ones in the upper part of the border as a 3x3 square with 0-9 pixels
//Start at column 1
y=1;
for (i=1;i<=9;i++)
{
//Start at line 1, increase every loop cycle
x++;
//the square is just three pixels wide, start over in next column once the row is full
if (x%4==0)
{ {
y++; // pick drawing color
x=1; uint8_t nOnesPen = nOnes > i ?
TETRIS_VIEW_COLORCOUNTER : TETRIS_VIEW_COLORSPACE;
uint8_t nTensPen = nTens > i ?
TETRIS_VIEW_COLORCOUNTER : TETRIS_VIEW_COLORSPACE;
// wrap lines if required
if ((x % 4) == 0)
{
y++;
x = 1;
}
// ones
setpixel((pixel){x, y}, nOnesPen);
// tens (increment x, add vertical offset for lower part of the border)
setpixel((pixel){x++, y + 11}, nTensPen);
} }
setpixel((pixel){x,y}, nPen);
//only draw as many ones as there are, make the rest of the square dark.
if (i==ones) nPen=TETRIS_VIEW_COLORSPACE;
}
//back to normal color, but only if tens is not divisible by 10
if ((tens%10)!=0)
nPen=TETRIS_VIEW_COLORFADE;
else nPen=TETRIS_VIEW_COLORSPACE;
//Draws ones in the lower part of the border as a 3x3 square with 0-9 pixels
x=0;
y=12; //offset for lower part of the border
for (i=1;i<=9;i++)
{
x++; //Start at line 1, increase every loop cycle
//the square is just three pixels wide, start over in next column once the row is full
if (x%4==0)
{
y++;
x=1;
}
setpixel((pixel){x,y}, nPen);
//only draw as many ones as there are, make the rest of the square dark.
if (i==tens) nPen=TETRIS_VIEW_COLORSPACE;
}
} }
/**************************** /****************************
* construction/destruction * * construction/destruction *
****************************/ ****************************/
@ -441,7 +414,7 @@ void tetris_view_update(tetris_view_t *pV)
if (tetris_playfield_getRowMask(pV->pPl) != 0) if (tetris_playfield_getRowMask(pV->pPl) != 0)
{ {
tetris_view_blinkLines(pV->pPl); tetris_view_blinkLines(pV->pPl);
tetris_view_showLineNumbers(pV, TETRIS_VIEW_COLORPIECE); tetris_view_showLineNumbers(pV);
} }
// draw preview piece // draw preview piece