#ifndef BUCKET_H_ #define BUCKET_H_ #include #include #include "../../config.h" #include "piece.h" /*********** * defines * ***********/ #define TETRIS_BUCKET_INVALIDROW -4 #define TETRIS_BUCKET_MAX_COLUMNS (INT8_MAX - 4) #define TETRIS_BUCKET_MAX_ROWS /********* * types * *********/ // directions to which a piece can be moved enum tetris_bucket_direction { TETRIS_BUD_LEFT = -1, TETRIS_BUD_RIGHT = 1 }; #ifdef NDEBUG typedef int8_t tetris_bucket_direction_t; #else typedef enum tetris_bucket_direction tetris_bucket_direction_t; #endif // status of the bucket enum tetris_bucket_status { TETRIS_BUS_HOVERING = 0, /** piece is hovering */ TETRIS_BUS_GLIDING = 1, /** piece is gliding on the dump */ TETRIS_BUS_DOCKED = 2, /** piece has been docked */ TETRIS_BUS_READY = 3, /** ready to get next piece */ TETRIS_BUS_GAMEOVER = 4 /** bucket is filled up */ }; #ifdef NDEBUG typedef uint8_t tetris_bucket_status_t; #else typedef enum tetris_bucket_status tetris_bucket_status_t; #endif // tetris_bucket_t typedef struct tetris_bucket { int8_t nWidth; /** width of bucket */ int8_t nHeight; /** height of bucket */ tetris_piece_t *pPiece; /** currently falling piece */ int8_t nColumn; /** horz. piece pos. (0 is left) */ int8_t nRow; /** vert. piece pos. (0 is top) */ uint8_t nRowMask; /** removed lines relative to nRow */ tetris_bucket_status_t status; /** status of the bucket */ int8_t nFirstTaintedRow; /** top most row which has matter */ uint16_t nFullRow; /** value of a full row */ uint16_t *dump; /** bucket itself */ } tetris_bucket_t; // iterator for predicted dump rows typedef struct tetris_bucket_iterator { tetris_bucket_t *pBucket; /** bucket to be examined */ uint16_t nPieceMap; /** piece bitmap */ int8_t nShift; /** helper variable for shifting piece bitmaps */ int8_t nCurrentRow; /** the actual row in the bucket */ int8_t nPieceTopRow; /** the highest row index of the piece */ int8_t nPieceBottomRow; /** the lowest row index of the piece */ int8_t nStopRow; /** the last row to be examined */ uint16_t nRowBuffer; /** buffer for returned row */ } tetris_bucket_iterator_t; /**************************** * construction/destruction * ****************************/ /** * constructs a bucket with the given dimensions * @param nWidth width of bucket (4 <= n <= 16) * @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, int8_t nHeight); /** * destructs a bucket * @param pBucket pointer to the bucket to be destructed */ inline static void tetris_bucket_destruct(tetris_bucket_t *pBucket) { assert(pBucket != NULL); assert(pBucket->dump != NULL); free(pBucket->dump); free(pBucket); } /******************************* * bucket related functions * *******************************/ /** * calculates number of lines for the given row mask * @param nRowMask row mask from which the no. of lines will be calculated * @return number of lines of the row mask */ inline static uint8_t tetris_bucket_calculateLines(uint8_t nRowMask) { uint8_t nLines = 0; if (nRowMask & 0x01) { ++nLines; } if (nRowMask & 0x02) { ++nLines; } if (nRowMask & 0x04) { ++nLines; } if (nRowMask & 0x08) { ++nLines; } return nLines; } /** * resets bucket to begin a new game * @param pBucket bucket to perform action on */ void tetris_bucket_reset(tetris_bucket_t *pBucket); /** * inserts a new piece * @param pBucket bucket to perform action on * @param pPiece piece to be inserted * @return pointer to former piece for deallocation */ tetris_piece_t *tetris_bucket_insertPiece(tetris_bucket_t *pBucket, tetris_piece_t *pPiece); /** * lowers piece by one row or finally docks it * @param pBucket bucket to perform action on */ void tetris_bucket_advancePiece(tetris_bucket_t *pBucket); /** * moves piece to the given direction * @param pBucket bucket to perform action on * @param direction direction (see tetris_bucket_direction_t) * @return 1 if piece could be moved, 0 otherwise */ uint8_t tetris_bucket_movePiece(tetris_bucket_t *pBucket, tetris_bucket_direction_t direction); /** * rotates piece to the given direction * @param pBucket bucket to perform action on * @param r type of rotation (see tetris_piece_rotation_t) * @return 1 if piece could be rotated, 0 otherwise */ uint8_t tetris_bucket_rotatePiece(tetris_bucket_t *pBucket, tetris_piece_rotation_t rotation); /** * removes completed lines (if any) and lowers the dump * @param pBucket bucket to perform action on */ void tetris_bucket_removeCompleteLines(tetris_bucket_t *pBucket); /***************** * get functions * *****************/ /** * returns the width of the bucket * @param pBucket the bucket we want information from * @return width of the bucket */ inline static int8_t tetris_bucket_getWidth(tetris_bucket_t *pBucket) { assert(pBucket != NULL); return pBucket->nWidth; } /** * returns the height of the bucket * @param pBucket the bucket we want information from * @return height of the bucket */ inline static int8_t tetris_bucket_getHeight(tetris_bucket_t *pBucket) { assert(pBucket != NULL); return pBucket->nHeight; } /** * returns the currently falling piece * @param pBucket the bucket we want information from * @return pointer to the currently falling piece */ inline static tetris_piece_t *tetris_bucket_getPiece(tetris_bucket_t *pBucket) { assert(pBucket != NULL); return pBucket->pPiece; } /** * returns the column of the currently falling piece * @param pBucket the bucket we want information from * @return column of the currently falling piece */ inline static int8_t tetris_bucket_getColumn(tetris_bucket_t *pBucket) { assert(pBucket != NULL); return pBucket->nColumn; } /** * returns the row of the currently falling piece * @param pBucket the bucket we want information from * @return row of the currently falling piece */ inline static int8_t tetris_bucket_getRow(tetris_bucket_t *pBucket) { assert(pBucket != NULL); return pBucket->nRow; } /** * returns the row of the currently falling piece * @param pBucket the bucket we want information from * @return highest row with matter */ inline static int8_t tetris_bucket_getFirstTaintedRow(tetris_bucket_t *pBucket) { assert(pBucket != NULL); return pBucket->nFirstTaintedRow; } /** * returns the row mask relative to nRow * @param pBucket the bucket we want information from * @return bit mask of removed lines (relative to current position) */ inline static uint8_t tetris_bucket_getRowMask(tetris_bucket_t *pBucket) { assert(pBucket != NULL); return pBucket->nRowMask; } /** * returns the status of the bucket * @param pBucket the bucket we want information from * @return status of the bucket (see tetris_bucket_status_t) */ inline static tetris_bucket_status_t tetris_bucket_getStatus(tetris_bucket_t *p) { assert(p != NULL); return p->status; } /** * 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 <= 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, int8_t nRow) { assert(pBucket != NULL); assert((0 <= nRow) && (nRow < pBucket->nHeight)); return pBucket->dump[nRow]; } #ifdef GAME_BASTET /** * returns the deepest possible row for a given piece * @param pBucket the bucket on which we want to test a piece * @param pPiece the piece which should be tested * @param nStartRow the row where the collision detection should start * @param nColumn the column where the piece should be dropped * @return the row of the piece (bucket compliant coordinates) */ int8_t tetris_bucket_predictDeepestRow(tetris_bucket_t *pBucket, tetris_piece_t *pPiece, int8_t nStartRow, int8_t nColumn); /** * predicts the number of complete lines for a piece at a given column * @param pBucket the bucket on which we want to test a piece * @param pPiece the piece which should be tested * @param nRow the row where the given piece collides * @param nColumn the column where the piece should be dropped * @return amount of complete lines */ int8_t tetris_bucket_predictCompleteLines(tetris_bucket_t *pBucket, tetris_piece_t *pPiece, int8_t nRow, int8_t nColumn); /** * predicts appearance of the bottom row and initializes an iterator structure * @param pIt a pointer to an iterator which should be initialized * @param pBucket the bucket on which we want to test a piece * @param pPiece the piece which should be tested * @param nRow the row where the given piece collides * @param nColumn the column where the piece should be dropped * @return appearance of the bottom row of the predicted dump (bit mask) */ uint16_t *tetris_bucket_predictBottomRow(tetris_bucket_iterator_t *pIt, tetris_bucket_t *pBucket, tetris_piece_t *pPiece, int8_t nRow, int8_t nColumn); /** * predicts appearance of the next row (via iterator) of the bucket * @param pIt a pointer to a dump iterator * @return appearance of next predicted row (or NULL -> no next line) */ uint16_t *tetris_bucket_predictNextRow(tetris_bucket_iterator_t *pIt); #endif /* GAME_BASTET */ #endif /*BUCKET_H_*/