Lab 4 for ECE4180, final verison

Dependencies:   4DGL-uLCD-SE SDFileSystem mbed-rtos mbed wave_player

Fork of Lab4-Reversi-v2 by Emeril Huang

Overview

For our project, we created the 2 player game “Reversi”, otherwise known as Othello using the uLCD-144-G2, a Sparkfun 5-way Tactile Switch Joystick, a speaker with a Class D audio amp breakout board, and SD card reader. The program begins with the dark player’s turn, and the joystick is used to move the red cursor box around. Pressing down on the joystick will attempt to put a piece down, resulting in a flipping sound, and will show an X on the screen for invalid moves. The game will finish when the board is filled, and go to a result screen, playing a victory sound. The result screen allows for a play again option. /media/uploads/EvolutionOfWar/reversimbed.jpg

Components

Wiring

mbedCableuLCD
P28TXRX
P27RXTX
P29RESRESET
VU+5V+5V
GNDGNDGND
mbedSD Card Reader
P5DI
P6DO
P7SCK
P8CS
GNDGND
VoutVCC
mbedAmpliferSpeaker
P18In +
GNDGND
VUPWR +
Out ++
Out --
GNDPWR -
mbedJoystick
P14Up
P13Center
P12Left
P11Down
P10Right
GND-
Vout+

Program

Import programLab4-Reversi-Final

Lab 4 for ECE4180, final verison

Reversi.cpp

Committer:
aolmenki
Date:
2016-11-01
Revision:
3:b1fe86f61f2f
Parent:
2:1f7c6cc19a9a

File content as of revision 3:b1fe86f61f2f:

#include "mbed.h"
#include "uLCD_4DGL.h"
#include "SDFileSystem.h"
#include "wave_player.h"
#include "stdio.h"
uLCD_4DGL uLCD(p28, p27, p29); // create a global lcd object
SDFileSystem sd(p5, p6, p7, p8, "sd"); // the pinout on the mbed Cool Components workshop board
PwmOut Speaker(p21);
AnalogOut DACout(p18);

DigitalIn pb(p15);

wave_player waver(&DACout);

class Nav_Switch
{
public:
    Nav_Switch(PinName up,PinName down,PinName left,PinName right,PinName fire);
    int read();
//boolean functions to test each switch
    bool up();
    bool down();
    bool left();
    bool right();
    bool fire();
//automatic read on RHS
    operator int ();
//index to any switch array style
    bool operator[](int index) {
        return _pins[index];
    };
private:
    BusIn _pins;
 
};
Nav_Switch::Nav_Switch (PinName up,PinName down,PinName left,PinName right,PinName fire):
    _pins(up, down, left, right, fire)
{
    _pins.mode(PullUp); //needed if pullups not on board or a bare nav switch is used - delete otherwise
    wait(0.001); //delays just a bit for pullups to pull inputs high
}
inline bool Nav_Switch::up()
{
    return !(_pins[0]);
}
inline bool Nav_Switch::down()
{
    return !(_pins[1]);
}
inline bool Nav_Switch::left()
{
    return !(_pins[2]);
}
inline bool Nav_Switch::right()
{
    return !(_pins[3]);
}
inline bool Nav_Switch::fire()
{
    return !(_pins[4]);
}
inline int Nav_Switch::read()
{
    return _pins.read();
}
inline Nav_Switch::operator int ()
{
    return _pins.read();
}
 
Nav_Switch myNav( p14, p11, p12, p10, p13); //pin order on Sparkfun breakout
 
int turn = 1; // black goes on 1, white goes on 2 (or 0)
int gb[8][8];
int NUM_COLS = 8;
int NUM_ROWS = 8;
int xCoor = 3;
int yCoor = 4;
int numBlack = 0;
int numWhite = 0;
bool moved = false;
bool gameover = false;

