synced with my personal Bastet tree
This commit is contained in:
parent
957457ef37
commit
903072815b
|
@ -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
|
||||||
|
|
|
@ -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,7 +141,6 @@ void display_loop(){
|
||||||
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case 42:
|
case 42:
|
||||||
mode = 1;
|
mode = 1;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,10 @@ TOPDIR = ../..
|
||||||
|
|
||||||
include $(TOPDIR)/defaults.mk
|
include $(TOPDIR)/defaults.mk
|
||||||
|
|
||||||
|
ifeq ($(GAME_BASTET),y)
|
||||||
SRC = piece.c playfield.c view.c logic.c input.c bast.c
|
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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
|
@ -8,16 +8,21 @@
|
||||||
#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
|
||||||
|
@ -28,17 +33,29 @@
|
||||||
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 };
|
||||||
|
game_descriptor_t tetris_game_descriptor
|
||||||
|
__attribute__((section(".game_descriptors"))) =
|
||||||
|
{
|
||||||
&tetris,
|
&tetris,
|
||||||
icon,
|
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 *
|
||||||
|
@ -131,6 +148,27 @@ void tetris_logic_destruct(tetris_logic_t *pLogic)
|
||||||
* 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;
|
||||||
|
#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_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,10 +232,30 @@ void tetris ()
|
||||||
{
|
{
|
||||||
// the playfield awaits a new piece
|
// the playfield awaits a new piece
|
||||||
case TETRIS_PFS_READY:
|
case TETRIS_PFS_READY:
|
||||||
|
#ifdef GAME_BASTET
|
||||||
|
if (nBastet)
|
||||||
|
{
|
||||||
|
if (pPiece != 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
|
// make preview piece the current piece and create new preview piece
|
||||||
pPiece = pNextPiece;
|
pPiece = pNextPiece;
|
||||||
pNextPiece =
|
pNextPiece = tetris_piece_construct(random8() % 7,
|
||||||
tetris_piece_construct(random8() % 7, TETRIS_PC_ANGLE_0);
|
TETRIS_PC_ANGLE_0);
|
||||||
tetris_logic_setPreviewPiece(pLogic, pNextPiece);
|
tetris_logic_setPreviewPiece(pLogic, pNextPiece);
|
||||||
|
|
||||||
// insert new piece into playfield
|
// insert new piece into playfield
|
||||||
|
@ -194,6 +268,9 @@ void tetris ()
|
||||||
tetris_piece_destruct(pOldPiece);
|
tetris_piece_destruct(pOldPiece);
|
||||||
pOldPiece = NULL;
|
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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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_*/
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
#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}, nColor);
|
||||||
setpixel((pixel){x, y + 11}, nColor);
|
setpixel((pixel){x, y + 11}, nColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -287,68 +290,38 @@ 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
|
// pick drawing color
|
||||||
x++;
|
uint8_t nOnesPen = nOnes > i ?
|
||||||
|
TETRIS_VIEW_COLORCOUNTER : TETRIS_VIEW_COLORSPACE;
|
||||||
//the square is just three pixels wide, start over in next column once the row is full
|
uint8_t nTensPen = nTens > i ?
|
||||||
if (x%4==0)
|
TETRIS_VIEW_COLORCOUNTER : TETRIS_VIEW_COLORSPACE;
|
||||||
|
// wrap lines if required
|
||||||
|
if ((x % 4) == 0)
|
||||||
{
|
{
|
||||||
y++;
|
y++;
|
||||||
x = 1;
|
x = 1;
|
||||||
}
|
}
|
||||||
setpixel((pixel){x,y}, nPen);
|
// ones
|
||||||
//only draw as many ones as there are, make the rest of the square dark.
|
setpixel((pixel){x, y}, nOnesPen);
|
||||||
if (i==ones) nPen=TETRIS_VIEW_COLORSPACE;
|
// tens (increment x, add vertical offset for lower part of the border)
|
||||||
|
setpixel((pixel){x++, y + 11}, nTensPen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//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
|
||||||
|
|
Loading…
Reference in New Issue