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