Lab 4 for ECE4180, final verison
Dependencies: 4DGL-uLCD-SE SDFileSystem mbed-rtos mbed wave_player
Fork of Lab4-Reversi-v2 by
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.
Components
- /users/4180_1/notebook/using-a-navigation-switch-digital-joystick/
- /users/4180_1/notebook/ulcd-144-g2-128-by-128-color-lcd/
- /users/4180_1/notebook/using-a-speaker-for-audio-output/
- /cookbook/SD-Card-File-System
Wiring
mbed | Cable | uLCD |
---|---|---|
P28 | TX | RX |
P27 | RX | TX |
P29 | RES | RESET |
VU | +5V | +5V |
GND | GND | GND |
mbed | SD Card Reader |
---|---|
P5 | DI |
P6 | DO |
P7 | SCK |
P8 | CS |
GND | GND |
Vout | VCC |
mbed | Amplifer | Speaker |
---|---|---|
P18 | In + | |
GND | GND | |
VU | PWR + | |
Out + | + | |
Out - | - | |
GND | PWR - |
mbed | Joystick |
---|---|
P14 | Up |
P13 | Center |
P12 | Left |
P11 | Down |
P10 | Right |
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();