Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: 4DGL-uLCD-SE PinDetect SDFileSystem mbed wave_player
BlueO.h
00001 /******************************************************* 00002 * This header program declares all of the functions and 00003 * variables used by the blue O player in Super 00004 * Tic-Tac-Toe. 00005 *******************************************************/ 00006 00007 00008 #define FORWARDSLASH 0 00009 #define BACKWARDSLASH 1 00010 #define VERTICAL 2 00011 #define HORIZONTAL 3 00012 #define BOMB "/sd/wavfiles/bomb.wav" 00013 #define WIN "/sd/win.wav" 00014 #define MEH "/sd/Meh.wav" 00015 00016 00017 /******************************************************* 00018 * This structure is used to represent the individual 00019 * blocks within a small grid. 00020 *******************************************************/ 00021 struct smallGrid { 00022 char individualGrid[3][3]; 00023 char done; 00024 }; 00025 00026 /******************************************************* 00027 * This structure is used to represent the small 00028 * blocks within the whole grid. 00029 *******************************************************/ 00030 struct largeGrid { 00031 smallGrid smallGrid[3][3]; 00032 char done; 00033 }; 00034 00035 00036 class BlueO { 00037 public: 00038 // Player O constructor 00039 BlueO(DigitalOut &reset, InterruptIn &input, Mpr121 &MPR121, RGBLED &RGB, SDFileSystem &sd, Serial &XBee, uLCD_4DGL &uLCD, wave_player &waver) : 00040 reset(reset), input(input), MPR121(MPR121), RGB(RGB), sd(sd), XBee(XBee), uLCD(uLCD), waver(waver) { 00041 uLCD.baudrate(MAXBAUDRATE); 00042 key = -1; 00043 00044 // Set up XBee 00045 reset = 0; 00046 wait(0.001); 00047 reset = 1; 00048 wait(0.001); 00049 } 00050 00051 // Play the game 00052 void playSuperTicTacToe() { 00053 initializeInterrupt(); 00054 displayInstructions(); 00055 initializeGrid(); 00056 00057 XBee.putc(true); 00058 bool readyToPlay = false; 00059 bool print = true; 00060 00061 while (readyToPlay == false) { 00062 if (XBee.readable() == true) { 00063 readyToPlay = XBee.getc(); 00064 print = false; 00065 } 00066 00067 if (print == true) { 00068 uLCD.cls(); 00069 uLCD.printf("Waiting for other player..."); 00070 print = false; 00071 } 00072 } 00073 00074 uLCD.cls(); 00075 drawStage(); 00076 00077 // False: player one's turn; true: player two's turn 00078 bool turn = true; 00079 00080 // Loop through the game 00081 while (grid.done == (char)(-1)) { 00082 turn = !turn; 00083 takeTurn(turn); 00084 gameWin(turn); 00085 } 00086 00087 uLCD.cls(); 00088 00089 if (grid.done == 0) { 00090 uLCD.printf("The other player\nwins."); 00091 playSound(BOMB); 00092 } else if (grid.done == 1) { 00093 uLCD.printf("You win!"); 00094 playSound(WIN); 00095 } else if (grid.done == 128) { 00096 uLCD.printf("It's a draw!"); 00097 playSound(MEH); 00098 } 00099 00100 wait(3); 00101 uLCD.cls(); 00102 } 00103 00104 00105 private: 00106 DigitalOut &reset; 00107 InterruptIn &input; 00108 Mpr121 &MPR121; 00109 RGBLED &RGB; 00110 SDFileSystem &sd; 00111 Serial &XBee; 00112 uLCD_4DGL &uLCD; 00113 wave_player &waver; 00114 bool keyAllowed; 00115 volatile int key; 00116 largeGrid grid; 00117 00118 // Initialize the interrupt 00119 void initializeInterrupt() { 00120 input.fall(this, &BlueO::keyInterrupt); 00121 wait(0.01); 00122 input.mode(PullUp); 00123 wait(0.01); 00124 } 00125 00126 // Determine value of the key pressed 00127 void keyInterrupt() { 00128 if (keyAllowed == true) { 00129 int value = MPR121.read(0x00); 00130 value += MPR121.read(0x01) << 8; 00131 00132 for (int i = 0; i < 12; i++) { 00133 if (((value >> i) & 0x01) == 1) { 00134 key = i; 00135 } 00136 } 00137 00138 // Ununsed keys 00139 if ((key == 3) || (key == 7) || (key == 11)) { 00140 key = -1; 00141 } 00142 } else { 00143 key = -1; 00144 } 00145 } 00146 00147 // Initialize the grid 00148 void initializeGrid() { 00149 grid.done = (char)(-1); 00150 00151 for (int i = 0; i < 3; i++) { 00152 for (int j = 0; j < 3; j++) { 00153 grid.smallGrid[i][j].done = (char)(-1); 00154 00155 for (int k = 0; k < 3; k++) { 00156 for (int l = 0; l < 3; l++) { 00157 grid.smallGrid[i][j].individualGrid[k][l] = (char)(-1); 00158 } 00159 } 00160 } 00161 } 00162 } 00163 00164 // Display instructions 00165 void displayInstructions() { 00166 uLCD.printf("Hello, and welcome"); 00167 uLCD.printf("to a game of Super"); 00168 uLCD.printf("Tic-Tac-Toe. Use "); 00169 uLCD.printf("the bottom three "); 00170 uLCD.printf("rows of the touch "); 00171 uLCD.printf("keypad to select "); 00172 uLCD.printf("the large grid "); 00173 uLCD.printf("followed by the "); 00174 uLCD.printf("small grid. You "); 00175 uLCD.printf("are the blue O.\n\n"); 00176 uLCD.printf("Press any key to "); 00177 uLCD.printf("begin playing."); 00178 wait(0.1); 00179 00180 key = -1; 00181 keyAllowed = true; 00182 00183 while (key == -1) { 00184 wait(0.01); 00185 } 00186 00187 key = -1; 00188 uLCD.cls(); 00189 } 00190 00191 // Play a sound file 00192 void playSound(char *wav) { 00193 // Open sound file 00194 FILE *wave_file; 00195 wave_file = fopen(wav, "r"); 00196 00197 // Play wav file 00198 waver.play(wave_file); 00199 00200 // Close wav file 00201 fclose(wave_file); 00202 } 00203 00204 // Draw the stage 00205 void drawStage() { 00206 for (int i = 15; i < 120; i += 14) { 00207 uLCD.line(i, 2, i, 127, YELLOW); 00208 uLCD.line(2, i, 127, i, YELLOW); 00209 } 00210 00211 for (int i = 43; i < 120; i += 42) { 00212 uLCD.line(i, 2, i, 127, WHITE); 00213 uLCD.line(2, i, 127, i, WHITE); 00214 } 00215 } 00216 00217 // Draw small X 00218 void drawSmallX(int largeX, int largeY, int smallX, int smallY) { 00219 int xCoordinate = 1 + (largeX * 42) + (smallX * 14) + 7; 00220 int yCoordinate = 1 + (largeY * 42) + (smallY * 14) + 7; 00221 00222 int x1 = xCoordinate - 6; 00223 int x2 = xCoordinate + 6; 00224 int y1 = yCoordinate - 6; 00225 int y2 = yCoordinate + 6; 00226 00227 uLCD.line(x1 + 1, y1 + 1, x2, y2, RED); 00228 uLCD.line(x1 + 1, y2 - 1, x2, y1, RED); 00229 } 00230 00231 // Draw small O 00232 void drawSmallO(int largeX, int largeY, int smallX, int smallY) { 00233 int xCoordinate = 1 + (largeX * 42) + (smallX * 14) + 7; 00234 int yCoordinate = 1 + (largeY * 42) + (smallY * 14) + 7; 00235 00236 uLCD.circle(xCoordinate, yCoordinate, 5, BLUE); 00237 } 00238 00239 // Draw large X 00240 void drawLargeX(int largeX, int largeY) { 00241 int xCoordinate = 1 + (largeX * 42) + 21; 00242 int yCoordinate = 1 + (largeY * 42) + 21; 00243 00244 int x1 = xCoordinate - 20; 00245 int x2 = xCoordinate + 20; 00246 int y1 = yCoordinate - 20; 00247 int y2 = yCoordinate + 20; 00248 00249 uLCD.filled_rectangle(x1, y1, x2, y2, BLACK); 00250 00251 uLCD.line(x1 + 1, y1 + 1, x2, y2, RED); 00252 uLCD.line(x1 + 1, y2 - 1, x2, y1, RED); 00253 } 00254 00255 // Draw large O 00256 void drawLargeO(int largeX, int largeY) { 00257 int xCoordinate = 1 + (largeX * 42) + 21; 00258 int yCoordinate = 1 + (largeY * 42) + 21; 00259 00260 int x1 = xCoordinate - 20; 00261 int x2 = xCoordinate + 20; 00262 int y1 = yCoordinate - 20; 00263 int y2 = yCoordinate + 20; 00264 00265 uLCD.filled_rectangle(x1, y1, x2, y2, BLACK); 00266 00267 uLCD.circle(xCoordinate, yCoordinate, 19, BLUE); 00268 } 00269 00270 // Find x-coordinate based on key input 00271 int xGrid() { 00272 int x; 00273 00274 if ((key == 0) || (key == 1) || (key == 2)) { 00275 x = 0; 00276 } else if ((key == 4) || (key == 5) || (key == 6)) { 00277 x = 1; 00278 } else if ((key == 8) || (key == 9) || (key == 10)) { 00279 x = 2; 00280 } else { 00281 x = -1; 00282 } 00283 00284 return x; 00285 } 00286 00287 // Find y-coordinate based on key input 00288 int yGrid() { 00289 int y; 00290 00291 if ((key == 2) || (key == 6) || (key == 10)) { 00292 y = 0; 00293 } else if ((key == 1) || (key == 5) || (key == 9)) { 00294 y = 1; 00295 } else if ((key == 0) || (key == 4) || (key == 8)) { 00296 y = 2; 00297 } else { 00298 y = -1; 00299 } 00300 00301 return y; 00302 } 00303 00304 // Display a certain small grid in a set color 00305 void drawSmallGrid(int x, int y, int color) { 00306 int x1 = 1 + (x * 42) + 1; 00307 int x2 = x1 + 40; 00308 int y1 = 1 + (y * 42) + 1; 00309 int y2 = y1 + 40; 00310 00311 for (int i = x1; i < x2; i += 14) { 00312 for (int j = y1; j < y2; j += 14) { 00313 uLCD.filled_rectangle(i, j, i + 12, j + 12, color); 00314 } 00315 } 00316 00317 for (int i = 0; i < 3; i++) { 00318 for (int j = 0; j < 3; j++) { 00319 if (grid.smallGrid[x][y].individualGrid[i][j] == 0) { 00320 drawSmallX(x, y, i, j); 00321 } else if (grid.smallGrid[x][y].individualGrid[i][j] == 1) { 00322 drawSmallO(x, y, i, j); 00323 } 00324 } 00325 } 00326 } 00327 00328 // Draw a line if a player takes a small grid 00329 void drawSmallWinLine(int x1, int y1, int orientation) { 00330 int x2 = x1; 00331 int y2 = y1; 00332 00333 if (orientation == FORWARDSLASH) { 00334 x2 = x1 - 41; 00335 y2 = y1 + 41; 00336 } else if (orientation == BACKWARDSLASH) { 00337 x2 = x1 + 41; 00338 y2 = y1 + 41; 00339 } else if (orientation == VERTICAL) { 00340 y2 = y1 + 41; 00341 } else if (orientation == HORIZONTAL) { 00342 x2 = x1 + 41; 00343 } 00344 00345 uLCD.line(x1, y1, x2, y2, GREEN); 00346 wait(1); 00347 } 00348 00349 // Check whether a player has taken a small grid 00350 bool smallGridWin(int largeX, int largeY, int smallX, int smallY) { 00351 bool taken = false; 00352 char individual[3][3]; 00353 00354 for (int i = 0; i < 3; i++) { 00355 for (int j = 0; j < 3; j++) { 00356 individual[i][j] = grid.smallGrid[largeX][largeY].individualGrid[i][j]; 00357 } 00358 } 00359 00360 int x1 = 1 + (largeX * 42) + 1; 00361 int y1 = 1 + (largeY * 42) + 1; 00362 int orientation = -1; 00363 00364 if ((individual[0][0] == individual[1][1]) && (individual[1][1] == individual[2][2]) && 00365 (individual[0][0] != (char)(-1))) { 00366 orientation = BACKWARDSLASH; 00367 taken = true; 00368 } else if ((individual[2][0] == individual[1][1]) && (individual[1][1] == individual[0][2]) && 00369 (individual[2][0] != (char)(-1))) { 00370 orientation = FORWARDSLASH; 00371 x1 += 40; 00372 taken = true; 00373 } else if ((individual[0][0] == individual[1][0]) && (individual[1][0] == individual[2][0]) && 00374 (individual[0][0] != (char)(-1))) { 00375 orientation = HORIZONTAL; 00376 y1 += 6; 00377 taken = true; 00378 } else if ((individual[0][1] == individual[1][1]) && (individual[1][1] == individual[2][1]) && 00379 (individual[0][1] != (char)(-1))) { 00380 orientation = HORIZONTAL; 00381 y1 += 20; 00382 taken = true; 00383 } else if ((individual[0][2] == individual[1][2]) && (individual[1][2] == individual[2][2]) && 00384 (individual[0][2] != (char)(-1))) { 00385 orientation = HORIZONTAL; 00386 y1 += 34; 00387 taken = true; 00388 } else if ((individual[0][0] == individual[0][1]) && (individual[0][1] == individual[0][2]) && 00389 (individual[0][0] != (char)(-1))) { 00390 orientation = VERTICAL; 00391 x1 += 6; 00392 taken = true; 00393 } else if ((individual[1][0] == individual[1][1]) && (individual[1][1] == individual[1][2]) && 00394 (individual[1][0] != (char)(-1))) { 00395 orientation = VERTICAL; 00396 x1 += 20; 00397 taken = true; 00398 } else if ((individual[2][0] == individual[2][1]) && (individual[2][1] == individual[2][2]) && 00399 (individual[2][0] != (char)(-1))) { 00400 orientation = VERTICAL; 00401 x1 += 34; 00402 taken = true; 00403 } else { 00404 orientation = -1; 00405 taken = false; 00406 } 00407 00408 // Check to see if there is a draw 00409 if (taken == false) { 00410 bool draw = true; 00411 00412 for (int i = 0; i < 3; i++) { 00413 for (int j = 0; j < 3; j++) { 00414 if (individual[i][j] != (char)(-1)) { 00415 draw = false; 00416 } 00417 } 00418 } 00419 00420 if (draw == true) { 00421 grid.smallGrid[largeX][largeY].done = 128; 00422 } 00423 } 00424 00425 drawSmallWinLine(x1, y1, orientation); 00426 00427 return taken; 00428 } 00429 00430 // Take a turn 00431 void takeTurn(bool turn) { 00432 // Player selects small grid, then individual grid 00433 int keyInputs[2] = {-1, -1}; 00434 00435 // If it is player one's turn 00436 if (turn == false) { 00437 RGB = RED; 00438 00439 // Allow user input 00440 keyAllowed = true; 00441 00442 int largeX = 0; 00443 int largeY = 0; 00444 00445 key = -1; 00446 00447 // Ready to proceed 00448 XBee.putc(true); 00449 00450 // Wait for player to select small grid 00451 while ((keyInputs[0] == -1) || (grid.smallGrid[largeX][largeY].done != (char)(-1))) { 00452 // Read in the value through the XBee 00453 if (XBee.readable() == true) { 00454 key = XBee.getc(); 00455 keyInputs[0] = key; 00456 largeX = xGrid(); 00457 largeY = yGrid(); 00458 } 00459 } 00460 00461 // Highlight selected grid 00462 drawSmallGrid(largeX, largeY, PINK); 00463 00464 playSound("/sd/select.wav"); 00465 00466 // Allow user input 00467 keyAllowed = true; 00468 key = -1; 00469 00470 // Ready to proceed 00471 XBee.putc(true); 00472 00473 // Wait for player to select individual grid 00474 while (keyInputs[1] == -1) { 00475 wait(0.01); 00476 00477 // Read in the value through the XBee 00478 if (XBee.readable() == true) { 00479 key = XBee.getc(); 00480 keyInputs[1] = key; 00481 } 00482 } 00483 00484 int smallX = xGrid(); 00485 int smallY = yGrid(); 00486 00487 grid.smallGrid[largeX][largeY].individualGrid[smallX][smallY] = 0; 00488 drawSmallGrid(largeX, largeY, BLACK); 00489 drawSmallX(largeX, largeY, smallX, smallY); 00490 00491 key = -1; 00492 playSound("/sd/select.wav"); 00493 00494 // Check if player one has taken a small grid 00495 if (smallGridWin(largeX, largeY, smallX, smallY) == true) { 00496 grid.smallGrid[largeX][largeY].done = 0; 00497 drawLargeX(largeX, largeY); 00498 } else { 00499 bool draw = true; 00500 00501 for (int i = 0; i < 3; i++) { 00502 for (int j = 0; j < 3; j++) { 00503 if (grid.smallGrid[largeX][largeY].individualGrid[i][j] == (char)(-1)) { 00504 draw = false; 00505 } 00506 } 00507 } 00508 00509 if (draw == true) { 00510 grid.smallGrid[largeX][largeY].done = 128; 00511 } 00512 } 00513 00514 // Ready to proceed 00515 XBee.putc(true); 00516 // If it is player two's turn 00517 } else { 00518 RGB = BLUE; 00519 00520 // Allow user input 00521 keyAllowed = true; 00522 00523 int largeX = 0; 00524 int largeY = 0; 00525 00526 key = -1; 00527 00528 // Check if the other player is ready to proceed 00529 bool ready = false; 00530 00531 while (ready == false) { 00532 if (XBee.readable() == true) { 00533 ready = XBee.getc(); 00534 } 00535 } 00536 00537 // Wait for player to select small grid 00538 while ((keyInputs[0] == -1) || (grid.smallGrid[largeX][largeY].done != (char)(-1))) { 00539 wait(0.01); 00540 keyInputs[0] = key; 00541 largeX = xGrid(); 00542 largeY = yGrid(); 00543 } 00544 00545 // Send out the small grid value through the XBee 00546 XBee.putc(keyInputs[0]); 00547 00548 // Highlight selected grid 00549 drawSmallGrid(largeX, largeY, CYAN); 00550 00551 playSound("/sd/select.wav"); 00552 00553 // Allow user input 00554 keyAllowed = true; 00555 key = -1; 00556 00557 // Check if the other player is ready to proceed 00558 ready = false; 00559 00560 while (ready == false) { 00561 if (XBee.readable() == true) { 00562 ready = XBee.getc(); 00563 } 00564 } 00565 00566 wait(0.5); 00567 00568 // Wait for player to select individual grid 00569 while (keyInputs[1] == -1) { 00570 wait(0.01); 00571 00572 if (grid.smallGrid[largeX][largeY].individualGrid[xGrid()][yGrid()] == (char)(-1)) { 00573 keyInputs[1] = key; 00574 } 00575 } 00576 00577 // Send out the individual grid value through the XBee 00578 XBee.putc(keyInputs[1]); 00579 00580 int smallX = xGrid(); 00581 int smallY = yGrid(); 00582 00583 grid.smallGrid[largeX][largeY].individualGrid[smallX][smallY] = 1; 00584 drawSmallGrid(largeX, largeY, BLACK); 00585 drawSmallO(largeX, largeY, smallX, smallY); 00586 00587 key = -1; 00588 playSound("/sd/select.wav"); 00589 00590 // Check if player two has taken a small grid 00591 if (smallGridWin(largeX, largeY, smallX, smallY) == true) { 00592 grid.smallGrid[largeX][largeY].done = 1; 00593 drawLargeO(largeX, largeY); 00594 } else { 00595 bool draw = true; 00596 00597 for (int i = 0; i < 3; i++) { 00598 for (int j = 0; j < 3; j++) { 00599 if (grid.smallGrid[largeX][largeY].individualGrid[i][j] == (char)(-1)) { 00600 draw = false; 00601 } 00602 } 00603 } 00604 00605 if (draw == true) { 00606 grid.smallGrid[largeX][largeY].done = 128; 00607 } 00608 } 00609 00610 // Check if the other player is ready to proceed 00611 ready = false; 00612 00613 while (ready == false) { 00614 if (XBee.readable() == true) { 00615 ready = XBee.getc(); 00616 } 00617 } 00618 } 00619 } 00620 00621 // Draw final line when a player wins 00622 void drawLargeWinLine(int x1, int y1, int orientation) { 00623 int x2 = 127; 00624 int y2 = 127; 00625 00626 if (orientation == FORWARDSLASH) { 00627 x2 = 0; 00628 } else if (orientation == HORIZONTAL) { 00629 y2 = y1; 00630 } else if (orientation == VERTICAL) { 00631 x2 = x1; 00632 } 00633 00634 wait(1); 00635 uLCD.line(x1, y1, x2, y2, GREEN); 00636 wait(3); 00637 } 00638 00639 // Check whether a player has won 00640 void gameWin(bool turn) { 00641 bool won = false; 00642 char small[3][3]; 00643 00644 for (int i = 0; i < 3; i++) { 00645 for (int j = 0; j < 3; j++) { 00646 small[i][j] = grid.smallGrid[i][j].done; 00647 } 00648 } 00649 00650 int x1 = 2; 00651 int y1 = 2; 00652 int orientation = -1; 00653 00654 if ((small[0][0] == small[1][1]) && (small[1][1] == small[2][2]) && 00655 (small[0][0] != (char)(-1)) && (small[0][0] != 128)) { 00656 orientation = BACKWARDSLASH; 00657 won = true; 00658 } else if ((small[2][0] == small[1][1]) && (small[1][1] == small[0][2]) && 00659 (small[2][0] != (char)(-1)) && (small[2][0] != 128)) { 00660 orientation = FORWARDSLASH; 00661 x1 = 126; 00662 won = true; 00663 } else if ((small[0][0] == small[1][0]) && (small[1][0] == small[2][0]) && 00664 (small[0][0] != (char)(-1)) && (small[0][0] != 128)) { 00665 orientation = HORIZONTAL; 00666 y1 += 21; 00667 won = true; 00668 } else if ((small[0][1] == small[1][1]) && (small[1][1] == small[2][1]) && 00669 (small[0][1] != (char)(-1)) && (small[0][1] != 128)) { 00670 orientation = HORIZONTAL; 00671 y1 += 63; 00672 won = true; 00673 } else if ((small[0][2] == small[1][2]) && (small[1][2] == small[2][2]) && 00674 (small[0][2] != (char)(-1)) && (small[0][2] != 128)) { 00675 orientation = HORIZONTAL; 00676 y1 += 105; 00677 won = true; 00678 } else if ((small[0][0] == small[0][1]) && (small[0][1] == small[0][2]) && 00679 (small[0][0] != (char)(-1)) && (small[0][0] != 128)) { 00680 orientation = VERTICAL; 00681 x1 += 21; 00682 won = true; 00683 } else if ((small[1][0] == small[1][1]) && (small[1][1] == small[1][2]) && 00684 (small[1][0] != (char)(-1)) && (small[1][0] != 128)) { 00685 orientation = VERTICAL; 00686 x1 += 63; 00687 won = true; 00688 } else if ((small[2][0] == small[2][1]) && (small[2][1] == small[2][2]) && 00689 (small[2][0] != (char)(-1)) && (small[2][0] != 128)) { 00690 orientation = VERTICAL; 00691 x1 += 105; 00692 won = true; 00693 } else { 00694 orientation = -1; 00695 won = false; 00696 } 00697 00698 // Check to see if there is a draw 00699 if (won == false) { 00700 bool draw = true; 00701 00702 for (int i = 0; i < 3; i++) { 00703 for (int j = 0; j < 3; j++) { 00704 if (small[i][j] == (char)(-1)) { 00705 draw = false; 00706 } 00707 } 00708 } 00709 00710 if (draw == true) { 00711 grid.done = 128; 00712 wait(3); 00713 } 00714 } else { 00715 if (turn == false) { 00716 grid.done = 0; 00717 } else { 00718 grid.done = 1; 00719 } 00720 00721 drawLargeWinLine(x1, y1, orientation); 00722 } 00723 } 00724 };
Generated on Mon Aug 1 2022 07:20:13 by
1.7.2