Multi-game multiplayer arcade gaming system meant for the blue O when playing Super Tic-Tac-Toe.
Dependencies: 4DGL-uLCD-SE PinDetect SDFileSystem mbed wave_player
Diff: BlueO.h
- Revision:
- 2:da0f01fbd25c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BlueO.h Fri Dec 04 23:00:42 2015 +0000 @@ -0,0 +1,724 @@ +/******************************************************* + * This header program declares all of the functions and + * variables used by the blue O player in Super + * Tic-Tac-Toe. + *******************************************************/ + + +#define FORWARDSLASH 0 +#define BACKWARDSLASH 1 +#define VERTICAL 2 +#define HORIZONTAL 3 +#define BOMB "/sd/wavfiles/bomb.wav" +#define WIN "/sd/win.wav" +#define MEH "/sd/Meh.wav" + + +/******************************************************* + * This structure is used to represent the individual + * blocks within a small grid. + *******************************************************/ +struct smallGrid { + char individualGrid[3][3]; + char done; +}; + +/******************************************************* + * This structure is used to represent the small + * blocks within the whole grid. + *******************************************************/ +struct largeGrid { + smallGrid smallGrid[3][3]; + char done; +}; + + +class BlueO { + public: + // Player O constructor + BlueO(DigitalOut &reset, InterruptIn &input, Mpr121 &MPR121, RGBLED &RGB, SDFileSystem &sd, Serial &XBee, uLCD_4DGL &uLCD, wave_player &waver) : + reset(reset), input(input), MPR121(MPR121), RGB(RGB), sd(sd), XBee(XBee), uLCD(uLCD), waver(waver) { + uLCD.baudrate(MAXBAUDRATE); + key = -1; + + // Set up XBee + reset = 0; + wait(0.001); + reset = 1; + wait(0.001); + } + + // Play the game + void playSuperTicTacToe() { + initializeInterrupt(); + displayInstructions(); + initializeGrid(); + + XBee.putc(true); + bool readyToPlay = false; + bool print = true; + + while (readyToPlay == false) { + if (XBee.readable() == true) { + readyToPlay = XBee.getc(); + print = false; + } + + if (print == true) { + uLCD.cls(); + uLCD.printf("Waiting for other player..."); + print = false; + } + } + + uLCD.cls(); + drawStage(); + + // False: player one's turn; true: player two's turn + bool turn = true; + + // Loop through the game + while (grid.done == (char)(-1)) { + turn = !turn; + takeTurn(turn); + gameWin(turn); + } + + uLCD.cls(); + + if (grid.done == 0) { + uLCD.printf("The other player\nwins."); + playSound(BOMB); + } else if (grid.done == 1) { + uLCD.printf("You win!"); + playSound(WIN); + } else if (grid.done == 128) { + uLCD.printf("It's a draw!"); + playSound(MEH); + } + + wait(3); + uLCD.cls(); + } + + + private: + DigitalOut &reset; + InterruptIn &input; + Mpr121 &MPR121; + RGBLED &RGB; + SDFileSystem &sd; + Serial &XBee; + uLCD_4DGL &uLCD; + wave_player &waver; + bool keyAllowed; + volatile int key; + largeGrid grid; + + // Initialize the interrupt + void initializeInterrupt() { + input.fall(this, &BlueO::keyInterrupt); + wait(0.01); + input.mode(PullUp); + wait(0.01); + } + + // Determine value of the key pressed + void keyInterrupt() { + if (keyAllowed == true) { + int value = MPR121.read(0x00); + value += MPR121.read(0x01) << 8; + + for (int i = 0; i < 12; i++) { + if (((value >> i) & 0x01) == 1) { + key = i; + } + } + + // Ununsed keys + if ((key == 3) || (key == 7) || (key == 11)) { + key = -1; + } + } else { + key = -1; + } + } + + // Initialize the grid + void initializeGrid() { + grid.done = (char)(-1); + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + grid.smallGrid[i][j].done = (char)(-1); + + for (int k = 0; k < 3; k++) { + for (int l = 0; l < 3; l++) { + grid.smallGrid[i][j].individualGrid[k][l] = (char)(-1); + } + } + } + } + } + + // Display instructions + void displayInstructions() { + uLCD.printf("Hello, and welcome"); + uLCD.printf("to a game of Super"); + uLCD.printf("Tic-Tac-Toe. Use "); + uLCD.printf("the bottom three "); + uLCD.printf("rows of the touch "); + uLCD.printf("keypad to select "); + uLCD.printf("the large grid "); + uLCD.printf("followed by the "); + uLCD.printf("small grid. You "); + uLCD.printf("are the blue O.\n\n"); + uLCD.printf("Press any key to "); + uLCD.printf("begin playing."); + wait(0.1); + + key = -1; + keyAllowed = true; + + while (key == -1) { + wait(0.01); + } + + key = -1; + uLCD.cls(); + } + + // Play a sound file + void playSound(char *wav) { + // Open sound file + FILE *wave_file; + wave_file = fopen(wav, "r"); + + // Play wav file + waver.play(wave_file); + + // Close wav file + fclose(wave_file); + } + + // Draw the stage + void drawStage() { + for (int i = 15; i < 120; i += 14) { + uLCD.line(i, 2, i, 127, YELLOW); + uLCD.line(2, i, 127, i, YELLOW); + } + + for (int i = 43; i < 120; i += 42) { + uLCD.line(i, 2, i, 127, WHITE); + uLCD.line(2, i, 127, i, WHITE); + } + } + + // Draw small X + void drawSmallX(int largeX, int largeY, int smallX, int smallY) { + int xCoordinate = 1 + (largeX * 42) + (smallX * 14) + 7; + int yCoordinate = 1 + (largeY * 42) + (smallY * 14) + 7; + + int x1 = xCoordinate - 6; + int x2 = xCoordinate + 6; + int y1 = yCoordinate - 6; + int y2 = yCoordinate + 6; + + uLCD.line(x1 + 1, y1 + 1, x2, y2, RED); + uLCD.line(x1 + 1, y2 - 1, x2, y1, RED); + } + + // Draw small O + void drawSmallO(int largeX, int largeY, int smallX, int smallY) { + int xCoordinate = 1 + (largeX * 42) + (smallX * 14) + 7; + int yCoordinate = 1 + (largeY * 42) + (smallY * 14) + 7; + + uLCD.circle(xCoordinate, yCoordinate, 5, BLUE); + } + + // Draw large X + void drawLargeX(int largeX, int largeY) { + int xCoordinate = 1 + (largeX * 42) + 21; + int yCoordinate = 1 + (largeY * 42) + 21; + + int x1 = xCoordinate - 20; + int x2 = xCoordinate + 20; + int y1 = yCoordinate - 20; + int y2 = yCoordinate + 20; + + uLCD.filled_rectangle(x1, y1, x2, y2, BLACK); + + uLCD.line(x1 + 1, y1 + 1, x2, y2, RED); + uLCD.line(x1 + 1, y2 - 1, x2, y1, RED); + } + + // Draw large O + void drawLargeO(int largeX, int largeY) { + int xCoordinate = 1 + (largeX * 42) + 21; + int yCoordinate = 1 + (largeY * 42) + 21; + + int x1 = xCoordinate - 20; + int x2 = xCoordinate + 20; + int y1 = yCoordinate - 20; + int y2 = yCoordinate + 20; + + uLCD.filled_rectangle(x1, y1, x2, y2, BLACK); + + uLCD.circle(xCoordinate, yCoordinate, 19, BLUE); + } + + // Find x-coordinate based on key input + int xGrid() { + int x; + + if ((key == 0) || (key == 1) || (key == 2)) { + x = 0; + } else if ((key == 4) || (key == 5) || (key == 6)) { + x = 1; + } else if ((key == 8) || (key == 9) || (key == 10)) { + x = 2; + } else { + x = -1; + } + + return x; + } + + // Find y-coordinate based on key input + int yGrid() { + int y; + + if ((key == 2) || (key == 6) || (key == 10)) { + y = 0; + } else if ((key == 1) || (key == 5) || (key == 9)) { + y = 1; + } else if ((key == 0) || (key == 4) || (key == 8)) { + y = 2; + } else { + y = -1; + } + + return y; + } + + // Display a certain small grid in a set color + void drawSmallGrid(int x, int y, int color) { + int x1 = 1 + (x * 42) + 1; + int x2 = x1 + 40; + int y1 = 1 + (y * 42) + 1; + int y2 = y1 + 40; + + for (int i = x1; i < x2; i += 14) { + for (int j = y1; j < y2; j += 14) { + uLCD.filled_rectangle(i, j, i + 12, j + 12, color); + } + } + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (grid.smallGrid[x][y].individualGrid[i][j] == 0) { + drawSmallX(x, y, i, j); + } else if (grid.smallGrid[x][y].individualGrid[i][j] == 1) { + drawSmallO(x, y, i, j); + } + } + } + } + + // Draw a line if a player takes a small grid + void drawSmallWinLine(int x1, int y1, int orientation) { + int x2 = x1; + int y2 = y1; + + if (orientation == FORWARDSLASH) { + x2 = x1 - 41; + y2 = y1 + 41; + } else if (orientation == BACKWARDSLASH) { + x2 = x1 + 41; + y2 = y1 + 41; + } else if (orientation == VERTICAL) { + y2 = y1 + 41; + } else if (orientation == HORIZONTAL) { + x2 = x1 + 41; + } + + uLCD.line(x1, y1, x2, y2, GREEN); + wait(1); + } + + // Check whether a player has taken a small grid + bool smallGridWin(int largeX, int largeY, int smallX, int smallY) { + bool taken = false; + char individual[3][3]; + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + individual[i][j] = grid.smallGrid[largeX][largeY].individualGrid[i][j]; + } + } + + int x1 = 1 + (largeX * 42) + 1; + int y1 = 1 + (largeY * 42) + 1; + int orientation = -1; + + if ((individual[0][0] == individual[1][1]) && (individual[1][1] == individual[2][2]) && + (individual[0][0] != (char)(-1))) { + orientation = BACKWARDSLASH; + taken = true; + } else if ((individual[2][0] == individual[1][1]) && (individual[1][1] == individual[0][2]) && + (individual[2][0] != (char)(-1))) { + orientation = FORWARDSLASH; + x1 += 40; + taken = true; + } else if ((individual[0][0] == individual[1][0]) && (individual[1][0] == individual[2][0]) && + (individual[0][0] != (char)(-1))) { + orientation = HORIZONTAL; + y1 += 6; + taken = true; + } else if ((individual[0][1] == individual[1][1]) && (individual[1][1] == individual[2][1]) && + (individual[0][1] != (char)(-1))) { + orientation = HORIZONTAL; + y1 += 20; + taken = true; + } else if ((individual[0][2] == individual[1][2]) && (individual[1][2] == individual[2][2]) && + (individual[0][2] != (char)(-1))) { + orientation = HORIZONTAL; + y1 += 34; + taken = true; + } else if ((individual[0][0] == individual[0][1]) && (individual[0][1] == individual[0][2]) && + (individual[0][0] != (char)(-1))) { + orientation = VERTICAL; + x1 += 6; + taken = true; + } else if ((individual[1][0] == individual[1][1]) && (individual[1][1] == individual[1][2]) && + (individual[1][0] != (char)(-1))) { + orientation = VERTICAL; + x1 += 20; + taken = true; + } else if ((individual[2][0] == individual[2][1]) && (individual[2][1] == individual[2][2]) && + (individual[2][0] != (char)(-1))) { + orientation = VERTICAL; + x1 += 34; + taken = true; + } else { + orientation = -1; + taken = false; + } + + // Check to see if there is a draw + if (taken == false) { + bool draw = true; + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (individual[i][j] != (char)(-1)) { + draw = false; + } + } + } + + if (draw == true) { + grid.smallGrid[largeX][largeY].done = 128; + } + } + + drawSmallWinLine(x1, y1, orientation); + + return taken; + } + + // Take a turn + void takeTurn(bool turn) { + // Player selects small grid, then individual grid + int keyInputs[2] = {-1, -1}; + + // If it is player one's turn + if (turn == false) { + RGB = RED; + + // Allow user input + keyAllowed = true; + + int largeX = 0; + int largeY = 0; + + key = -1; + + // Ready to proceed + XBee.putc(true); + + // Wait for player to select small grid + while ((keyInputs[0] == -1) || (grid.smallGrid[largeX][largeY].done != (char)(-1))) { + // Read in the value through the XBee + if (XBee.readable() == true) { + key = XBee.getc(); + keyInputs[0] = key; + largeX = xGrid(); + largeY = yGrid(); + } + } + + // Highlight selected grid + drawSmallGrid(largeX, largeY, PINK); + + playSound("/sd/select.wav"); + + // Allow user input + keyAllowed = true; + key = -1; + + // Ready to proceed + XBee.putc(true); + + // Wait for player to select individual grid + while (keyInputs[1] == -1) { + wait(0.01); + + // Read in the value through the XBee + if (XBee.readable() == true) { + key = XBee.getc(); + keyInputs[1] = key; + } + } + + int smallX = xGrid(); + int smallY = yGrid(); + + grid.smallGrid[largeX][largeY].individualGrid[smallX][smallY] = 0; + drawSmallGrid(largeX, largeY, BLACK); + drawSmallX(largeX, largeY, smallX, smallY); + + key = -1; + playSound("/sd/select.wav"); + + // Check if player one has taken a small grid + if (smallGridWin(largeX, largeY, smallX, smallY) == true) { + grid.smallGrid[largeX][largeY].done = 0; + drawLargeX(largeX, largeY); + } else { + bool draw = true; + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (grid.smallGrid[largeX][largeY].individualGrid[i][j] == (char)(-1)) { + draw = false; + } + } + } + + if (draw == true) { + grid.smallGrid[largeX][largeY].done = 128; + } + } + + // Ready to proceed + XBee.putc(true); + // If it is player two's turn + } else { + RGB = BLUE; + + // Allow user input + keyAllowed = true; + + int largeX = 0; + int largeY = 0; + + key = -1; + + // Check if the other player is ready to proceed + bool ready = false; + + while (ready == false) { + if (XBee.readable() == true) { + ready = XBee.getc(); + } + } + + // Wait for player to select small grid + while ((keyInputs[0] == -1) || (grid.smallGrid[largeX][largeY].done != (char)(-1))) { + wait(0.01); + keyInputs[0] = key; + largeX = xGrid(); + largeY = yGrid(); + } + + // Send out the small grid value through the XBee + XBee.putc(keyInputs[0]); + + // Highlight selected grid + drawSmallGrid(largeX, largeY, CYAN); + + playSound("/sd/select.wav"); + + // Allow user input + keyAllowed = true; + key = -1; + + // Check if the other player is ready to proceed + ready = false; + + while (ready == false) { + if (XBee.readable() == true) { + ready = XBee.getc(); + } + } + + wait(0.5); + + // Wait for player to select individual grid + while (keyInputs[1] == -1) { + wait(0.01); + + if (grid.smallGrid[largeX][largeY].individualGrid[xGrid()][yGrid()] == (char)(-1)) { + keyInputs[1] = key; + } + } + + // Send out the individual grid value through the XBee + XBee.putc(keyInputs[1]); + + int smallX = xGrid(); + int smallY = yGrid(); + + grid.smallGrid[largeX][largeY].individualGrid[smallX][smallY] = 1; + drawSmallGrid(largeX, largeY, BLACK); + drawSmallO(largeX, largeY, smallX, smallY); + + key = -1; + playSound("/sd/select.wav"); + + // Check if player two has taken a small grid + if (smallGridWin(largeX, largeY, smallX, smallY) == true) { + grid.smallGrid[largeX][largeY].done = 1; + drawLargeO(largeX, largeY); + } else { + bool draw = true; + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (grid.smallGrid[largeX][largeY].individualGrid[i][j] == (char)(-1)) { + draw = false; + } + } + } + + if (draw == true) { + grid.smallGrid[largeX][largeY].done = 128; + } + } + + // Check if the other player is ready to proceed + ready = false; + + while (ready == false) { + if (XBee.readable() == true) { + ready = XBee.getc(); + } + } + } + } + + // Draw final line when a player wins + void drawLargeWinLine(int x1, int y1, int orientation) { + int x2 = 127; + int y2 = 127; + + if (orientation == FORWARDSLASH) { + x2 = 0; + } else if (orientation == HORIZONTAL) { + y2 = y1; + } else if (orientation == VERTICAL) { + x2 = x1; + } + + wait(1); + uLCD.line(x1, y1, x2, y2, GREEN); + wait(3); + } + + // Check whether a player has won + void gameWin(bool turn) { + bool won = false; + char small[3][3]; + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + small[i][j] = grid.smallGrid[i][j].done; + } + } + + int x1 = 2; + int y1 = 2; + int orientation = -1; + + if ((small[0][0] == small[1][1]) && (small[1][1] == small[2][2]) && + (small[0][0] != (char)(-1)) && (small[0][0] != 128)) { + orientation = BACKWARDSLASH; + won = true; + } else if ((small[2][0] == small[1][1]) && (small[1][1] == small[0][2]) && + (small[2][0] != (char)(-1)) && (small[2][0] != 128)) { + orientation = FORWARDSLASH; + x1 = 126; + won = true; + } else if ((small[0][0] == small[1][0]) && (small[1][0] == small[2][0]) && + (small[0][0] != (char)(-1)) && (small[0][0] != 128)) { + orientation = HORIZONTAL; + y1 += 21; + won = true; + } else if ((small[0][1] == small[1][1]) && (small[1][1] == small[2][1]) && + (small[0][1] != (char)(-1)) && (small[0][1] != 128)) { + orientation = HORIZONTAL; + y1 += 63; + won = true; + } else if ((small[0][2] == small[1][2]) && (small[1][2] == small[2][2]) && + (small[0][2] != (char)(-1)) && (small[0][2] != 128)) { + orientation = HORIZONTAL; + y1 += 105; + won = true; + } else if ((small[0][0] == small[0][1]) && (small[0][1] == small[0][2]) && + (small[0][0] != (char)(-1)) && (small[0][0] != 128)) { + orientation = VERTICAL; + x1 += 21; + won = true; + } else if ((small[1][0] == small[1][1]) && (small[1][1] == small[1][2]) && + (small[1][0] != (char)(-1)) && (small[1][0] != 128)) { + orientation = VERTICAL; + x1 += 63; + won = true; + } else if ((small[2][0] == small[2][1]) && (small[2][1] == small[2][2]) && + (small[2][0] != (char)(-1)) && (small[2][0] != 128)) { + orientation = VERTICAL; + x1 += 105; + won = true; + } else { + orientation = -1; + won = false; + } + + // Check to see if there is a draw + if (won == false) { + bool draw = true; + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (small[i][j] == (char)(-1)) { + draw = false; + } + } + } + + if (draw == true) { + grid.done = 128; + wait(3); + } + } else { + if (turn == false) { + grid.done = 0; + } else { + grid.done = 1; + } + + drawLargeWinLine(x1, y1, orientation); + } + } +}; \ No newline at end of file