void initialize_game_board()
{
    //This is a nested loop to make sure every cell is empty
    //Cell Codes: 0 = empty, 1 = white piece, 2 = black piece
    for (int i = 0; i < NUM_ROWS; i++)
    {
        for (int j = 0; j < NUM_COLS; j++)
        gb[i][j] = 0;
    }
    gb[3][3] = 1;//Put down white piece
    gb[4][4] = 1;//Put down white piece
    gb[3][4] = 2;//Put down black piece
    gb[4][3] = 2;//Put down black piece
    
    uLCD.cls();
    uLCD.filled_rectangle(0,0,127,127,0x007f00);
    
    uLCD.rectangle(7,7,120,120,DGREY);
    uLCD.rectangle(8,8,119,119,DGREY);
    //uLCD.filled_rectangle(8,20,120,21,DGREY);
    
    for( int i = 1; i< 9; i++)
    {
        uLCD.filled_rectangle(8, 7 + 14*i,119,8 + 14*i,DGREY);
    }
    for( int j = 1; j<9; j++)
    {
        uLCD.filled_rectangle(7 + 14*j, 8, 8+14*j, 119, DGREY);
    }
}

void drawCursor(int x, int y) //Expecting x ={0,7} and y ={0,7}
{
    uLCD.filled_rectangle(7 + 14*x, 7 + 14*y,8 + 14*x,22 + 14*y,RED);
    uLCD.filled_rectangle(7 + 14*x, 7 + 14*y,22 + 14*x,8 + 14*y,RED);
    uLCD.filled_rectangle(7 + 14*x, 21 + 14*y,22 + 14*x,22 + 14*y,RED);
    uLCD.filled_rectangle(21 + 14*x, 7 + 14*y,22 + 14*x,22 + 14*y,RED);
}
    
void removeCursor(int x,int y)
{
    uLCD.filled_rectangle(7 + 14*x, 7 + 14*y,8 + 14*x,22 + 14*y,DGREY);
    uLCD.filled_rectangle(7 + 14*x, 7 + 14*y,22 + 14*x,8 + 14*y,DGREY);
    uLCD.filled_rectangle(7 + 14*x, 21 + 14*y,22 + 14*x,22 + 14*y,DGREY);
    uLCD.filled_rectangle(21 + 14*x, 7 + 14*y,22 + 14*x,22 + 14*y,DGREY);
}

void drawPieces(){
    for (int i = 0; i < NUM_ROWS; i++)
    {
        for (int j = 0; j < NUM_COLS; j++)
        {
            if(gb[i][j] == 0){
                uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 5 , 0x007f00);
            }
            if(gb[i][j] == 1){
                uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 5 , WHITE);
            }
            if(gb[i][j] == 2){
                uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 5 , BLACK);
            }
        }
    }
}

void drawPiece(int i, int j) { //xCoor, yCoor
    if (turn == 0) {
        gb[i][j] = 1;
    } else {
        gb[i][j] = 2;
    }
    if(gb[i][j] == 1){
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 5 , WHITE);
    }
    if(gb[i][j] == 2){
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 5 , BLACK);
    }
}

void flippingPiece(int i, int j) { //xCoor, yCoor, animation
    
    if(gb[i][j] == 2){ //Gradually changes a piece White
        gb[i][j] = 1;
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 1 , 0x4c4c4c);
        wait(0.1);
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 1 , 0xb2b2b2);
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 3 , 0x4c4c4c);
        wait(0.1);
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 1 , 0xffffff);
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 3 , 0xb2b2b2);
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 5 , 0x4c4c4c);
        wait(0.1);
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 3 , 0xffffff);
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 5 , 0xb2b2b2);
        wait(0.1);
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 5 , 0xffffff);
        wait(0.1);
    } else if(gb[i][j] == 1){ //Gradually changes a piece Black
        gb[i][j] = 2;
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 1 , 0xb2b2b2);
        wait(0.1);
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 1 , 0x4c4c4c);
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 3 , 0xb2b2b2);
        wait(0.1);
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 1 , 0x000000);
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 3 , 0x4c4c4c);
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 5 , 0xb2b2b2);
        wait(0.1);
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 3 , 0x000000);
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 5 , 0x4c4c4c);
        wait(0.1);
        uLCD.filled_circle(14 * (i + 1), 14 * (j + 1), 5 , 0x000000);
        wait(0.1);
    }  
}


