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

RedX.h

Committer:
soapy12312
Date:
2015-12-04
Revision:
2:d35fde2d82cd

File content as of revision 2:d35fde2d82cd:

/*******************************************************
 * 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);
            }
        }
};