Multi-game multiplayer arcade gaming system meant for the red X when playing Super Tic-Tac-Toe.

Dependencies:   uLCD_4DGL_SE PinDetect SDFileSystem mbed wave_player

Revision:
2:d35fde2d82cd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RedX.h	Fri Dec 04 23:03:08 2015 +0000
@@ -0,0 +1,717 @@
+/*******************************************************
+ * This header program declares all of the functions and
+ * variables used by the red X 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"
+
+
+// Smaller Super Tic_Tac_Toe grid structure
+struct smallGrid {
+    char individualGrid[3][3];
+    char done;
+};
+
+// Entire Super Tic_Tac_Toe grid structure
+struct largeGrid {
+    smallGrid smallGrid[3][3];
+    char done;
+};
+
+
+class RedX {
+    public:
+        // Player X constructor
+        RedX(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);
+        }
+
+        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("You win!");
+                playSound(WIN);
+            } else if (grid.done == 1) {
+                uLCD.printf("The other player\nwins.");
+                playSound(BOMB);
+            } 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, &RedX::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 red X.\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;
+
+                // 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, PINK);
+
+                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] = 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;
+                    }
+                }
+
+                // Check if the other player is ready to proceed
+                ready = false;
+
+                while (ready == false) {
+                    if (XBee.readable() == true) {
+                        ready = XBee.getc();
+                    }
+                }
+            // If it is player two's turn
+            } else {
+                RGB = BLUE;
+        
+                // 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, CYAN);
+
+                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] = 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;
+                    }
+                }
+
+                // Ready to proceed
+                XBee.putc(true);
+            }
+        }
+
+        // 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