Tetris game for mbed.
Dependencies: 4DGL-uLCD-SE SDFileSystem mbed-rtos mbed wave_player
Fork of HelloWorld by
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 }
Generated on Sat Jul 23 2022 12:39:35 by 1.7.2