Tetris game for mbed.

Dependencies:   4DGL-uLCD-SE SDFileSystem mbed-rtos mbed wave_player

Fork of HelloWorld by Simon Ford

Revision:
2:36cda8980746
diff -r 03c191369089 -r 36cda8980746 tetris.cpp
--- /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