Tetris game for mbed.
Dependencies: 4DGL-uLCD-SE SDFileSystem mbed-rtos mbed wave_player
Fork of HelloWorld by
Diff: tetris.cpp
- Revision:
- 2:36cda8980746
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tetris.cpp Mon Nov 07 00:43:45 2016 +0000 @@ -0,0 +1,542 @@ +#include <stdlib.h> +#include <time.h> +#include "tetris.h" +#include "uLCD_4DGL.h" +#include "rtos.h" +#include "mbed.h" + +uLCD_4DGL uLCD(p28,p27,p29); // serial tx, serial rx, reset pin; +Mutex lcd_mutex; + +Block::Block(){ + srand(time(NULL)); + block = block_list[rand() % SET_SIZE]; + offset = DIMX / 2; + height = DIMZ - 5; +} + +Block::Block(short ind){ + block = block_list[ind]; + offset = DIMX / 2; + height = DIMZ - 5; +} + +Block::Block(short ind, short offs, short h){ + block = block_list[ind]; + offset = offs; + height = h; +} + +unsigned long long Block::getFace(int n){ + unsigned long long rv = 0; + unsigned int lower = block&0xFFFFFFFFULL; + unsigned int upper = (block>>32); + switch(n){ + case 0: + rv = lower&FACE0; + break; + case 1: + rv = (lower>>16)&FACE0;//shift(block,-16)&FACE0; + break; + case 2: + rv = (upper)&FACE0;//shift(block,-16)&FACE0; + break; + case 3: + rv = (upper>>16)&FACE0;//shift(block,-16)&FACE0; + break; + default: + rv = 0; + } + return rv; + +} + +unsigned long long Block::getLine(int n){ + unsigned long long rv = 0; + unsigned int lower = block&0xFFFFFFFFULL; + unsigned int upper = (block>>32); + switch(n){ + case 0: + rv = (lower&LINE0) | ((upper&LINE0)<<32); + break; + case 1: + lower = lower >>4; + upper = upper >>4; + rv = (lower&LINE0) | ((upper&LINE0)<<32); + break; + case 2: + lower = lower >>8; + upper = upper >>8; + rv = (lower&LINE0) | ((upper&LINE0)<<32); + break; + case 3: + lower = lower >>12; + upper = upper >>12; + rv = (lower&LINE0) | ((upper&LINE0)<<32); + break; + default: + rv = 0; + } + return rv; + + +} + +unsigned long long Block::getFaceLine(int f, int l){ + unsigned long long face = getFace(f); + unsigned long long rv = 0; + switch(l){ + case 0: + rv = (face&0x000F); + break; + case 1: + rv = (face&0x00F0)>>4; + break; + case 2: + rv = (face&0x0F00)>>8; + break; + case 3: + rv = (face&0xF000)>>12; + break; + default: + rv = 0; + } + return rv; +} +void Block::rotY(){ + unsigned long long temp = block; + block = ((temp&0x0001000100010001ULL)<<3)|((temp&0x0002000200020002ULL)<<6)| + ((temp&0x0004000400040004ULL)<<9)|((temp&0x0008000800080008ULL)<<12)| + ((temp&0x0010001000100010ULL)>>2)|((temp&0x0020002000200020ULL)<<1)| + ((temp&0x0040004000400040ULL)<<4)|((temp&0x0080008000800080ULL)<<7)| + ((temp&0x0100010001000100ULL)>>7)|((temp&0x0200020002000200ULL)>>4)| + ((temp&0x0400040004000400ULL)>>1)|((temp&0x0800080008000800ULL)<<2)| + ((temp&0x1000100010001000ULL)>>12)|((temp&0x2000200020002000ULL)>>9)| + ((temp&0x4000400040004000ULL)>>6)|((temp&0x8000800080008000ULL)>>3); +} +void Block::rotZ(){ + unsigned long long temp = block; + block = ((temp&0x0000000000001111ULL)<<3) |((temp&0x0000000000002222ULL)<<18)| + ((temp&0x0000000000004444ULL)<<33)|((temp&0x0000000000008888ULL)<<48)| + ((temp&0x0000000011110000ULL)>>14)|((temp&0x0000000022220000ULL)<<1) | + ((temp&0x0000000044440000ULL)<<16)|((temp&0x0000000088880000ULL)<<31)| + ((temp&0x0000111100000000ULL)>>31)|((temp&0x0000222200000000ULL)>>16)| + ((temp&0x0000444400000000ULL)>>1) |((temp&0x0000888800000000ULL)<<14)| + ((temp&0x1111000000000000ULL)>>48)|((temp&0x2222000000000000ULL)>>33)| + ((temp&0x4444000000000000ULL)>>18)|((temp&0x8888000000000000ULL)>>3); +} +void Block::rotX(){ + unsigned long long temp = block; + block = ((temp&0x000000000000000FULL)<<12)|((temp&0x00000000000000F0ULL)<<24)| + ((temp&0x0000000000000F00ULL)<<36)|((temp&0x000000000000F000ULL)<<48)| + ((temp&0x00000000000F0000ULL)>>8)| ((temp&0x0000000000F00000ULL)<<4)| + ((temp&0x000000000F000000ULL)<<16)|((temp&0x00000000F0000000ULL)<<28)| + ((temp&0x0000000F00000000ULL)>>28)|((temp&0x000000F000000000ULL)>>16)| + ((temp&0x00000F0000000000ULL)>>4) |((temp&0x0000F00000000000ULL)<<8)| + ((temp&0x000F000000000000ULL)>>48)|((temp&0x00F0000000000000ULL)>>36)| + ((temp&0x0F00000000000000ULL)>>24)|((temp&0xF000000000000000ULL)>>12); +} +void Block::movR(){ + offset++; + //if (offset >= DIMX) offset = 0; +} + +void Block::movL(){ + offset--; + if (offset <-3) offset = -3; +} + +void Block::movB(){ + unsigned long long temp = block; + block = ((temp&0x0000FFFFFFFFFFFFULL)<<16)|((temp&0xFFFF000000000000ULL)>>48); +} + +void Block::movF(){ + unsigned long long temp = block; + block = ((temp&0xFFFFFFFFFFFF0000ULL)>>16)|((temp&0x000000000000FFFFULL)<<48); +} + +void Block::movU(){ + height++; +} + +void Block::movD(){ + height--; + //if (height<-3) height = -3; +} + + + +Board::Board(){ + nextBlock.offset = activeBlock.offset; + nextBlock.height = activeBlock.height; + nextBlock.block = activeBlock.block; + int i; + for (i = 0; i<4; i++) line[i] = 0xFFFFFFFFFFFFFFFFULL; + for (i = 4; i<DIMZ+4; i++) line[i] = 0xF807F807F807F807ULL; + score = 0; +} + +int Board::check(){ + //Check next block with board lines. + //Returns 0 when a collision (illegal state) is detected. + //Returns 1 when move is legal. + int invalid = 0; + int f = 0; + int l = 0; + if (nextBlock.height >-4){ + for (l=0;l<4;l++){ + for (f=0;f<4;f++){ + if (!checkFaceLine(f,l)) invalid = 1; + } + } + } else{ + invalid = 1; + } + if(invalid){ + nextBlock.height = activeBlock.height; + nextBlock.offset = activeBlock.offset; + nextBlock.block = activeBlock.block; + return 0; + } + return 1; +} + +int Board::checkFaceLine(int f, int l){ + //Determine which board line is being checked + unsigned long long boardLine = line[nextBlock.height + l +4]; + unsigned long long val = nextBlock.getFaceLine(f,l); + //Determine which board values are being compared + unsigned int lower = boardLine&0x00000000FFFFFFFF; + unsigned int upper = boardLine >> 32; + switch(f){ + case 0: + boardLine = lower&0x0000FFFF; + break; + case 1: + boardLine = lower>>16; + break; + case 2: + boardLine = upper&0x0000FFFF; + break; + case 3: + boardLine = upper>>16; + break; + default: + break; + } + //Shift block to align with board + val = shift(val,3+nextBlock.offset); + //boardLine = (boardLine>>2)<<nextBlock.offset; + //Compare block line value with the board value + if(boardLine&val)return 0;//Collision detected + return 1; + +} + +void Board::updateBlock(){ + eraseBlock(activeBlock); + activeBlock = nextBlock; + drawBlock(activeBlock); +} + +void Board::checkAndUpdate(){ + if(check()) updateBlock(); +} + +void Board::setBlock(){ + //Set block line by line. + int f = 0; + int l = 0; + for (f=0; f<4; f++){ + for (l=0; l<4; l++){ + setBlockFaceLine(f,l); + } + } + //Now check if lines need to be cleared + for (l=activeBlock.height+3; (l>activeBlock.height-1); l--){ + checkForClear(l+4); + } + //Now check if you lost + checkLose(); +} + +void Board::checkForClear(int l){ + if(l>3){ + if( line[l] == 0xFFFFFFFFFFFFFFFFULL) clearLine(l); + } +} + +void Board::setBlockFaceLine(int f, int l){ + //Determine which board line is being set + unsigned long long boardLine = getFaceLine(f,l+4+nextBlock.height); + unsigned long long val = nextBlock.getFaceLine(f,l); + //Shift block to align with board + val = shift(val,3+nextBlock.offset); + //Write to the board + boardLine |= val; + setBlockFaceLineVal(f,l+4+nextBlock.height, boardLine); +} + +void Board::setBlockFaceLineVal(int f, int l, unsigned long long bl){ + switch(f){ + case 0: + line[l] |= (bl); + break; + case 1: + line[l] |= (bl<<16); + break; + case 2: + line[l] |= (bl<<32); + break; + case 3: + line[l] |= (bl<<48); + break; + default: + break; + } +} + +void Board::drawGrid(){ + uLCD.baudrate(3000000); + int col = BLUE; + if(lost) col = RED; + lcd_mutex.lock(); + //Top left + uLCD.rectangle(127,0,126,91,col); + uLCD.rectangle(93,0,92,91,col); + //Bot right + uLCD.rectangle(0,127,1,36,col); + uLCD.rectangle(34,127,35,36,col); + //Bot left + uLCD.rectangle(0,0,93,1,col); + uLCD.rectangle(0,34,93,35,col); + //Top right + uLCD.rectangle(127,127,34,126,col); + uLCD.rectangle(127,93,34,92,col); + + drawBlock(activeBlock); + drawScore(); + lcd_mutex.unlock(); +} +void Board::drawPix(int line, int offset, int grid){ + int x0; + int y0; + switch(grid){ + case 0: + x0 = 94; + y0 = 36; + uLCD.rectangle(y0 + 4*line, x0 + 4*offset, y0 + 4*line + 3, x0 + 4*offset + 3, RED); + break; + case 1: + x0 = 36; + y0 = 33; + uLCD.rectangle(y0 - 4*offset, x0 + 4*line, y0 - 4*offset - 3, x0 + 4*line + 3, RED); + break; + case 2: + x0 = 33; + y0 = 91; + uLCD.rectangle(y0 - 4*line, x0 - 4*offset, y0 - 4*line - 3, x0 - 4*offset - 3, RED); + break; + case 3: + x0 = 91; + y0 = 94; + uLCD.rectangle(y0 + 4*offset, x0 - 4*line, y0 + 4*offset + 3, x0 - 4*line - 3, RED); + break; + default: + break; + + } + +} +void Board::erasePix(int line, int offset, int grid){ + int x0; + int y0; + switch(grid){ + case 0: + x0 = 94; + y0 = 36; + uLCD.rectangle(y0 + 4*line, x0 + 4*offset, y0 + 4*line + 3, x0 + 4*offset + 3, BLACK); + break; + case 1: + x0 = 36; + y0 = 33; + uLCD.rectangle(y0 - 4*offset, x0 + 4*line, y0 - 4*offset - 3, x0 + 4*line + 3, BLACK); + break; + case 2: + x0 = 33; + y0 = 91; + uLCD.rectangle(y0 - 4*line, x0 - 4*offset, y0 - 4*line - 3, x0 - 4*offset - 3, BLACK); + break; + case 3: + x0 = 91; + y0 = 94; + uLCD.rectangle(y0 + 4*offset, x0 - 4*line, y0 + 4*offset + 3, x0 - 4*line - 3, BLACK); + break; + default: + break; + + } + +} + + +void Board::drawBlock(Block blk){ + unsigned long long temp; + int i = 0; + lcd_mutex.lock(); + //Draw front face in grid 0 + temp = (blk.block&FACE0); + for (i=0; i<16; i++){ + if(temp&(0x01<<i)) drawPix(blk.height+(i/4), blk.offset+(i%4),0); + } + //Draw second face in grid 1 + temp = (blk.block&FACE1)>>16; + for (i=0; i<16; i++){ + if(temp&(0x01<<i)) drawPix(blk.height+(i/4), blk.offset+(i%4),1); + } + //Draw third face in grid 2 + temp = (blk.block&FACE2)>>32; + for (i=0; i<16; i++){ + if(temp&(0x01<<i)) drawPix(blk.height+(i/4), blk.offset+(i%4),2); + } + //Draw fourth face in grid 3 + temp = (blk.block&FACE3)>>48; + for (i=0; i<16; i++){ + if(temp&(0x01<<i)) drawPix(blk.height+(i/4), blk.offset+(i%4),3); + } + lcd_mutex.unlock(); +} + +void Board::eraseBlock(Block blk){ + unsigned long long temp; + int i = 0; + lcd_mutex.lock(); + //Draw front face in grid 0 + temp = (blk.block&FACE0); + for (i=0; i<16; i++){ + if(temp&(0x01<<i)) erasePix(blk.height+(i/4), blk.offset+(i%4),0); + } + //Draw second face in grid 1 + temp = (blk.block&FACE1)>>16; + for (i=0; i<16; i++){ + if(temp&(0x01<<i)) erasePix(blk.height+(i/4), blk.offset+(i%4),1); + } + //Draw third face in grid 2 + temp = (blk.block&FACE2)>>32; + for (i=0; i<16; i++){ + if(temp&(0x01<<i)) erasePix(blk.height+(i/4), blk.offset+(i%4),2); + } + //Draw fourth face in grid 3 + temp = (blk.block&FACE3)>>48; + for (i=0; i<16; i++){ + if(temp&(0x01<<i)) erasePix(blk.height+(i/4), blk.offset+(i%4),3); + } + lcd_mutex.unlock(); +} + +void Board::getNewBlock(){ + activeBlock.block = block_list[rand() % SET_SIZE]; + activeBlock.offset = DIMX / 2; + activeBlock.height = DIMZ - 5; + nextBlock.offset = activeBlock.offset; + nextBlock.height = activeBlock.height; + nextBlock.block = activeBlock.block; +} + +unsigned long long shift(unsigned long long value,int offset){ + unsigned long long rv; + if (offset > 0) rv = (value<<offset); + if (offset < 0) rv = (value>>offset); + if (offset == 0) rv = value; + return rv; +} + +unsigned long long Board::getFaceLine(int f, int l){ + unsigned int lower = line[l]&0xFFFFFFFFULL; + unsigned int upper = (line[l]>>32); + unsigned long long boardLine = 0; + switch(f){ + case 0: + boardLine = lower&0xFFFF; + break; + case 1: + boardLine = lower>>16; + break; + case 2: + boardLine = upper&0xFFFF; + break; + case 3: + boardLine = upper>>16; + break; + default: + break; + } + return boardLine; +} + +void Board::clearLine(int l){ + //Clears the line indexed by board array + int i; + int f; + for (i=l; i<(DIMZ+3); i++){ + //Replace the line with the one above it if they are not the same. + if (line[i] != line[i+1]){ + line[i] = line[i+1]; + //Then redraw the current line. + for (f=0; f<4; f++){ + redrawBoardLine(i-4, f, getFaceLine(f,i)); + } + } + } + line[DIMZ+3] = 0xF807F807F807F807ULL; + for (f=0; f<4; f++){ + redrawBoardLine(DIMZ-1, f, getFaceLine(f,DIMZ+3)); + } + score++; + drawScore(); +} + +void Board::redrawBoardLine(int l, int f, unsigned long long val){ + //Redraws the board line using natural index. + int offset = 0; + for(offset = 0; offset<DIMX; offset++){ + //Erase the pixel in the line. + erasePix(l, offset, f); + //check if we draw pixel here + if ( (val&(0x01<<(offset+3))) > 0) drawPix(l,offset,f); + + } +} + +void Board::drawScore(){ + uLCD.locate(6,6); + uLCD.text_width(1); //4X size text + uLCD.text_height(1); + uLCD.background_color(BLUE); + uLCD.color(BLUE); + uLCD.textbackground_color(BLACK); + uLCD.set_font(FONT_7X8); + uLCD.text_mode(OPAQUE); + uLCD.printf("Score:"); + uLCD.locate(6,8); + uLCD.printf(" %d",score); +} + +void Board::blockFall(){ + nextBlock.height--; + int h = nextBlock.height; + while(check()){ + h--; + nextBlock.height--; + } + nextBlock.height = h+1; +} + +void Board::checkLose(){ + int i; + for (i=DIMLOSE; i<DIMZ; i++){ + if (line[i+4] != 0xF807F807F807F807ULL)lost=1; + drawGrid(); + } +} \ No newline at end of file