Mert Us Matthew Hannay Logan Starr
Dependencies: mbed 4DGL-uLCD-SE
main.cpp
- Committer:
- mus3
- Date:
- 24 months ago
- Revision:
- 16:b66a720631dd
- Parent:
- 14:f390d08e5f92
- Child:
- 17:4d74a661d6a0
File content as of revision 16:b66a720631dd:
#include "mbed.h" #include "uLCD_4DGL.h" #include <vector> uLCD_4DGL uLCD(p28,p27,p30); // serial tx, serial rx, reset pin; Serial Blue(p13, p14); DigitalOut bad_move(p18); DigitalIn reset_button(p19); DigitalIn game_mode_switch(p20); enum Piece {e, wK, bK, wQ, bQ, wR, bR, wB, bB, wN, bN, w, b}; std::vector<Piece> whitePieces; std::vector<Piece> blackPieces; enum GameState {whiteSelecting, whitePickedUp, whiteAI, blackSelecting, blackPickedUp, blackAI}; struct pixelCoord { uint8_t x; uint8_t y; }; struct boardPos { uint8_t row; uint8_t column; bool operator==(const boardPos &other) const { return row == other.row && column == other.column; } }; 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(); } const int BOARD_DARK_COLOR = 0x769656; const int BOARD_LIGHT_COLOR = 0xbaca44; const float KING_POSITION_VALUES[] = {2.0, 3.0, 1.0, 0.0, 0.0, 1.0, 3.0, 2,0, 2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, -1.0, -2.0, -2.0, -2.0, -2.0, -2.0, -2.0, -1.0, -2.0, -3.0, -3.0, -4.0, -4.0, -3.0, -3.0, -2,0, -3.0, -4.0, -4.0, -5.0, -5.0, -4.0, -4.0, -3.0, -3.0, -4.0, -4.0, -5.0, -5.0, -4.0, -4.0, -3.0, -3.0, -4.0, -4.0, -5.0, -5.0, -4.0, -4.0, -3.0, -3.0, -4.0, -4.0, -5.0, -5.0, -4.0, -4.0, -3.0 }; const float QUEEN_POSITION_VALUES[] = {-2.0, -1.0, -1.0, -0.5, -0.5, -1.0, -1.0, -2.0, -1.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, -1.0, -1.0, 0.5, 0.5, 0.5, 0.5, 0.5, 0.0, -1.0, 0.0, 0.0, 0.5, 0.5, 0.5, 0.5, 0.0, -0.5, -0.5, 0.0, 0.5, 0.5, 0.5, 0.5, 0.0, -0.5, -1.0, 0.0, 0.5, 0.5, 0.5, 0.5, 0.0, -1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, -2.0, -1.0, -1.0, -0.5, -0.5, -1.0, -1.0, -2.0 }; const float ROOK_POSITION_VALUES[] = {0.0, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, -0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.5, -0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.5, -0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.5, -0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.5, -0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; const float BISHOP_POSITION_VALUES[] = {-2.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -2.0, -1.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, -1.0, -1.0, 0.5, 0.5, 1.0, 1.0, 0.5, 0.5, -1.0, -1.0, 0.0, 0.5, 1.0, 1.0, 0.5, 0.0, -1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, -2.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -2.0 }; const float KNIGHT_POSITION_VALUES[] = {-5.0, -4.0, -3.0, -3.0, -3.0, -3.0, -4.0, -5.0, -4.0, -2.0, 0.0, 0.5, 0.5, 0.0, -2.0, -4.0, -3.0, 0.5, 1.0, 1.5, 1.5, 1.0, 0.5, -3.0, -3.0, 0.0, 1.5, 2.0, 2.0, 1.5, 0.0, -3.0, -3.0, 0.5, 1.5, 2.0, 2.0, 1.5, 0.5, -3.0, -3.0, 0.0, 1.0, 1.5, 1.5, 1.0, 0.0, -3.0, -4.0, -2.0, 0.0, 0.0, 0.0, 0.0, -2.0, -4.0, -5.0, -4.0, -3.0, -3.0, -3.0, -3.0, -4.0, -5.0 }; const float PAWN_POSITION_VALUES[] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 1.0, 1.0, -2.0, -2.0, 1.0, 1.0, 0.5, 0.5, -0.5, -1.0, 0.0, 0.0, -1.0, -0.5, 0.5, 0.0, 0.0, 0.0, 2.0, 2.0, 0.0, 0.0, 0.0, 0.5, 0.5, 1.0, 2.5, 2.5, 1.0, 0.5, 0.5, 1.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 1.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; class BoardState { private: Piece array[64]; // These values are for white pieces, need to be inverted // when making calculations for black pieces. static const float PAWN_VALUE = 10.0; static const float KNIGHT_VALUE = 30.0; static const float BISHOP_VALUE = 30.0; static const float ROOK_VALUE = 50.0; static const float QUEEN_VALUE = 90.0; static const float KING_VALUE = 900.0; public: BoardState() {} // calculates the advantage difference for the board state float calculateBoardState() { float sum = 0.0; for (int i = 0; i < 64; i++) { int row = i / 8; int column = i % 8; Piece curr = getPiece(row, column); switch(curr) { case wK: sum += KING_VALUE + KING_POSITION_VALUES[row*8 + column]; break; case bK: sum -= (KING_VALUE + KING_POSITION_VALUES[(7-row)*8 + (7-column)]); break; case wQ: sum += QUEEN_VALUE + QUEEN_POSITION_VALUES[row*8 + column]; break; case bQ: sum -= (QUEEN_VALUE - QUEEN_POSITION_VALUES[(7-row)*8 + (7-column)]); break; case wR: sum += ROOK_VALUE + ROOK_POSITION_VALUES[row*8 + column]; break; case bR: sum -= (ROOK_VALUE - ROOK_POSITION_VALUES[(7-row)*8 + (7-column)]); break; case wB: sum += BISHOP_VALUE + BISHOP_POSITION_VALUES[row*8 + column]; break; case bB: sum -= (BISHOP_VALUE - BISHOP_POSITION_VALUES[(7-row)*8 + (7-column)]); break; case wN: sum += KNIGHT_VALUE + KNIGHT_POSITION_VALUES[row*8 + column]; break; case bN: sum -= (KNIGHT_VALUE - KNIGHT_POSITION_VALUES[(7-row)*8 + (7-column)]); break; case w: sum += PAWN_VALUE + PAWN_POSITION_VALUES[row*8 + column]; break; case b: sum -= (PAWN_VALUE - PAWN_POSITION_VALUES[(7-row)*8 + (7-column)]); break; default: break; } } return sum; } // returns the piece at a given location Piece getPiece(int row, int column) { return array[column + 8 * row]; } // puts a piece at a given location void placePiece(Piece piece, int row, int column) { // pawn promotion handling if (piece == w && row == 7) { array[column + 8 * row] = wQ; } else if (piece == b && row == 0) { array[column + 8 * row] = bQ; } else { array[column + 8 * row] = piece; } } /* removes a piece from the set position of the board returns the bit representation of the piece */ Piece removePiece(int row, int column) { Piece removedPiece = array[column + 8 * row]; array[column + 8 * row] = e; return removedPiece; } /* moves a piece from one position to another returns the captured piece */ Piece movePiece(int startRow, int startColumn, int endRow, int endColumn) { Piece movingPiece = removePiece(startRow, startColumn); Piece capturedPiece = removePiece(endRow, endColumn); placePiece(movingPiece, endRow, endColumn); return capturedPiece; } // generates a list of possible moves for a piece // returns moves std::vector<boardPos> getMoves(boardPos pos) { return getMoves(pos.row, pos.column); } std::vector<boardPos> getMoves(int row, int column) { std::vector<boardPos> moves; std::vector<boardPos> lineMoves; Piece movingPiece = getPiece(row, column); uint8_t rowIndex; uint8_t columnIndex; bool isWhite; switch(movingPiece) { case wK: case bK: isWhite = movingPiece == wK; if (validMove(isWhite, row + 1, column)) { moves.push_back((boardPos) { row + 1, column }); } if (validMove(isWhite, row, column + 1)) { moves.push_back((boardPos) { row, column + 1 }); } if (validMove(isWhite, row - 1, column)) { moves.push_back((boardPos) { row - 1, column }); } if (validMove(isWhite, row, column - 1)) { moves.push_back((boardPos) { row, column - 1 }); } if (validMove(isWhite, row + 1, column + 1)) { moves.push_back((boardPos) { row + 1, column + 1 }); } if (validMove(isWhite, row - 1, column + 1)) { moves.push_back((boardPos) { row - 1, column + 1 }); } if (validMove(isWhite, row - 1, column - 1)) { moves.push_back((boardPos) { row - 1, column - 1 }); } if (validMove(isWhite, row + 1, column - 1)) { moves.push_back((boardPos) { row + 1, column - 1 }); } break; case wQ: case bQ: isWhite = movingPiece == wQ; rowIndex = row + 1; columnIndex = column + 1; while (validMove(isWhite, rowIndex, columnIndex)) { moves.push_back((boardPos) { rowIndex, columnIndex }); if (getPiece(rowIndex, columnIndex) != e) { break; } rowIndex++; columnIndex++; } rowIndex = row - 1; columnIndex = column + 1; while (validMove(isWhite, rowIndex, columnIndex)) { moves.push_back((boardPos) { rowIndex, columnIndex }); if (getPiece(rowIndex, columnIndex) != e) { break; } rowIndex--; columnIndex++; } rowIndex = row + 1; columnIndex = column - 1; while (validMove(isWhite, rowIndex, columnIndex)) { moves.push_back((boardPos) { rowIndex, columnIndex }); if (getPiece(rowIndex, columnIndex) != e) { break; } rowIndex++; columnIndex--; } rowIndex = row - 1; columnIndex = column - 1; while (validMove(isWhite, rowIndex, columnIndex)) { moves.push_back((boardPos) { rowIndex, columnIndex }); if (getPiece(rowIndex, columnIndex) != e) { break; } rowIndex--; columnIndex--; } rowIndex = row + 1; columnIndex = column; while (validMove(isWhite, rowIndex, columnIndex)) { moves.push_back((boardPos) { rowIndex, columnIndex }); if (getPiece(rowIndex, columnIndex) != e) { break; } rowIndex++; } rowIndex = row - 1; columnIndex = column; while (validMove(isWhite, rowIndex, columnIndex)) { moves.push_back((boardPos) { rowIndex, columnIndex }); if (getPiece(rowIndex, columnIndex) != e) { break; } rowIndex--; } rowIndex = row; columnIndex = column + 1; while (validMove(isWhite, rowIndex, columnIndex)) { moves.push_back((boardPos) { rowIndex, columnIndex }); if (getPiece(rowIndex, columnIndex) != e) { break; } columnIndex++; } rowIndex = row; columnIndex = column - 1; while (validMove(isWhite, rowIndex, columnIndex)) { moves.push_back((boardPos) { rowIndex, columnIndex }); if (getPiece(rowIndex, columnIndex) != e) { break; } columnIndex--; } break; case wB: case bB: isWhite = movingPiece == wB; rowIndex = row + 1; columnIndex = column + 1; while (validMove(isWhite, rowIndex, columnIndex)) { moves.push_back((boardPos) { rowIndex, columnIndex }); if (getPiece(rowIndex, columnIndex) != e) { break; } rowIndex++; columnIndex++; } rowIndex = row - 1; columnIndex = column + 1; while (validMove(isWhite, rowIndex, columnIndex)) { moves.push_back((boardPos) { rowIndex, columnIndex }); if (getPiece(rowIndex, columnIndex) != e) { break; } rowIndex--; columnIndex++; } rowIndex = row + 1; columnIndex = column - 1; while (validMove(isWhite, rowIndex, columnIndex)) { moves.push_back((boardPos) { rowIndex, columnIndex }); if (getPiece(rowIndex, columnIndex) != e) { break; } rowIndex++; columnIndex--; } rowIndex = row - 1; columnIndex = column - 1; while (validMove(isWhite, rowIndex, columnIndex)) { moves.push_back((boardPos) { rowIndex, columnIndex }); if (getPiece(rowIndex, columnIndex) != e) { break; } rowIndex--; columnIndex--; } break; case wN: case bN: isWhite = movingPiece == wN; if (validMove(isWhite, row + 2, column + 1)) { moves.push_back((boardPos) { row + 2, column + 1 }); } if (validMove(isWhite, row + 2, column - 1)) { moves.push_back((boardPos) { row + 2, column - 1 }); } if (validMove(isWhite, row - 2, column - 1)) { moves.push_back((boardPos) { row - 2, column - 1 }); } if (validMove(isWhite, row - 2, column + 1)) { moves.push_back((boardPos) { row - 2, column + 1 }); } if (validMove(isWhite, row + 1, column + 2)) { moves.push_back((boardPos) { row + 1, column + 2 }); } if (validMove(isWhite, row - 1, column + 2)) { moves.push_back((boardPos) { row - 1, column + 2 }); } if (validMove(isWhite, row - 1, column - 2)) { moves.push_back((boardPos) { row - 1, column - 2 }); } if (validMove(isWhite, row + 1, column - 2)) { moves.push_back((boardPos) { row + 1, column - 2 }); } break; case wR: case bR: isWhite = movingPiece == wR; rowIndex = row + 1; columnIndex = column; while (validMove(isWhite, rowIndex, columnIndex)) { moves.push_back((boardPos) { rowIndex, columnIndex }); if (getPiece(rowIndex, columnIndex) != e) { break; } rowIndex++; } rowIndex = row - 1; columnIndex = column; while (validMove(isWhite, rowIndex, columnIndex)) { moves.push_back((boardPos) { rowIndex, columnIndex }); if (getPiece(rowIndex, columnIndex) != e) { break; } rowIndex--; } rowIndex = row; columnIndex = column + 1; while (validMove(isWhite, rowIndex, columnIndex)) { moves.push_back((boardPos) { rowIndex, columnIndex }); if (getPiece(rowIndex, columnIndex) != e) { break; } columnIndex++; } rowIndex = row; columnIndex = column - 1; while (validMove(isWhite, rowIndex, columnIndex)) { moves.push_back((boardPos) { rowIndex, columnIndex }); if (getPiece(rowIndex, columnIndex) != e) { break; } columnIndex--; } break; case w: case b: isWhite = movingPiece == w; int rowChange = isWhite ? 1 : -1; if (validMove(isWhite, row + rowChange, column) && getPiece(row + rowChange, column) == e) { moves.push_back((boardPos) { row + rowChange, column }); // The case for pawns moving two squares at the start if (((isWhite && row == 1) || (!isWhite && row == 6)) && validMove(isWhite, row + rowChange + rowChange, column) && getPiece(row + rowChange + rowChange, column) == e) { moves.push_back((boardPos) { row + rowChange + rowChange, column }); } } if (validMove(isWhite, row + rowChange, column + 1) && getPiece(row + rowChange, column + 1) != e) { moves.push_back((boardPos) { row + rowChange, column + 1 }); } if (validMove(isWhite, row + rowChange, column - 1) && getPiece(row + rowChange, column - 1) != e) { moves.push_back((boardPos) { row + rowChange, column - 1 }); } break; default: break; } return moves; } // returns a vector of board positions that a piece can move in a line std::vector<boardPos> movesInLine(bool isMovingPieceWhite, int row, int column, int rowChange, int columnChange) { std::vector<boardPos> moves; for (int i = 1; ; i++) { // check if piece can move to location if (validMove(isMovingPieceWhite, row + i * rowChange, column + i * columnChange)) { moves.push_back((boardPos) { row + i * rowChange, column + i * columnChange }); // if piece is capturable, stop moving beyond it if (getPiece(row + i * rowChange, column + i * columnChange) != e) { break; } // if unable to move, break out } else { break; } } return moves; } // returns if a piece can move to a given location bool validMove(bool isMovingPieceWhite, int row, int column) { if (row < 0 || row > 7 || column < 0 || column > 7) { return false; } Piece capturedPiece = getPiece(row, column); switch(capturedPiece) { case wK: case wQ: case wR: case wB: case wN: case w: return !isMovingPieceWhite; case bK: case bQ: case bR: case bB: case bN: case b: return isMovingPieceWhite; case e: return true; } return false; } }; class GameBoard { private: BoardState boardState; static const int HOVER_COLOR = 0x0000ff; static const int SELECTED_COLOR = 0xff8800; static const int MOVE_COLOR = 0xff00ff; // piece sprites (12 x 12) static void drawPawn(int row, int column, bool white, bool light) { int X = white ? 0xffffff : 0x000000; int _ = light ? BOARD_LIGHT_COLOR : BOARD_DARK_COLOR; int sprite[144] = {_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, X, X, _, _, _, _, _, _, _, _, _, X, X, X, X, _, _, _, _, _, _, _, _, X, X, X, X, _, _, _, _, _, _, _, _, _, X, X, _, _, _, _, _, _, _, _, _, _, X, X, _, _, _, _, _, _, _, _, _, X, X, X, X, _, _, _, _, _, _, X, X, X, X, X, X, X, X, _, _, _, _, X, X, X, X, X, X, X, X, _, _ }; pixelCoord tl = getTopLeftOfSquare(row, column); uLCD.BLIT(tl.x + 2, tl.y + 2, 12, 12, sprite); } static void drawRook(int row, int column, bool white, bool light) { int X = white ? 0xffffff : 0x000000; int _ = light ? BOARD_LIGHT_COLOR : BOARD_DARK_COLOR; int sprite[144] = {X, X, _, X, X, _, _, X, X, _, X, X, X, X, _, X, X, _, _, X, X, _, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, _, X, X, X, _, X, X, _, X, X, X, _, _, X, X, X, _, X, X, _, X, X, X, _, _, _, X, X, _, X, X, _, X, X, _, _, _, _, X, X, _, X, X, _, X, X, _, _, _, _, X, X, _, X, X, _, X, X, _, _, _, X, X, X, X, X, X, X, X, X, X, _, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X }; pixelCoord tl = getTopLeftOfSquare(row, column); uLCD.BLIT(tl.x + 2, tl.y + 2, 12, 12, sprite); } static void drawKnight(int row, int column, bool white, bool light) { int X = white ? 0xffffff : 0x000000; int _ = light ? BOARD_LIGHT_COLOR : BOARD_DARK_COLOR; int sprite[144] = {_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, X, X, _, X, X, _, _, _, _, _, _, _, X, X, _, X, X, _, _, _, _, _, X, X, X, X, X, X, _, _, _, _, _, X, X, X, X, X, _, X, _, _, _, _, _, X, X, X, X, X, X, X, _, _, _, _, _, _, _, _, X, X, X, X, _, _, _, _, _, _, _, X, X, X, X, X, _, _, _, _, _, _, X, X, X, X, X, X, X, _, _, _, _, X, X, X, X, X, X, X, X, _, _, _, X, X, X, X, X, X, X, X, X, X, _, _, X, X, X, X, X, X, X, X, X, X, _ }; pixelCoord tl = getTopLeftOfSquare(row, column); uLCD.BLIT(tl.x + 2, tl.y + 2, 12, 12, sprite); } static void drawBishop(int row, int column, bool white, bool light) { int X = white ? 0xffffff : 0x000000; int _ = light ? BOARD_LIGHT_COLOR : BOARD_DARK_COLOR; int sprite[144] = {_, _, _, _, _, X, X, _, _, _, _, _, _, _, _, _, X, X, X, _, _, _, _, _, _, _, _, X, X, X, _, _, X, _, _, _, _, _, _, X, X, _, _, X, X, _, _, _, _, _, _, X, X, X, X, X, X, _, _, _, _, _, _, _, X, X, X, X, _, _, _, _, _, _, _, _, _, X, X, _, _, _, _, _, _, _, _, _, X, X, X, X, _, _, _, _, _, _, _, X, X, X, X, X, X, _, _, _, _, _, _, X, X, X, X, X, X, _, _, _, _, _, X, X, X, X, X, X, X, X, _, _, _, _, X, X, X, X, X, X, X, X, _, _ }; pixelCoord tl = getTopLeftOfSquare(row, column); uLCD.BLIT(tl.x + 2, tl.y + 2, 12, 12, sprite); } static void drawQueen(int row, int column, bool white, bool light) { int X = white ? 0xffffff : 0x000000; int _ = light ? BOARD_LIGHT_COLOR : BOARD_DARK_COLOR; int sprite[144] = {_, _, _, _, _, X, X, _, _, _, _, _, _, _, X, _, _, X, X, _, _, X, _, _, X, _, X, X, _, X, X, _, X, X, _, X, X, _, X, X, _, X, X, _, X, X, _, X, X, _, X, X, _, X, X, _, X, X, _, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, _, X, X, X, X, X, X, _, X, X, X, X, X, X, _, X, X, _, X, X, X, X, _, X, X, X, X, X, X, X, X, X, X, _, _, _, X, X, X, X, X, X, X, X, _, _, _, X, X, X, X, X, X, X, X, X, X, _ }; pixelCoord tl = getTopLeftOfSquare(row, column); uLCD.BLIT(tl.x + 2, tl.y + 2, 12, 12, sprite); } static void drawKing(int row, int column, bool white, bool light) { int X = white ? 0xffffff : 0x000000; int _ = light ? BOARD_LIGHT_COLOR : BOARD_DARK_COLOR; int sprite[144] = {_, _, _, _, _, X, X, _, _, _, _, _, _, _, _, _, _, X, X, _, _, _, _, _, _, _, _, X, X, X, X, X, X, _, _, _, _, _, _, X, X, X, X, X, X, _, _, _, X, X, _, _, _, X, X, _, _, _, X, X, X, X, X, X, _, X, X, _, X, X, X, X, X, _, X, X, X, X, X, X, X, X, _, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, _, X, X, X, X, _, X, X, X, _, X, X, X, X, X, X, X, X, X, X, _, _, _, X, X, X, _, _, X, X, X, _, _, _, X, X, X, X, X, X, X, X, X, X, _ }; pixelCoord tl = getTopLeftOfSquare(row, column); uLCD.BLIT(tl.x + 2, tl.y + 2, 12, 12, sprite); } public: BoardState getBoardState() { return boardState; } void setBoardState(BoardState newBoardState) { boardState = newBoardState; } // initializes the starting board state GameBoard() { // draw board for (int row = 0; row < 8; row++) { for (int column = 0; column < 8; column++) { uint64_t color; if ((row + column) % 2 == 0) { color = BOARD_DARK_COLOR; } else { color = BOARD_LIGHT_COLOR; } pixelCoord tl = getTopLeftOfSquare(row, column); uLCD.filled_rectangle(tl.x, tl.y, tl.x + 15, tl.y + 15, color); } } // draw pieces placePieceAndDraw(wR, 0, 0); placePieceAndDraw(wN, 0, 1); placePieceAndDraw(wB, 0, 2); placePieceAndDraw(wQ, 0, 3); placePieceAndDraw(wK, 0, 4); placePieceAndDraw(wB, 0, 5); placePieceAndDraw(wN, 0, 6); placePieceAndDraw(wR, 0, 7); placePieceAndDraw(bR, 7, 0); placePieceAndDraw(bN, 7, 1); placePieceAndDraw(bB, 7, 2); placePieceAndDraw(bQ, 7, 3); placePieceAndDraw(bK, 7, 4); placePieceAndDraw(bB, 7, 5); placePieceAndDraw(bN, 7, 6); placePieceAndDraw(bR, 7, 7); for (int i = 0; i < 8; i++) { placePieceAndDraw(w, 1, i); placePieceAndDraw(b, 6, i); } } // gets the pixel coordinates of the top left of the square static pixelCoord getTopLeftOfSquare(boardPos pos) { return getTopLeftOfSquare(pos.row, pos.column); } static pixelCoord getTopLeftOfSquare(int row, int column) { pixelCoord topLeft; topLeft.x = 16 * column; topLeft.y = 112 - 16 * row; return topLeft; } // PIECE MOVEMENT AND GRAPHICS FUNCTIONS // returns the piece at a given location Piece getPiece(boardPos pos) { return getPiece(pos.row, pos.column); } Piece getPiece(int row, int column) { return boardState.getPiece(row, column); } /* puts the bit representation of a piece at the set position of the board assumes that the position of the board is emptied beforehand */ void placePieceAndDraw(Piece piece, boardPos pos) { placePieceAndDraw(piece, pos.row, pos.column); } void placePieceAndDraw(Piece piece, int row, int column) { boardState.placePiece(piece, row, column); pixelCoord tl = getTopLeftOfSquare(row, column); switch(piece) { case wK: case bK: drawKing(row, column, piece==wK, (row+column)%2); break; case wQ: case bQ: drawQueen(row, column, piece==wQ, (row+column)%2); break; case wB: case bB: drawBishop(row, column, piece==wB, (row+column)%2); break; case wN: case bN: drawKnight(row, column, piece==wN, (row+column)%2); break; case wR: case bR: drawRook(row, column, piece==wR, (row+column)%2); break; case w: case b: if (piece == w && row == 7) { drawQueen(row, column, true, (row+column)%2); } else if (piece == b && row == 0) { drawQueen(row, column, false, (row+column)%2); } else { drawPawn(row, column, piece==w, (row+column)%2); } break; } } /* removes a piece from the set position of the board returns the bit representation of the piece */ Piece removePieceAndDraw(boardPos pos) { return removePieceAndDraw(pos.row, pos.column); } Piece removePieceAndDraw(int row, int column) { Piece removedPiece = boardState.removePiece(row, column); pixelCoord tl = getTopLeftOfSquare(row, column); uint64_t color; if ((row + column) % 2 == 0) { color = BOARD_DARK_COLOR; } else { color = BOARD_LIGHT_COLOR; } uLCD.filled_rectangle(tl.x+2, tl.y+2, tl.x + 13, tl.y + 13, color); return removedPiece; } /* moves a piece from one position to another returns the captured piece */ Piece movePieceAndDraw(boardPos startPos, boardPos endPos) { return movePieceAndDraw(startPos.row, startPos.column, endPos.row, endPos.column); } Piece movePieceAndDraw(int startRow, int startColumn, int endRow, int endColumn) { Piece movingPiece = removePieceAndDraw(startRow, startColumn); Piece capturedPiece = boardState.removePiece(endRow, endColumn); placePieceAndDraw(movingPiece, endRow, endColumn); return capturedPiece; } // SQUARE BORDER GRAPHICS FUNCTIONS // removes selection border around square void unselectSquare(boardPos pos) { unselectSquare(pos.row, pos.column); } void unselectSquare(int row, int column) { if (row < 0 || row > 7 || column < 0 || column > 7) { return; } pixelCoord tl = getTopLeftOfSquare(row, column); uint64_t color; if ((row + column) % 2 == 0) { color = BOARD_DARK_COLOR; } else { color = BOARD_LIGHT_COLOR; } uLCD.rectangle(tl.x, tl.y, tl.x + 15, tl.y + 15, color); } // draws the hover border around square void hoverSquare(boardPos pos) { hoverSquare(pos.row, pos.column); } void hoverSquare(int row, int column) { pixelCoord tl = getTopLeftOfSquare(row, column); uLCD.rectangle(tl.x, tl.y, tl.x + 15, tl.y + 15, HOVER_COLOR); } // draws selection border around square void selectSquare(boardPos pos) { selectSquare(pos.row, pos.column); } void selectSquare(int row, int column) { if (row < 0 || row > 7 || column < 0 || column > 7) { return; } pixelCoord tl = getTopLeftOfSquare(row, column); uLCD.rectangle(tl.x, tl.y, tl.x + 15, tl.y + 15, SELECTED_COLOR); } // draws the movement border around square void movementSquare(boardPos pos) { movementSquare(pos.row, pos.column); } void movementSquare(int row, int column) { pixelCoord tl = getTopLeftOfSquare(row, column); uLCD.rectangle(tl.x, tl.y, tl.x + 15, tl.y + 15, MOVE_COLOR); } }; // game variables GameBoard gameBoard; GameState state = whiteSelecting; boardPos cursorPos = (boardPos) { 3, 4 }; bool OnePlayer = true; boardPos selectedPos; Piece selectedPiece; std::vector<boardPos> possibleMoves; // callbacks void moveCursor(int rowChange, int columnChange) { // calculate new positoin that is within board bounds int newRow = cursorPos.row + rowChange; int newColumn = cursorPos.column + columnChange; if (newRow > 7 || newRow < 0 || newColumn > 7 || newColumn < 0) { bad_move = 1; wait(0.2); bad_move = 0; wait(0.02); } newRow = newRow <= 7 ? newRow : 7; newRow = newRow >= 0 ? newRow : 0; newColumn = newColumn <= 7 ? newColumn : 7; newColumn = newColumn >= 0 ? newColumn : 0; boardPos newPos = (boardPos) { newRow, newColumn }; // draw border around square that should be there after moving cursor off if (cursorPos == selectedPos) { gameBoard.selectSquare(cursorPos); } else if (std::find(possibleMoves.begin(), possibleMoves.end(), cursorPos) != possibleMoves.end()) { gameBoard.movementSquare(cursorPos); } else { gameBoard.unselectSquare(cursorPos); } // draw hover rectangle over new square cursorPos = newPos; gameBoard.hoverSquare(cursorPos); } void reset_game(void) { BoardState newBS; for (int i = 0; i < 64; i++) { newBS.placePiece(e, i/8, i%8); } gameBoard.setBoardState(newBS); // draw board for (int row = 0; row < 8; row++) { for (int column = 0; column < 8; column++) { uint64_t color; if ((row + column) % 2 == 0) { color = BOARD_DARK_COLOR; } else { color = BOARD_LIGHT_COLOR; } pixelCoord tl = gameBoard.getTopLeftOfSquare(row, column); uLCD.filled_rectangle(tl.x, tl.y, tl.x + 15, tl.y + 15, color); } } // draw pieces gameBoard.placePieceAndDraw(wR, 0, 0); gameBoard.placePieceAndDraw(wN, 0, 1); gameBoard.placePieceAndDraw(wB, 0, 2); gameBoard.placePieceAndDraw(wQ, 0, 3); gameBoard.placePieceAndDraw(wK, 0, 4); gameBoard.placePieceAndDraw(wB, 0, 5); gameBoard.placePieceAndDraw(wN, 0, 6); gameBoard.placePieceAndDraw(wR, 0, 7); gameBoard.placePieceAndDraw(bR, 7, 0); gameBoard.placePieceAndDraw(bN, 7, 1); gameBoard.placePieceAndDraw(bB, 7, 2); gameBoard.placePieceAndDraw(bQ, 7, 3); gameBoard.placePieceAndDraw(bK, 7, 4); gameBoard.placePieceAndDraw(bB, 7, 5); gameBoard.placePieceAndDraw(bN, 7, 6); gameBoard.placePieceAndDraw(bR, 7, 7); for (int i = 0; i < 8; i++) { gameBoard.placePieceAndDraw(w, 1, i); gameBoard.placePieceAndDraw(b, 6, i); } state = whiteSelecting; cursorPos = (boardPos) { 3, 4 }; if (game_mode_switch) { OnePlayer = true; } else { OnePlayer = false; } selectedPos = (boardPos) { 10, 10 }; possibleMoves.clear(); moveCursor(0, 0); } void joyStickUp() { moveCursor(1, 0); } void joyStickDown() { moveCursor(-1, 0); } void joyStickLeft() { moveCursor(0, -1); } void joyStickRight() { moveCursor(0, 1); } void joyStickPressed() { switch(state) { case whiteSelecting: case blackSelecting: { possibleMoves.clear(); selectedPos = cursorPos; Piece tempPiece = gameBoard.getPiece(cursorPos); std::vector<Piece> pickablePieces = state == whiteSelecting ? whitePieces : blackPieces; // check that piece is white and able to be picked up if (std::find(pickablePieces.begin(), pickablePieces.end(), tempPiece) != pickablePieces.end()) { selectedPiece = tempPiece; possibleMoves = gameBoard.getBoardState().getMoves(cursorPos); // draw movement squares for (std::vector<boardPos>::iterator it = possibleMoves.begin(); it != possibleMoves.end(); ++it) { gameBoard.movementSquare(*it); } gameBoard.selectSquare(selectedPos); // transition state if (OnePlayer) { state = whitePickedUp; } else { state = state == whiteSelecting ? whitePickedUp : blackPickedUp; } } else { selectedPos = (boardPos) { 10, 10 }; bad_move = 1; wait(0.1); bad_move = 0; wait(0.02); } break; } case whitePickedUp: case blackPickedUp: { // check if move is valid if (std::find(possibleMoves.begin(), possibleMoves.end(), cursorPos) != possibleMoves.end()) { // move the piece Piece capturedPiece = gameBoard.movePieceAndDraw(selectedPos, cursorPos); // check for king capture if (state == whitePickedUp && capturedPiece == bK) { uLCD.cls(); uLCD.text_height(2); uLCD.text_width(2); uLCD.color(WHITE); uLCD.locate(2,2); uLCD.printf("WHITE"); uLCD.locate(2,4); uLCD.printf("WINS"); while(1) { if (!reset_button) { reset_game(); break; } } break; } else if (state == blackPickedUp && capturedPiece == wK) { uLCD.cls(); uLCD.text_height(2); uLCD.text_width(2); uLCD.color(WHITE); uLCD.locate(2,2); uLCD.printf("BLACK"); uLCD.locate(2,4); uLCD.printf("WINS"); while(1) { if (!reset_button) { reset_game(); break; } } break; } // transition state if (OnePlayer) { state = blackAI; } else { state = state == whitePickedUp ? blackSelecting : whiteSelecting; } // check if placing piece back down } else { // transition state state = state == whitePickedUp ? whiteSelecting : blackSelecting; } // unselect movement squares for (std::vector<boardPos>::iterator it = possibleMoves.begin(); it != possibleMoves.end(); ++it) { gameBoard.unselectSquare(*it); } gameBoard.unselectSquare(selectedPos); gameBoard.hoverSquare(cursorPos); possibleMoves.clear(); selectedPos = (boardPos) { 10, 10 }; break; } case whiteAI: break; case blackAI: { boardPos bestMoveSourceDepth0 = (boardPos) { 0, 0 }; boardPos bestMoveDestDepth0 = (boardPos) { 0, 0 }; float bestMoveValueDepth0 = 100000.0; for (int i = 0; i < 64; i++) { boardPos currSourceDepth0 = (boardPos) { i/8, i%8 }; Piece currPieceDepth0 = gameBoard.getBoardState().getPiece(i/8, i%8); if (currPieceDepth0 == bK || currPieceDepth0 == bQ || currPieceDepth0 == bR || currPieceDepth0 == bB || currPieceDepth0 == bN || currPieceDepth0 == b) { std::vector<boardPos> possibleMovesDepth0 = gameBoard.getBoardState().getMoves(currSourceDepth0); for (std::vector<boardPos>::iterator it = possibleMovesDepth0.begin(); it != possibleMovesDepth0.end(); ++it) { BoardState bsDepth0; for (int j = 0; j < 64; j++) { bsDepth0.placePiece(gameBoard.getBoardState().getPiece(j/8, j%8), j/8, j%8); } bsDepth0.movePiece(currSourceDepth0.row, currSourceDepth0.column, (*it).row, (*it).column); float bestMoveValueDepth1 = -100000.0; for (int i2 = 0; i2 < 64; i2++) { boardPos currSourceDepth1 = (boardPos) { i2/8, i2%8 }; Piece currPieceDepth1 = bsDepth0.getPiece(i2/8, i2%8); if (currPieceDepth1 == wK || currPieceDepth1 == wQ || currPieceDepth1 == wR || currPieceDepth1 == wB || currPieceDepth1 == wN || currPieceDepth1 == w) { std::vector<boardPos> possibleMovesDepth1 = bsDepth0.getMoves(currSourceDepth1); for (std::vector<boardPos>::iterator it2 = possibleMovesDepth1.begin(); it2 != possibleMovesDepth1.end(); ++it2) { BoardState bsDepth1; for (int j2 = 0; j2 < 64; j2++) { bsDepth1.placePiece(bsDepth0.getPiece(j2/8, j2%8), j2/8, j2%8); } bsDepth1.movePiece(currSourceDepth1.row, currSourceDepth1.column, (*it2).row, (*it2).column); float bestMoveValueDepth2 = 100000.0; for (int i3 = 0; i3 < 64; i3++) { boardPos currSourceDepth2 = (boardPos) { i3/8, i3%8 }; Piece currPieceDepth2 = bsDepth1.getPiece(i3/8, i3%8); if (currPieceDepth2 == bK || currPieceDepth2 == bQ || currPieceDepth2 == bR || currPieceDepth2 == bB || currPieceDepth2 == bN || currPieceDepth2 == b) { std::vector<boardPos> possibleMovesDepth2 = bsDepth1.getMoves(currSourceDepth2); for (std::vector<boardPos>::iterator it3 = possibleMovesDepth2.begin(); it3 != possibleMovesDepth2.end(); ++it3) { BoardState bsDepth2; for (int j3 = 0; j3 < 64; j3++) { bsDepth2.placePiece(bsDepth1.getPiece(j3/8, j3%8), j3/8, j3%8); } bsDepth2.movePiece(currSourceDepth2.row, currSourceDepth2.column, (*it3).row, (*it3).column); float thisMoveValueDepth2 = bsDepth2.calculateBoardState(); if (thisMoveValueDepth2 < bestMoveValueDepth2) { bestMoveValueDepth2 = thisMoveValueDepth2; } } } } if (bestMoveValueDepth2 > bestMoveValueDepth1) { bestMoveValueDepth1 = bestMoveValueDepth2; } } } } if (bestMoveValueDepth1 < bestMoveValueDepth0) { bestMoveSourceDepth0 = currSourceDepth0; bestMoveDestDepth0 = *it; bestMoveValueDepth0 = bestMoveValueDepth1; } } } } Piece capturedPiece = gameBoard.movePieceAndDraw(bestMoveSourceDepth0, bestMoveDestDepth0); if (capturedPiece == wK) { uLCD.cls(); uLCD.text_height(2); uLCD.text_width(2); uLCD.color(WHITE); uLCD.locate(2,2); uLCD.printf("BLACK"); uLCD.locate(2,4); uLCD.printf("WINS"); while(1) { if (!reset_button) { reset_game(); break; } } break; } state = whiteSelecting; break; } default: { break; } } } // bluetooth volatile bool button_ready = 0; volatile int bnum = 0; volatile int bhit = 0; enum statetype {start = 0, got_exclm, got_B, got_num, got_hit}; statetype bluetooth_state = start; void parse_message() { switch (bluetooth_state) { case start: if (Blue.getc() == '!') bluetooth_state = got_exclm; else bluetooth_state = start; break; case got_exclm: if (Blue.getc() == 'B') bluetooth_state = got_B; else bluetooth_state = start; break; case got_B: bnum = Blue.getc(); bluetooth_state = got_num; break; case got_num: bhit = Blue.getc(); bluetooth_state = got_hit; break; case got_hit: if (Blue.getc() == char(~('!' + ' B' + bnum + bhit))) button_ready = 1; bluetooth_state = start; break; default: Blue.getc(); bluetooth_state = start; } } Nav_Switch myNav(p9, p6, p7, p5, p8); //pin order on Sparkfun breakout int main() { reset_button.mode(PullUp); game_mode_switch.mode(PullUp); wait(0.01); whitePieces.push_back(wK); whitePieces.push_back(wQ); whitePieces.push_back(wB); whitePieces.push_back(wN); whitePieces.push_back(wR); whitePieces.push_back(w); blackPieces.push_back(bK); blackPieces.push_back(bQ); blackPieces.push_back(bB); blackPieces.push_back(bN); blackPieces.push_back(bR); blackPieces.push_back(b); if (game_mode_switch) { OnePlayer = true; } else { OnePlayer = false; } moveCursor(0, 0); Blue.attach(&parse_message,Serial::RxIrq); while (1) { if (!reset_button) { reset_game(); } else if (state == blackAI) { joyStickPressed(); } else if (myNav.up()) { joyStickUp(); } else if (myNav.down()) { joyStickDown(); } else if (myNav.left()) { joyStickLeft(); } else if (myNav.right()) { joyStickRight(); } else if (myNav.fire()) { joyStickPressed(); } else if (button_ready && bhit == '1') { switch(bnum) { case '1': joyStickPressed(); break; case '5': joyStickUp(); break; case '6': joyStickDown(); break; case '7': joyStickLeft(); break; case '8': joyStickRight(); break; } button_ready = false; } wait(0.2); } }