void invalid(int x, int y, int oldColor){
    gb[x][y] = oldColor;
    drawPieces();
    uLCD.line(9 + 14 * xCoor, 11+ 14 * yCoor, 11+ 14 * xCoor, 9+ 14 * yCoor, RED);
    uLCD.line(11+ 14 * xCoor, 9+ 14 * yCoor, 20+ 14 * xCoor, 18+ 14 * yCoor, RED);
    uLCD.line(20+ 14 * xCoor, 18+ 14 * yCoor, 18+ 14 * xCoor, 20+ 14 * yCoor, RED);
    uLCD.line(18+ 14 * xCoor, 20+ 14 * yCoor, 9+ 14 * xCoor, 11+ 14 * yCoor, RED);
    uLCD.line(9+ 14 * xCoor, 18+ 14 * yCoor, 18+ 14 * xCoor, 9+ 14 * yCoor, RED);
    uLCD.line(18+ 14 * xCoor, 9+ 14 * yCoor, 20+ 14 * xCoor, 11+ 14 * yCoor, RED);
    uLCD.line(20+ 14 * xCoor, 11+ 14 * yCoor, 11+ 14 * xCoor, 20+ 14 * yCoor, RED);
    uLCD.line(11+ 14 * xCoor, 20+ 14 * yCoor, 9+ 14 * xCoor, 18+ 14 * yCoor, RED);
    wait(1);
    uLCD.line(9 + 14 * xCoor, 11+ 14 * yCoor, 11+ 14 * xCoor, 9+ 14 * yCoor, 0x007F00);
    uLCD.line(11+ 14 * xCoor, 9+ 14 * yCoor, 20+ 14 * xCoor, 18+ 14 * yCoor, 0x007F00);
    uLCD.line(20+ 14 * xCoor, 18+ 14 * yCoor, 18+ 14 * xCoor, 20+ 14 * yCoor, 0x007F00);
    uLCD.line(18+ 14 * xCoor, 20+ 14 * yCoor, 9+ 14 * xCoor, 11+ 14 * yCoor, 0x007F00);
    uLCD.line(9+ 14 * xCoor, 18+ 14 * yCoor, 18+ 14 * xCoor, 9+ 14 * yCoor, 0x007F00);
    uLCD.line(18+ 14 * xCoor, 9+ 14 * yCoor, 20+ 14 * xCoor, 11+ 14 * yCoor, 0x007F00);
    uLCD.line(20+ 14 * xCoor, 11+ 14 * yCoor, 11+ 14 * xCoor, 20+ 14 * yCoor, 0x007F00);
    uLCD.line(11+ 14 * xCoor, 20+ 14 * yCoor, 9+ 14 * xCoor, 18+ 14 * yCoor, 0x007F00);
    drawPieces();
}

