Tetris game for mbed.

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

Fork of HelloWorld by Simon Ford

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers tetris.cpp Source File

tetris.cpp

00001 #include <stdlib.h>
00002 #include <time.h>
00003 #include "tetris.h"
00004 #include "uLCD_4DGL.h"
00005 #include "rtos.h"
00006 #include "mbed.h"
00007 
00008 uLCD_4DGL uLCD(p28,p27,p29); // serial tx, serial rx, reset pin;
00009 Mutex lcd_mutex;
00010 
00011 Block::Block(){
00012     srand(time(NULL));
00013     block = block_list[rand() % SET_SIZE];
00014     offset = DIMX / 2;
00015     height = DIMZ - 5;
00016 }
00017 
00018 Block::Block(short ind){
00019     block = block_list[ind];
00020     offset = DIMX / 2;
00021     height = DIMZ - 5;
00022 }
00023 
00024 Block::Block(short ind, short offs, short h){
00025     block = block_list[ind];
00026     offset = offs;
00027     height = h;
00028 }
00029 
00030 unsigned long long Block::getFace(int n){
00031     unsigned long long rv = 0;
00032     unsigned int lower = block&0xFFFFFFFFULL;
00033     unsigned int upper = (block>>32);
00034     switch(n){
00035         case 0:
00036         rv = lower&FACE0;
00037         break;
00038         case 1:
00039         rv = (lower>>16)&FACE0;//shift(block,-16)&FACE0;
00040         break;
00041         case 2:
00042         rv = (upper)&FACE0;//shift(block,-16)&FACE0;
00043         break;
00044         case 3:
00045         rv = (upper>>16)&FACE0;//shift(block,-16)&FACE0;
00046         break;
00047         default:
00048         rv =  0;
00049         }
00050         return rv;
00051 
00052 }
00053 
00054 unsigned long long Block::getLine(int n){
00055     unsigned long long rv = 0;
00056     unsigned int lower = block&0xFFFFFFFFULL;
00057     unsigned int upper = (block>>32);
00058     switch(n){
00059         case 0:
00060         rv = (lower&LINE0) | ((upper&LINE0)<<32);
00061         break;
00062         case 1:
00063         lower = lower >>4;
00064         upper = upper >>4;
00065         rv = (lower&LINE0) | ((upper&LINE0)<<32);
00066         break;
00067         case 2:
00068         lower = lower >>8;
00069         upper = upper >>8;
00070         rv = (lower&LINE0) | ((upper&LINE0)<<32);
00071         break;
00072         case 3:
00073         lower = lower >>12;
00074         upper = upper >>12;
00075         rv = (lower&LINE0) | ((upper&LINE0)<<32);
00076         break;
00077         default:
00078         rv =  0;
00079         }
00080         return rv;
00081         
00082 
00083 }
00084 
00085 unsigned long long Block::getFaceLine(int f, int l){
00086     unsigned long long face = getFace(f);
00087     unsigned long long rv = 0;
00088     switch(l){
00089         case 0:
00090         rv = (face&0x000F);
00091         break;
00092         case 1:
00093         rv = (face&0x00F0)>>4;
00094         break;
00095         case 2:
00096         rv = (face&0x0F00)>>8;
00097         break;
00098         case 3:
00099         rv = (face&0xF000)>>12;
00100         break;
00101         default:
00102         rv =  0;
00103         }
00104         return rv;
00105 }
00106 void Block::rotY(){
00107             unsigned long long temp = block;
00108             block = ((temp&0x0001000100010001ULL)<<3)|((temp&0x0002000200020002ULL)<<6)|
00109                         ((temp&0x0004000400040004ULL)<<9)|((temp&0x0008000800080008ULL)<<12)|
00110                         ((temp&0x0010001000100010ULL)>>2)|((temp&0x0020002000200020ULL)<<1)|
00111                         ((temp&0x0040004000400040ULL)<<4)|((temp&0x0080008000800080ULL)<<7)|
00112                         ((temp&0x0100010001000100ULL)>>7)|((temp&0x0200020002000200ULL)>>4)|
00113                         ((temp&0x0400040004000400ULL)>>1)|((temp&0x0800080008000800ULL)<<2)|
00114                         ((temp&0x1000100010001000ULL)>>12)|((temp&0x2000200020002000ULL)>>9)|
00115                         ((temp&0x4000400040004000ULL)>>6)|((temp&0x8000800080008000ULL)>>3);
00116 }
00117 void Block::rotZ(){
00118             unsigned long long temp = block;
00119             block =     ((temp&0x0000000000001111ULL)<<3) |((temp&0x0000000000002222ULL)<<18)|
00120                         ((temp&0x0000000000004444ULL)<<33)|((temp&0x0000000000008888ULL)<<48)|
00121                         ((temp&0x0000000011110000ULL)>>14)|((temp&0x0000000022220000ULL)<<1) |
00122                         ((temp&0x0000000044440000ULL)<<16)|((temp&0x0000000088880000ULL)<<31)|
00123                         ((temp&0x0000111100000000ULL)>>31)|((temp&0x0000222200000000ULL)>>16)|
00124                         ((temp&0x0000444400000000ULL)>>1) |((temp&0x0000888800000000ULL)<<14)|
00125                         ((temp&0x1111000000000000ULL)>>48)|((temp&0x2222000000000000ULL)>>33)|
00126                         ((temp&0x4444000000000000ULL)>>18)|((temp&0x8888000000000000ULL)>>3);
00127 }
00128 void Block::rotX(){
00129             unsigned long long temp = block;
00130             block =     ((temp&0x000000000000000FULL)<<12)|((temp&0x00000000000000F0ULL)<<24)|
00131                         ((temp&0x0000000000000F00ULL)<<36)|((temp&0x000000000000F000ULL)<<48)|
00132                         ((temp&0x00000000000F0000ULL)>>8)| ((temp&0x0000000000F00000ULL)<<4)|
00133                         ((temp&0x000000000F000000ULL)<<16)|((temp&0x00000000F0000000ULL)<<28)|
00134                         ((temp&0x0000000F00000000ULL)>>28)|((temp&0x000000F000000000ULL)>>16)|
00135                         ((temp&0x00000F0000000000ULL)>>4) |((temp&0x0000F00000000000ULL)<<8)|
00136                         ((temp&0x000F000000000000ULL)>>48)|((temp&0x00F0000000000000ULL)>>36)|
00137                         ((temp&0x0F00000000000000ULL)>>24)|((temp&0xF000000000000000ULL)>>12);
00138 }
00139 void Block::movR(){
00140     offset++;
00141     //if (offset >= DIMX) offset = 0;
00142 }
00143 
00144 void Block::movL(){
00145     offset--;
00146     if (offset <-3) offset = -3;
00147 }
00148 
00149 void Block::movB(){
00150     unsigned long long temp = block;
00151     block = ((temp&0x0000FFFFFFFFFFFFULL)<<16)|((temp&0xFFFF000000000000ULL)>>48);
00152 }
00153 
00154 void Block::movF(){
00155     unsigned long long temp = block;
00156     block = ((temp&0xFFFFFFFFFFFF0000ULL)>>16)|((temp&0x000000000000FFFFULL)<<48);
00157 }
00158 
00159 void Block::movU(){
00160     height++;
00161 }
00162 
00163 void Block::movD(){
00164     height--;
00165     //if (height<-3) height = -3;
00166 }
00167 
00168 
00169 
00170 Board::Board(){
00171     nextBlock.offset = activeBlock.offset;
00172     nextBlock.height = activeBlock.height;
00173     nextBlock.block = activeBlock.block;
00174     int i;
00175     for (i = 0; i<4; i++) line[i] = 0xFFFFFFFFFFFFFFFFULL;
00176     for (i = 4; i<DIMZ+4; i++) line[i] = 0xF807F807F807F807ULL;
00177     score = 0;
00178 }
00179 
00180 int Board::check(){
00181     //Check next block with board lines.
00182     //Returns 0 when a collision (illegal state) is detected.
00183     //Returns 1 when move is legal.
00184     int invalid = 0;
00185     int f = 0;
00186     int l = 0;
00187     if (nextBlock.height >-4){
00188         for (l=0;l<4;l++){
00189             for (f=0;f<4;f++){
00190                 if (!checkFaceLine(f,l)) invalid = 1;
00191             }
00192         }
00193     } else{
00194             invalid = 1;
00195         }
00196     if(invalid){
00197         nextBlock.height = activeBlock.height;
00198         nextBlock.offset = activeBlock.offset;
00199         nextBlock.block = activeBlock.block;
00200         return 0;
00201         }
00202     return 1;
00203 }
00204 
00205 int Board::checkFaceLine(int f, int l){
00206     //Determine which board line is being checked
00207     unsigned long long boardLine = line[nextBlock.height + l +4];
00208     unsigned long long val = nextBlock.getFaceLine(f,l);
00209     //Determine which board values are being compared
00210     unsigned int lower = boardLine&0x00000000FFFFFFFF;
00211     unsigned int upper = boardLine >> 32;
00212     switch(f){
00213         case 0:
00214         boardLine = lower&0x0000FFFF;
00215         break;
00216         case 1:
00217         boardLine = lower>>16;
00218         break;
00219         case 2:
00220         boardLine = upper&0x0000FFFF;
00221         break;
00222         case 3:
00223         boardLine = upper>>16;
00224         break;
00225         default:
00226         break;
00227     }
00228     //Shift block to align with board
00229     val = shift(val,3+nextBlock.offset);
00230     //boardLine = (boardLine>>2)<<nextBlock.offset;
00231     //Compare block line value with the board value
00232     if(boardLine&val)return 0;//Collision detected
00233     return 1;
00234     
00235 }
00236 
00237 void Board::updateBlock(){
00238     eraseBlock(activeBlock);
00239     activeBlock = nextBlock;
00240     drawBlock(activeBlock);
00241 }
00242 
00243 void Board::checkAndUpdate(){
00244     if(check()) updateBlock();
00245 }
00246 
00247 void Board::setBlock(){
00248     //Set block line by line.
00249     int f = 0;
00250     int l = 0;
00251     for (f=0; f<4; f++){
00252         for (l=0; l<4; l++){
00253             setBlockFaceLine(f,l);   
00254         }
00255     }
00256     //Now check if lines need to be cleared
00257     for (l=activeBlock.height+3; (l>activeBlock.height-1); l--){
00258         checkForClear(l+4);
00259     }
00260     //Now check if you lost
00261     checkLose();
00262 }
00263 
00264 void Board::checkForClear(int l){
00265     if(l>3){
00266         if( line[l] == 0xFFFFFFFFFFFFFFFFULL) clearLine(l);
00267     }
00268 }
00269 
00270 void Board::setBlockFaceLine(int f, int l){
00271     //Determine which board line is being set
00272     unsigned long long boardLine = getFaceLine(f,l+4+nextBlock.height);
00273     unsigned long long val = nextBlock.getFaceLine(f,l);
00274     //Shift block to align with board
00275     val = shift(val,3+nextBlock.offset);
00276     //Write to the board
00277     boardLine |= val;
00278     setBlockFaceLineVal(f,l+4+nextBlock.height, boardLine);
00279 }
00280 
00281 void Board::setBlockFaceLineVal(int f, int l, unsigned long long bl){
00282     switch(f){
00283         case 0:
00284         line[l] |= (bl);
00285         break;
00286         case 1:
00287         line[l] |= (bl<<16);
00288         break;
00289         case 2:
00290         line[l] |= (bl<<32);
00291         break;
00292         case 3:
00293         line[l] |= (bl<<48);
00294         break;
00295         default:
00296         break;
00297         }
00298 }
00299 
00300 void Board::drawGrid(){
00301         uLCD.baudrate(3000000);
00302         int col = BLUE;
00303         if(lost) col = RED;
00304         lcd_mutex.lock();
00305         //Top left
00306         uLCD.rectangle(127,0,126,91,col);
00307         uLCD.rectangle(93,0,92,91,col);
00308         //Bot right
00309         uLCD.rectangle(0,127,1,36,col);
00310         uLCD.rectangle(34,127,35,36,col);
00311         //Bot left
00312         uLCD.rectangle(0,0,93,1,col);
00313         uLCD.rectangle(0,34,93,35,col);
00314         //Top right
00315         uLCD.rectangle(127,127,34,126,col);
00316         uLCD.rectangle(127,93,34,92,col);
00317         
00318         drawBlock(activeBlock);
00319         drawScore();
00320         lcd_mutex.unlock();
00321 }
00322 void Board::drawPix(int line, int offset, int grid){
00323     int x0;
00324     int y0;
00325     switch(grid){
00326         case 0:
00327         x0 = 94;
00328         y0 = 36;
00329         uLCD.rectangle(y0 + 4*line, x0 + 4*offset, y0 + 4*line + 3, x0 + 4*offset + 3, RED);
00330         break;
00331         case 1:
00332         x0 = 36;
00333         y0 = 33;
00334         uLCD.rectangle(y0 - 4*offset, x0 + 4*line, y0 - 4*offset - 3, x0 + 4*line + 3, RED);
00335         break;
00336         case 2:
00337         x0 = 33;
00338         y0 = 91;
00339         uLCD.rectangle(y0 - 4*line, x0 - 4*offset, y0 - 4*line - 3, x0 - 4*offset - 3, RED);
00340         break;
00341         case 3:
00342         x0 = 91;
00343         y0 = 94;
00344         uLCD.rectangle(y0 + 4*offset, x0 - 4*line, y0 + 4*offset + 3, x0 - 4*line - 3, RED);
00345         break;
00346         default:
00347         break;
00348         
00349         }
00350     
00351 }
00352 void Board::erasePix(int line, int offset, int grid){
00353     int x0;
00354     int y0;
00355     switch(grid){
00356         case 0:
00357         x0 = 94;
00358         y0 = 36;
00359         uLCD.rectangle(y0 + 4*line, x0 + 4*offset, y0 + 4*line + 3, x0 + 4*offset + 3, BLACK);
00360         break;
00361         case 1:
00362         x0 = 36;
00363         y0 = 33;
00364         uLCD.rectangle(y0 - 4*offset, x0 + 4*line, y0 - 4*offset - 3, x0 + 4*line + 3, BLACK);
00365         break;
00366         case 2:
00367         x0 = 33;
00368         y0 = 91;
00369         uLCD.rectangle(y0 - 4*line, x0 - 4*offset, y0 - 4*line - 3, x0 - 4*offset - 3, BLACK);
00370         break;
00371         case 3:
00372         x0 = 91;
00373         y0 = 94;
00374         uLCD.rectangle(y0 + 4*offset, x0 - 4*line, y0 + 4*offset + 3, x0 - 4*line - 3, BLACK);
00375         break;
00376         default:
00377         break;
00378         
00379         }
00380     
00381 }
00382 
00383 
00384 void Board::drawBlock(Block blk){
00385     unsigned long long temp;
00386     int i = 0;
00387     lcd_mutex.lock();
00388     //Draw front face in grid 0
00389     temp = (blk.block&FACE0);
00390     for (i=0; i<16; i++){
00391         if(temp&(0x01<<i)) drawPix(blk.height+(i/4), blk.offset+(i%4),0);
00392         }
00393     //Draw second face in grid 1
00394     temp = (blk.block&FACE1)>>16;
00395     for (i=0; i<16; i++){
00396         if(temp&(0x01<<i)) drawPix(blk.height+(i/4), blk.offset+(i%4),1);
00397         }
00398     //Draw third face in grid 2
00399     temp = (blk.block&FACE2)>>32;
00400     for (i=0; i<16; i++){
00401         if(temp&(0x01<<i)) drawPix(blk.height+(i/4), blk.offset+(i%4),2);
00402         }
00403     //Draw fourth face in grid 3
00404     temp = (blk.block&FACE3)>>48;
00405     for (i=0; i<16; i++){
00406         if(temp&(0x01<<i)) drawPix(blk.height+(i/4), blk.offset+(i%4),3);
00407         }
00408         lcd_mutex.unlock();
00409 }
00410 
00411 void Board::eraseBlock(Block blk){
00412     unsigned long long temp;
00413     int i = 0;
00414     lcd_mutex.lock();
00415     //Draw front face in grid 0
00416     temp = (blk.block&FACE0);
00417     for (i=0; i<16; i++){
00418         if(temp&(0x01<<i)) erasePix(blk.height+(i/4), blk.offset+(i%4),0);
00419         }
00420     //Draw second face in grid 1
00421     temp = (blk.block&FACE1)>>16;
00422     for (i=0; i<16; i++){
00423         if(temp&(0x01<<i)) erasePix(blk.height+(i/4), blk.offset+(i%4),1);
00424         }
00425     //Draw third face in grid 2
00426     temp = (blk.block&FACE2)>>32;
00427     for (i=0; i<16; i++){
00428         if(temp&(0x01<<i)) erasePix(blk.height+(i/4), blk.offset+(i%4),2);
00429         }
00430     //Draw fourth face in grid 3
00431     temp = (blk.block&FACE3)>>48;
00432     for (i=0; i<16; i++){
00433         if(temp&(0x01<<i)) erasePix(blk.height+(i/4), blk.offset+(i%4),3);
00434         }
00435         lcd_mutex.unlock();
00436 }
00437 
00438 void Board::getNewBlock(){
00439     activeBlock.block = block_list[rand() % SET_SIZE];
00440     activeBlock.offset = DIMX / 2;
00441     activeBlock.height = DIMZ - 5;
00442     nextBlock.offset = activeBlock.offset;
00443     nextBlock.height = activeBlock.height;
00444     nextBlock.block = activeBlock.block;
00445 }
00446 
00447 unsigned long long shift(unsigned long long value,int offset){
00448     unsigned long long rv;
00449     if (offset > 0) rv =  (value<<offset);
00450     if (offset < 0) rv = (value>>offset);
00451     if (offset == 0) rv = value;
00452     return rv;
00453 }
00454 
00455 unsigned long long Board::getFaceLine(int f, int l){
00456     unsigned int lower = line[l]&0xFFFFFFFFULL;
00457     unsigned int upper = (line[l]>>32);
00458     unsigned long long boardLine = 0;
00459     switch(f){
00460         case 0:
00461         boardLine = lower&0xFFFF;
00462         break;
00463         case 1:
00464         boardLine = lower>>16;
00465         break;
00466         case 2:
00467         boardLine = upper&0xFFFF;
00468         break;
00469         case 3:
00470         boardLine = upper>>16;
00471         break;
00472         default:
00473         break;
00474         }    
00475         return boardLine;
00476 }
00477 
00478 void Board::clearLine(int l){
00479     //Clears the line indexed by board array
00480     int i;
00481     int f;
00482     for (i=l; i<(DIMZ+3); i++){
00483         //Replace the line with the one above it if they are not the same.
00484         if (line[i] != line[i+1]){
00485             line[i] = line[i+1];
00486             //Then redraw the current line.
00487             for (f=0; f<4; f++){
00488                 redrawBoardLine(i-4, f, getFaceLine(f,i));
00489             }
00490         }
00491     }
00492     line[DIMZ+3] = 0xF807F807F807F807ULL;
00493     for (f=0; f<4; f++){
00494         redrawBoardLine(DIMZ-1, f, getFaceLine(f,DIMZ+3));
00495     }
00496     score++;
00497     drawScore();
00498 }
00499 
00500 void Board::redrawBoardLine(int l, int f, unsigned long long val){
00501     //Redraws the board line using natural index.
00502     int offset = 0;
00503     for(offset = 0; offset<DIMX; offset++){
00504         //Erase the pixel in the line.
00505         erasePix(l, offset, f);
00506         //check if we draw pixel here
00507         if ( (val&(0x01<<(offset+3))) > 0) drawPix(l,offset,f);     
00508         
00509     }
00510 }
00511 
00512 void Board::drawScore(){
00513     uLCD.locate(6,6);
00514     uLCD.text_width(1); //4X size text
00515     uLCD.text_height(1);
00516     uLCD.background_color(BLUE);
00517     uLCD.color(BLUE);
00518     uLCD.textbackground_color(BLACK);
00519     uLCD.set_font(FONT_7X8);
00520     uLCD.text_mode(OPAQUE);
00521     uLCD.printf("Score:");
00522     uLCD.locate(6,8);
00523     uLCD.printf("   %d",score);
00524 }
00525 
00526 void Board::blockFall(){
00527     nextBlock.height--;
00528     int h = nextBlock.height;
00529     while(check()){
00530             h--;
00531             nextBlock.height--;
00532         }
00533     nextBlock.height = h+1;   
00534 }
00535 
00536 void Board::checkLose(){
00537     int i;
00538     for (i=DIMLOSE; i<DIMZ; i++){
00539         if (line[i+4] != 0xF807F807F807F807ULL)lost=1;
00540         drawGrid();
00541         }
00542 }