Chess game on the mbed.
Dependencies: 4DGL-uLCD-SE PinDetect SDFileSystem mbed
main.cpp
- Committer:
- mbavare
- Date:
- 2016-03-14
- Revision:
- 1:af3a896cd76d
- Parent:
- 0:a5f9535b6e3d
File content as of revision 1:af3a896cd76d:
#include "mbed.h" #include "uLCD_4DGL.h" #include "SDFileSystem.h" #include <algorithm> #include "PinDetect.h" #include "Speaker.h" uLCD_4DGL uLCD(p28,p27,p29); // serial tx, serial rx, reset pin; //bluetooth for the player two controller Serial blue(p13,p14); //serial tx, rx //Using the speaker as a pwm out Speaker mySpeaker(p21); //set up the chess board as an int array int board[8][8]={0}; //Set the pieces so we can refer to them by name const int pawn=1; const int rook=2; const int knight=3; const int bishop=4; const int queen=5; const int king=6; //global variables to keep track of the current player and the winner int winner = 0; int current_player = 1; //class declaration for the navswitch 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 p1( p9, p6, p7, p5, p8); //pin order on Sparkfun breakout //set the MBED leds up to signal information DigitalOut myLed1(LED1); DigitalOut myLed2(LED2); DigitalOut myLed3(LED3); DigitalOut myLed4(LED4); //functions for drawing the different chess pieces using uLCD member functions void drawPawn(int x, int y, int Color) { uLCD.filled_circle(x*16+8,y*16+5,2,Color); uLCD.triangle(x*16+8,y*16+5,x*16+4,y*16+12,x*16+12,y*16+12,Color); } void drawQueen(int x, int y, int Color) { uLCD.filled_rectangle(x*16+4,y*16+6, x*16+12, y*16+12, Color); uLCD.triangle(x*16+4,y*16+6,x*16+4,y*16+2,x*16+7,y*16+6,Color); uLCD.triangle(x*16+7,y*16+6,x*16+8.5,y*16+2,x*16+10,y*16+6,Color); uLCD.triangle(x*16+10,y*16+6,x*16+12,y*16+6,x*16+12,y*16+2,Color); } void drawKing(int x,int y, int Color) { uLCD.filled_rectangle(x*16+7,y*16+2,x*16+9,y*16+12,Color); uLCD.filled_rectangle(x*16+4,y*16+6,x*16+12,y*16+8,Color); } void drawKnight(int x, int y, int Color) { uLCD.triangle(x*16+8,y*16+2,x*16+4,y*16+4,x*16+8,y*16+4,Color); uLCD.filled_rectangle(x*16+7, y*16+2, x*16+9, y*16+10, Color); uLCD.filled_rectangle(x*16+4, y*16+10, x*16+12, y*16+ 12, Color); } void drawRook(int x, int y, int Color) { uLCD.filled_rectangle(x*16+2, y*16+4, x*16+ 14, y*16+6,Color); uLCD.filled_rectangle(x*16+5, y*16+6, x*16+11, y*16+12, Color); uLCD.filled_rectangle(x*16+2, y*16+12, x*16+14,y*16+14,Color); uLCD.filled_rectangle(x*16+3, y*16+2, x*16+5, y*16+4,Color); uLCD.filled_rectangle(x*16+7, y*16+2, x*16+9, y*16+4,Color); uLCD.filled_rectangle(x*16+11, y*16+2,x*16+13,y*16+4,Color); } void drawBishop(int x, int y, int Color) { uLCD.filled_rectangle(x*16+4,y*16+10, x*16+12, y*16+12,Color); uLCD.filled_rectangle(x*16+7, y*16+4,x*16+9,y*16+10,Color); uLCD.triangle(x*16+5,y*16+4,x*16+11,y*16+4,x*16+8,y*16,Color); } //display_board sets up the board in the beginning of the game void display_board(void) { //this loop draws the board squares, alternating color bool alternator = true; for(int i=0; i<8; i++)//This loop will be executed for each row once { for(int j=0; j<8; j++) //This loop will be executed 7 times for each row { if (alternator) { uLCD.filled_rectangle(j*16,i*16,(j*16)+16,(i*16)+16, 0xbcb6b8); //draws a light tan (white) square alternator = false; } else { uLCD.filled_rectangle(j*16,i*16,(j*16)+16,(i*16)+16, 0x645659); //draws a dark brown (black) square alternator = true; } } alternator = !alternator; } //draw the pieces in their initial placement and update the board array for(int i=0;i<8;i++) //set the pawns up in a for loop { drawPawn(i,1,BLACK); board[i][1]= -pawn; drawPawn(i,6,WHITE); board[i][6]= pawn; } drawRook(0,0,BLACK); drawRook(7,0,BLACK); board[0][0]=-rook; board[7][0]=-rook; drawRook(0,7,WHITE); drawRook(7,7,WHITE); board[0][7]=rook; board[7][7]=rook; drawKnight(1,0,BLACK); drawKnight(6,0,BLACK); board[1][0]=-knight; board[6][0]=-knight; drawKnight(1,7,WHITE); drawKnight(6,7,WHITE); board[1][7]=knight; board[6][7]=knight; drawBishop(2,0,BLACK); drawBishop(5,0,BLACK); board[2][0]=-bishop; board[5][0]=-bishop; drawBishop(2,7,WHITE); drawBishop(5,7,WHITE); board[2][7]=bishop; board[5][7]=bishop; drawQueen(3,0,BLACK); board[3][0]=-queen; drawQueen(3,7,WHITE); board[3][7]=queen; drawKing(4,0,BLACK); board[4][0]=-king; drawKing(4,7,WHITE); board[4][7]=king; } //globals for castling - keep track of if the pieces have moved //false indicates they have not moved, mark true on a monement bool king1 = false; bool king2 = false; bool rook11 = false; bool rook12 = false; bool rook21 = false; bool rook22 = false; bool castling = false; //set this flag high in validMove so we know in movePiece //movePiece takes in a piece coordinate and moves it to a new spot void movePiece(int ox, int oy, int dx, int dy, int player) { //first clear the piece in the destination if a piece is being captured if(board[dx][dy] !=0) { if( (dx+dy)%2==0) { //moving to a white square uLCD.filled_rectangle(dx*16,dy*16,(dx*16)+16,(dy*16)+16, 0xbcb6b8); } else { //moving to a dark square uLCD.filled_rectangle(dx*16,dy*16,(dx*16)+16,(dy*16)+16, 0x645659); } } //blank out the old square if( (ox+oy)%2==0) { //moving from a white square uLCD.filled_rectangle(ox*16,oy*16,(ox*16)+16,(oy*16)+16, 0xbcb6b8); } else { //moving from a dark square uLCD.filled_rectangle(ox*16,oy*16,(ox*16)+16,(oy*16)+16, 0x645659); } //draw the piece in the new square switch (abs(board[ox][oy])) { //switch based on the piece type case pawn: //if a pawn reaches the end of the line then promote it to a queen if(current_player == 1 && dy == 0) { //white pawn reaches end of file board[ox][oy] = queen; drawQueen(dx,dy,player); } else if(current_player == 2 && dy == 7) { //black pawn reaches end of file board[ox][oy] = -queen; drawQueen(dx,dy,player); } else drawPawn(dx,dy,player); break; case rook: drawRook(dx,dy,player); //this marks if rooks have moved or not (can only castle if false) if(oy == 0) { if(ox == 0) //black left rook rook21 = true; else if(ox==7) //black right rook rook22 = true; } else if(oy == 7) { if(ox == 0) //white rook 1 rook11 = true; else if(ox==7) //white rook 2 rook12 = true; } break; case knight: drawKnight(dx,dy,player); break; case bishop: drawBishop(dx,dy,player); break; case queen: drawQueen(dx,dy,player); break; case king: //for king we also need to mark the king as moved if(current_player == 1) king1 = true; else king2 = true; drawKing(dx,dy,player); break; } //play two notes for a piece capture or one for a regular move if(board[dx][dy] !=0) { mySpeaker.PlayNote(500.0,0.1,0.05); mySpeaker.PlayNote(700.0,0.1,0.05); } else mySpeaker.PlayNote(600.0,0.1,0.05); //if the king is captured then mark then mark the correct player as winning if(board[dx][dy] == 6) winner = 2; else if(board[dx][dy] == -6) winner=1; //adjust the board array for the piece movement board[dx][dy] = board[ox][oy]; board[ox][oy] = 0; //if we're castling we also need to move the rook //first mark castling false then make a recursive call to the movePiece function to move the rook if(castling) { castling = false; if(dx<ox) { //castling left movePiece(0,oy,3,oy, player); } else { //castling right movePiece(7,oy,5,oy, player); } } } //this function takes in the location of a piece and the destination and outputs whether or not it is a valid move int validMove(int ox, int oy, int dx, int dy) { int source = board[ox][oy]; int target = board[dx][dy]; int typePiece = abs(source); //taking one of your own pieces is not allowed if (board[ox][oy] > 0 && board[dx][dy]>0 || board[ox][oy] < 0 && board[dx][dy]<0) return 0; //movement rules for pawns if (typePiece == pawn) { if(current_player == 2 && dx==ox && dy-oy==1 && target==0) return 1; if(current_player == 1 && dx==ox && dy-oy==-1 && target==0) return 1; if(abs(dx-ox)==1 && current_player == 2 && dy-oy==1 && target > 0) return 1; if(abs(dx-ox)==1 && current_player == 1 && dy-oy==-1 && target < 0) return 1; if(current_player == 2 && oy==1 && (abs(ox-dx)==0) && abs(oy-dy)==2 && target == 0) return 1; if(current_player == 1 && oy==6 && (abs(ox-dx)==0) &&(abs(oy-dy)==2) && target == 0) return 1; //movement rules for rooks } else if (typePiece == rook) { if(dx==ox){ // Moving vertically if(dy>oy){ // Downards for(size_t row = (unsigned)(oy+1); row < (unsigned)dy; ++row){ if(board[dx][row] != 0) return 0; } } else { // Upwards for(size_t row = (unsigned)dy+1; row < (unsigned)(oy); ++row){ if(board[dx][row] != 0) return 0; } } return 1; } if(dy==oy){ // Moving horizontally if(dx>ox){ // Rightwards for(size_t column = (unsigned)(ox+1); column < (unsigned)dx; ++column){ if(board[column][dy] != 0) return 0; } } if(dx<ox){ // Leftwards for(size_t column = (unsigned)dx+1; column < (unsigned)(ox); ++column){ if(board[column][dy] != 0) return 0; } } return 1; } return 0; //movement rules for the knight } else if (typePiece == knight) { if((abs(dy-oy)==2 && abs(dx-ox)==1) || (abs(dx-ox)==2 && abs(dy-oy)==1)){ return 1; } return 0; //movement rules for bishops } else if (typePiece == bishop) { if (abs(dx-ox) != abs(dy-oy)) //must move diagonally return 0; int ymult = -1; int xmult = -1; if (dx>ox) xmult = 1; if (dy>oy) ymult = 1; //check all the spots between location and destination on the diagonal for pieces for(int i=1; i < abs(dx-ox); ++i) { if(board[ox + i*xmult][oy+i*ymult] != 0) return 0; } return 1; //movement rules for queens } else if (typePiece ==queen) { // Queen if(abs(dx-ox) == abs(dy-oy)) { //diagonal movement int ymult = -1; int xmult = -1; if (dx>ox) xmult = 1; if (dy>oy) ymult = 1; for(int i=1; i < abs(dx-ox); ++i) { if(board[ox + i*xmult][oy+i*ymult] != 0) return 0; } return 1; } if(dx==ox){ // Moving vertically if(dy>oy){ // Downards for(size_t row = (unsigned)(oy+1); row < (unsigned)dy; ++row){ if(board[dx][row] != 0) return 0; } } else { // Upwards for(size_t row = (unsigned)dy+1; row < (unsigned)(oy); ++row){ if(board[dx][row] != 0) return 0; } } return 1; } if(dy==oy){ // Moving horizontally if(dx>ox){ // Rightwards for(size_t column = (unsigned)(ox+1); column < (unsigned)dx; ++column){ if(board[column][dy] != 0) return 0; } } if(dx<ox){ // Leftwards for(size_t column = (unsigned)dx+1; column < (unsigned)(ox); ++column){ if(board[column][dy] != 0) return 0; } } return 1; } return 0; //movement rules for a king } else if (typePiece ==king) { //special exception for castling if(dy == oy && ox-2 == dx && (!king1 && current_player == 1 && !rook11 || !king2 && current_player==2 && !rook21)) { if(board[ox-1][oy] ==0 && board[ox-2][oy] ==0 && board[ox-3][oy]==0) { castling = true; return 1; //king can castle to the left } } else if(dy == oy && ox + 2 == dx && (!king1 && current_player == 1 && !rook12 || !king2 && current_player==2 && !rook22)) { if(board[ox+1][oy] ==0 && board[ox+2][oy] ==0){ castling = true; return 1; //king can castle to the right } } if(abs(dy-oy)<=1 && abs(dx-ox)<=1) return 1; return 0; } return 0; } //naming the pins for the joystick PinDetect up(p26); PinDetect center(p25); PinDetect left(p24); PinDetect down(p23); PinDetect right(p22); //variables for the joystick interrupt functions volatile int x = 4; volatile int y = 6; volatile int x2 = 4; volatile int y2 = 2; volatile bool center_hit = false; //joystick interrupt functions that control which square is selected void up_hit_callback(void) { --y; if(y<0) y=7; } void down_hit_callback(void) { y = (y+1)%8; } void left_hit_callback(void) { --x; if(x<0) x=7; } void right_hit_callback(void) { x = (x+1)%8; } void center_hit_callback(void) { center_hit = true; } int main() { //set up the interrupt functions for the joystick center.attach_deasserted(¢er_hit_callback); left.attach_deasserted(&left_hit_callback); right.attach_deasserted(&right_hit_callback); up.attach_deasserted(&up_hit_callback); down.attach_deasserted(&down_hit_callback); center.setSampleFrequency(); left.setSampleFrequency(); right.setSampleFrequency(); down.setSampleFrequency(); up.setSampleFrequency(); //setup the board display_board(); //set the default cursor locations int oldx = 4; int oldx2 = 4; int oldy = 6; int oldy2 = 1; //control variables for p1 and p2 int selectedx; int selectedy; bool selected=false; int selectedx2; int selectedy2; bool selected2 = false; //draw the initial cursor uLCD.rectangle(oldx*16,oldy*16,(oldx*16)+16,(oldy*16)+16, GREEN); //the overall game loop while(1) { //the loop for player one while(current_player==1) { myLed4 = 0; //this led indicates okayer myLed1 = selected; //this led indicates whether or not a piece has been selected //if the selected square has moved if(x != oldx || y != oldy) { mySpeaker.PlayNote(969.0,0.05,0.05); //play a noise for cursor movement //delete the old selector if(oldx % 2 == oldy %2) uLCD.rectangle(oldx*16,oldy*16,(oldx*16)+16,(oldy*16)+16, 0xbcb6b8); else uLCD.rectangle(oldx*16,oldy*16,(oldx*16)+16,(oldy*16)+16, 0x645659); //draw the new cursor uLCD.rectangle(x*16,y*16,(x*16)+16,(y*16)+16, GREEN); //record the old cursor location oldx = x; oldy = y; } if (center_hit) { if(board[oldx][oldy] > 0 || selected) { if(selected) { //if a piece has already been selected //check move, make move and change turn if valid if(selectedx == oldx && selectedy==oldy) { //deselect piece by clicking on it again selected = false; } else { if (validMove(selectedx, selectedy, oldx, oldy) ==1) { //if the move is valid make the move and swith turns movePiece(selectedx, selectedy, oldx, oldy, WHITE); selected = false; current_player = 2; //erase the player one selector if(oldx % 2 == oldy %2) uLCD.rectangle(oldx*16,oldy*16,(oldx*16)+16,(oldy*16)+16, 0xbcb6b8); else uLCD.rectangle(oldx*16,oldy*16,(oldx*16)+16,(oldy*16)+16, 0x645659); //draw the player two selector uLCD.rectangle(oldx2*16,oldy2*16,(oldx2*16)+16,(oldy2*16)+16, BLUE); } } } else { //if no piece is selected select the piece being clicked on selected = true; selectedx = oldx; selectedy = oldy; } } center_hit =false; //set the center hit flag to false } } //the loop for player two while(current_player==2 && winner!=1) { myLed4 = 1; //this indicates that it is player twos turn myLed1 = selected2; //shows whether or not a piece is selected //variables for the bluetooth char bnum=0; char bhit=0; bool one_hit = false; //this reads input from the bluetooth and adjusts the location of the cursor or registers a selection if (blue.getc()=='!') { if (blue.getc()=='B') { //button data packet bnum = blue.getc(); //button number bhit = blue.getc(); //1=hit, 0=release if (blue.getc()==char(~('!' + 'B' + bnum + bhit))) { //checksum OK? switch (bnum) { case '1': //number button 1 if (bhit=='1') { one_hit = true; } break; case '5': //button 5 up arrow if (bhit=='1') { //y2 = (y2-1)%8; --y2; if(y2<0) y2=7; } break; case '6': //button 6 down arrow if (bhit=='1') { y2 = (y2+1)%8; } break; case '7': //button 7 left arrow if (bhit=='1') { //x2 = (x2-1)%8; --x2; if(x2<0) x2=7; } break; case '8': //button 8 right arrow if (bhit=='1') { x2 = (x2+1)%8; } break; } //sames as in player 1, play a sound and move the selection box if necessary if(x2 != oldx2 || y2 != oldy2) { mySpeaker.PlayNote(800.0,0.05,0.05); if(oldx % 2 == oldy2 %2) uLCD.rectangle(oldx2*16,oldy2*16,(oldx2*16)+16,(oldy2*16)+16, 0xbcb6b8); else uLCD.rectangle(oldx2*16,oldy2*16,(oldx2*16)+16,(oldy2*16)+16, 0x645659); uLCD.rectangle(x2*16,y2*16,(x2*16)+16,(y2*16)+16, BLUE); oldx2 = x2; oldy2 = y2; } //if the selection button was pressed select/ deselect the piece or attempt to make a move if (one_hit) { if(board[oldx2][oldy2] < 0 || selected2) { if(selected2) { //check move, make move and change turn if valid if(selectedx2 == oldx2 && selectedy2 == oldy2) { selected2 = false; } else { if(validMove(selectedx2, selectedy2, oldx2, oldy2)) { movePiece(selectedx2, selectedy2, oldx2, oldy2, BLACK); selected2 = false; current_player = 1; if(oldx % 2 == oldy2 %2) uLCD.rectangle(oldx2*16,oldy2*16,(oldx2*16)+16,(oldy2*16)+16, 0xbcb6b8); else uLCD.rectangle(oldx2*16,oldy2*16,(oldx2*16)+16,(oldy2*16)+16, 0x645659); uLCD.rectangle(oldx*16,oldy*16,(oldx*16)+16,(oldy*16)+16, GREEN); } } } else { selected2 = true; selectedx2 = oldx2; selectedy2 = oldy2; } one_hit =false; } } } } } } //if someone won the game then display the winner and play the video if(winner) { uLCD.cls(); uLCD.printf("Player %i wins", winner); wait(1); while(1) { uLCD.media_init(); uLCD.set_sector_address(0x0000, 0x00); uLCD.display_video(0,0); } } } }