void valid_move(int x, int y) {
    int opp, pl;
    bool invalidD[] = {false, false, false, false, false, false, false, false}; //flip checker
    if (turn == 1) { //pl is black
        opp = 1;
        pl = 2;
    } else { // pl is white
        opp = 2;
        pl = 1;
    }
    int oldColor = gb[x][y]; //save old color for drawing over X
    bool flipped = false;
    if (gb[x][y] == 0) { // check empty space
        drawPiece(x, y); // emtpy so draw
        for (int i = 0; i < 8; i++) { // check for opponent around emtpy space and fill
            if (i == 0) { // right
                if (x + 1 < 7 && gb[x + 1][y] == opp) { //check to see if not beyond board and has to be next to the opponent
                    for (int j = x + 2; j < 8  && !flipped; j++) {
                        if (gb[j][y] == pl) {
                            for (int k = x + 1; k < j; k++) {
                                flippingPiece(k, y);
                            }
                            flipped = true;
                        } else if (gb[j][y] == 0) {
                            j = 8;
                        }
                    }
                    if (flipped) {
                        flipped = false;
                    } else {
                        invalidD[0] = true;
                    }
                } else {
                    invalidD[0] = true;
                }
            } else if (i == 1) { // down-right
                if (x + 1 < 7 && y + 1 < 7 && gb[x + 1][y + 1] == opp) { // check if within margin and next to other color
                    for (int j = 2; j < 8 - x && j < 8 - y && !flipped; j++) { // start finding next same color
                        if (gb[x + j][y + j] == pl) { // if same color and not already been flipping
                            for (int k = 1; k < j; k++) { // between other color to this same color
                                flippingPiece(x + k, y + k); // flip
                            }
                            flipped = true; // marked flipped
                        } else if (gb[x + j][y + j] == 0) { // if you find an empty instead
                            j = 8; // skip for loop
                        }
                    }
                    if (flipped) { // if flipped
                        flipped = false; // set variable back to false
                    } else {
                        invalidD[1] = true; // no flip happened, so set invalid tracker to true
                    }
                } else {
                    invalidD[1] = true; // not within margin or next to other color
                }
            } else if (i == 2) { // down
                if (y + 1 < 7 && gb[x][y + 1] == opp) {
                    for (int j = y + 2; j < 8 && !flipped; j++) {
                        if (gb[x][j] == pl) {
                            for (int k = y + 1; k < j; k++) {
                                flippingPiece(x, k);
                            }
                            flipped = true;
                        } else if (gb[x][j] == 0) {
                            j = 8;
                        }
                    }
                    if (flipped) {
                        flipped = false;
                    } else {
                        invalidD[2] = true;
                    }
                } else {
                    invalidD[2] = true;
                }
            } else if (i == 3) { // down-left
                if (x - 1 > 0 && y + 1 < 7 && gb[x - 1][y + 1] == opp) {
                    for (int j = 2; j < x + 1 && j < 8 - y && !flipped; j++) {
                        if (gb[x - j][y + j] == pl) {
                            for (int k = 1; k < j; k++) {
                                flippingPiece(x - k, y + k);
                            }
                            flipped = true;
                        } else if (gb[x - j][y + j] == 0) {
                            j = 5;
                        }
                    }
                    if (flipped) {
                        flipped = false;
                    } else {
                        invalidD[3] = true;
                    }
                } else {
                    invalidD[3] = true;
                }
            } else if (i == 4) { // left
                if (x - 1 > 0 && gb[x - 1][y] == opp) {
                    for (int j = x - 2; j > -1 && !flipped; j--) {
                        if (gb[j][y] == pl) {
                            for (int k = x - 1; k > j; k--) {
                                flippingPiece(k, y);
                            }
                            flipped = true;
                        } else if (gb[j][y] == 0) {
                            j = -1;
                        }
                    }
                    if (flipped) {
                        flipped = false;
                    } else {
                        invalidD[4] = true;
                    }
                } else {
                    invalidD[4] = true;
                }
            } else if (i == 5) { // up-left
                if (x - 1 > 0 && y - 1 > 0 && gb[x - 1][y - 1] == opp) {
                    for (int j = 2; j < x + 1 && j < y + 1 && !flipped; j++) {
                        if (gb[x - j][y - j] == pl) {
                            for (int k = 1; k < j; k++) {
                                flippingPiece(x - k, y - k);
                            }
                            flipped = true;
                        } else if (gb[x - j][y - j] == 0) {
                            j = x + 1;
                        }
                    }
                    if (flipped) {
                        flipped = false;
                    } else {
                        invalidD[5] = true;
                    }
                } else {
                    invalidD[5] = true;
                }
            } else if (i == 6) { // up
                if (y - 1 > 0 && gb[x][y - 1] == opp) {
                    for (int j = y - 2; j > -1 && !flipped; j--) {
                        if (gb[x][j] == pl) {
                            for (int k = y - 1; k > j; k--) {
                                flippingPiece(x, k);
                            }
                            flipped = true;
                        } else if (gb[x][j] == 0) {
                            j = -1;
                        }
                    }
                    if (flipped) {
                        flipped = false;
                    } else {
                        invalidD[6] = true;
                    }
                } else {
                    invalidD[6] = true;
                }
            } else if (i == 7) { // up-right
                if (x + 1 < 7 && y - 1 > 0 && gb[x + 1][y - 1] == opp) {
                    for (int j = 2; j < 8 - x && j < y + 1 && !flipped; j++) {
                        if (gb[x + j][y - j] == pl) {
                            for (int k = 1; k < j; k++) {
                                flippingPiece(x + k, y - k);
                            }
                            flipped = true;
                        } else if (gb[x + j][y - j] == 0) {
                            j = 8 - x;
                        }
                    }
                    if (flipped) {
                        flipped = false;
                    } else {
                        invalidD[7] = true;
                    }
                } else {
                    invalidD[7] = true;
                }
            }
        } // finish checking around
        flipped = false;
        for (int i = 0; i < 8; i++) {
            if (!invalidD[i] && !flipped) { // if a move is found, and only once
                moved = true; // has moved
                turn = ++turn%2; // increment turn
                flipped = true; // check flip
                
                FILE *fp2 = fopen("/sd/wavfiles/FlipSound.wav", "r");
                if(fp2 == NULL) {
                error("Could not open file for read\n");
                }
                Speaker.period(1.0/400000.0);
                waver.play(fp2); //Plays *.wav audio file
                fclose(fp2);
            }
        }
        if (!flipped) { // no changes were made
            invalid(x, y, oldColor); // change back to old color and revert changes
        }
    } else { //invalid
        invalid(x, y, oldColor); // not empty space
    }
}


void countPieces()
{
    numBlack = 0;
    numWhite = 0;
    for(int row = 0; row < 8; row++){
        for(int col = 0; col < 8; col++){
            if(gb[row][col]==2)
            {
                numBlack++;
            }
            if(gb[row][col]==1)
            {
                numWhite++;
            }
        }
    } 
}
void result() {
    uLCD.cls(); // THIS CODE ASSUMES BACKGROUND CORRECTLY RESETS TO 0x007F00
    uLCD.filled_rectangle(0,0,127,127,0x007f00);
    
    FILE *fp1 = fopen("/sd/wavfiles/Victory.wav", "r");
    if(fp1 == NULL) {
        error("Could not open file for read\n");
    }
    Speaker.period(1.0/400000.0);
    waver.play(fp1); //Plays *.wav audio file
    fclose(fp1);
    countPieces();
    uLCD.textbackground_color(0x007f00);
    uLCD.color(RED);
    uLCD.printf("Score\n");
    uLCD.color(BLACK);
    uLCD.printf("%d", numBlack);
    uLCD.color(RED);
    uLCD.printf(" - ");
    uLCD.color(WHITE);
    uLCD.printf("%D \n", numWhite);
    uLCD.color(RED);
    uLCD.printf("\n Play again? \n");
    
    uLCD.text_char('Y', 8, 9, BLUE);
    uLCD.text_char('E', 9, 9, BLUE);
    uLCD.text_char('S', 10, 9, BLUE);
    
    bool optionSelected = false;
    while(optionSelected == false){
        if(myNav[4] == 0){ //Joystick pressed to Select
            //Restart and play again
            initialize_game_board();
            drawPieces();
            xCoor = 3;
            yCoor = 4;
            optionSelected = true;
        }       
    } 
}

int main() {
    pb.mode(PullUp);
    while (1) {
       
        initialize_game_board();
        drawPieces();
        while(!gameover) { //active game, checks game over
            while (!moved) {
                drawCursor(xCoor, yCoor);
                wait(0.02);
                removeCursor(xCoor, yCoor);
                //with pullups a button hit is a "0" - "~" inverts data to leds
                //~(myNav & 0x0F); //update leds with nav switch direction inputs
                if(myNav[0] == 0 && xCoor != 0){xCoor --;}
                if(myNav[1] == 0 && xCoor != 7){xCoor ++;}
                if(myNav[2] == 0 && yCoor != 7){yCoor ++;}
                if(myNav[3] == 0 && yCoor != 0){yCoor --;}
                if(myNav.fire()) {valid_move(xCoor, yCoor);} // Press Down Joystick for Select
                //or use - if(myNav[4]==0) mbedleds = 0x0F; //can index a switch bit like this
                if (pb == 0) {
                    result();
                }
            }
            moved = false;
            // check game over
            countPieces();
            gameover = (numBlack + numWhite == 64 || gameover);
        }
        result();
    }
}
//initializeBoard();
//drawBoard();
//displayScore();