Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed mbed-rtos 4DGL-uLCD-SE
Diff: main.cpp
- Revision:
- 0:d9dcc0c3cd64
- Child:
- 1:4af874b42e33
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Tue Apr 28 01:18:23 2020 +0000
@@ -0,0 +1,1019 @@
+
+/*
+
+desired functionality (not priority)
+-----------------------------------
+ - 2 player
+ - check for moves so that if you try to move into check it displays an error
+ - highlight previous move and new position in movePiece() function
+ - display possible moves as yellow
+ - audio needs done in separate thread or with short clips so that it doesn't freeze program
+ - alternating color tiles
+
+program flow
+-----------------------------------
+ - game initializes
+ - a startup screen displays (or start on menu?)
+ - timer begins on first move
+ - timer changes every time a move is made
+ - loop for new button inputs
+ - when select button is hit is when the real checks run
+ - if selecting a piece, simply update x and y coordinates of selected piece
+ - if moving a selected piece, check if the move is valid and then update the board, switch current player
+ - if menu button is hit, it takes priority
+ - menu contains settings
+ - if timer runs out or your king is taken you lose (display game end screen)
+ - make sure gameend resets all variables to original values (or just use the initialize() function)
+
+TODO
+----------------------------------
+ - game settings menu
+ - en passant
+ - castling
+ - timer
+ - images for pieces
+ - need to handle input better, with debounced timer or on deasserted or something
+ - restart button
+*/
+
+#include "mbed.h"
+#include "rtos.h"
+#include "uLCD_4DGL.h"
+#include "Speaker.h"
+
+//piece colors
+#define white true
+#define black false
+
+//button inputs
+#define SELECT 0
+#define FORWARD 1
+#define BACKWARD 2
+#define RIGHT 3
+#define LEFT 4
+#define MENU 5
+
+//piece types
+#define NONE 0
+#define KING 1
+#define QUEEN 2
+#define BISHOP 3
+#define KNIGHT 4
+#define ROOK 5
+#define PAWN 6
+
+//seven-segment display conversions
+#define ZERO 126
+#define ONE 48
+#define TWO 109
+#define THREE 121
+#define FOUR 51
+#define FIVE 91
+#define SIX 95
+#define SEVEN 112
+#define EIGHT 127
+#define NINE 123
+
+#define D1 7
+#define D2 11
+#define D3 13
+#define D4 14
+
+uLCD_4DGL uLCD(p28, p27, p29); // serial tx, serial rx, reset pin;
+
+Serial pc(USBTX, USBRX);
+
+//button control (directions optional)
+DigitalIn Select(p14);
+DigitalIn Menu(p15);
+DigitalOut led3(LED3);
+DigitalOut whiteLED(p12);
+DigitalOut blackLED(p13);
+Speaker speakerOut(p26);
+
+//Joystick variables
+AnalogIn JoyX(p19);
+AnalogIn JoyY(p20);
+
+
+volatile bool currentPlayer = white;
+volatile bool gameActive = false;
+
+bool menuOpen = false;
+int menuSelectionIndex = 0;
+
+bool playSound = true;
+
+int boxWidth = 16;
+
+int programTimeSetting = 600;
+
+bool pieceSelected = false;
+int currentPiece = NONE;
+int positionX = 0;
+int positionY = 0;
+int selectedX = 0;
+int selectedY = 0;
+int board[8][8] = {
+ {ROOK, PAWN, NONE, NONE, NONE, NONE, PAWN, ROOK},
+ {KNIGHT, PAWN, NONE, NONE, NONE, NONE, PAWN, KNIGHT},
+ {BISHOP, PAWN, NONE, NONE, NONE, NONE, PAWN, BISHOP},
+ {KING, PAWN, NONE, NONE, NONE, NONE, PAWN, KING},
+ {QUEEN, PAWN, NONE, NONE, NONE, NONE, PAWN, QUEEN},
+ {BISHOP, PAWN, NONE, NONE, NONE, NONE, PAWN, BISHOP},
+ {KNIGHT, PAWN, NONE, NONE, NONE, NONE, PAWN, KNIGHT},
+ {ROOK, PAWN, NONE, NONE, NONE, NONE, PAWN, ROOK}
+};//not sure if i did this right, also check x and y
+
+bool color[8][8] = {
+ {white, white, white, white, white, white, black, black},
+ {white, white, white, white, white, white, black, black},
+ {white, white, white, white, white, white, black, black},
+ {white, white, white, white, white, white, black, black},
+ {white, white, white, white, white, white, black, black},
+ {white, white, white, white, white, white, black, black},
+ {white, white, white, white, white, white, black, black},
+ {white, white, white, white, white, white, black, black}
+};
+
+Timer timerWhite;
+Timer timerBlack;
+
+void drawGameBoard();
+int waitForInput();
+
+//TIMER FUNCTIONS---------------------------------------------------------------------------------------------------------------------------------
+
+void timer(void const *args) {
+ //updates the small clock
+ int time_left = programTimeSetting; // remaining time for either player
+ int min2, min1, sec2, sec1; // decimal value for each digit
+ int digits[10] = {ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE}; //contains bus words for each symbol
+
+ BusOut digit_value(p18, p17, p9, p8, p7, p6, p5);
+ BusOut digit_select(p21, p22, p23, p24);
+ DigitalOut decimal_point(p25);
+
+ while (true) {
+ led3 = currentPlayer;
+ whiteLED = currentPlayer;
+ blackLED = !currentPlayer;
+ if (!gameActive) {
+ time_left = programTimeSetting;
+ }
+ else if (currentPlayer == black) {
+ //output: programTimeSetting - whiteTime.read()
+ time_left = programTimeSetting - timerBlack.read();
+ }
+ else {
+ //output: programTimeSetting - blackTime.read()
+ time_left = programTimeSetting - timerWhite.read();
+ }
+
+ // calculate digit values for display
+ min2 = time_left / 600;
+ min1 = (time_left - 600*min2) / 60;
+ sec2 = (time_left - 600*min2 - 60*min1) / 10;
+ sec1 = (time_left - 600*min2 - 60*min1 - 10*sec2) / 1;
+
+ // write 7seg display digits
+ digit_select = D4;
+ digit_value = digits[min2];
+ decimal_point = 0;
+ Thread::wait(1);
+ digit_select = D3;
+ digit_value = digits[min1];
+ decimal_point = 1;
+ Thread::wait(1);
+ digit_select = D2;
+ digit_value = digits[sec2];
+ decimal_point = 0;
+ Thread::wait(1);
+ digit_select = D1;
+ digit_value = digits[sec1];
+ decimal_point = 0;
+ Thread::wait(1);
+ }
+}
+
+//INITIALIZING FUNCTIONS--------------------------------------------------------------------------------------------------------------------------
+
+void initializeButtons() {
+ blackLED = 0;
+ whiteLED = 0;
+ Select.mode(PullUp);
+ Menu.mode(PullUp);
+}
+
+void initializeVariables() {
+ currentPlayer = white;
+ positionX = 0;
+ positionY = 0;
+ pieceSelected = false;
+ timerWhite.stop();
+ timerWhite.reset();
+ timerBlack.stop();
+ timerBlack.reset();
+}
+
+void initializeLCD() {
+ uLCD.baudrate(BAUD_3000000); //jack up baud rate to max for fast display
+ uLCD.display_control(PORTRAIT);
+ uLCD.text_mode(TRANSPARENT);
+ uLCD.cls();
+ uLCD.printf("ChessDude");
+ wait(1.0);
+ uLCD.cls();
+ drawGameBoard();
+}
+
+void initialize() {
+ initializeButtons();
+ initializeVariables();
+ initializeLCD();
+}
+
+
+//DRAW FUNCTIONS----------------------------------------------------------------------------------------------------------------------------------
+
+void drawMenuLine(int line) {
+ uLCD.filled_rectangle(1, 32*line+1, 127, 32*line+31, WHITE);
+ uLCD.text_mode(TRANSPARENT);
+ switch (line) {
+ case 0: {
+ if (playSound)
+ uLCD.text_string("SOUND: ON", 4, 2, FONT_7X8, BLACK);
+ else
+ uLCD.text_string("SOUND: OFF", 4, 2, FONT_7X8, BLACK);
+ break;
+ }
+ case 1: {
+ char text[13] = {"TIME: XX MIN"};
+ text[6] = (char)(programTimeSetting/600);
+ text[7] = (char)((programTimeSetting/60)%10);
+ uLCD.text_string(text, 4, 6, FONT_7X8, BLACK);
+ break;
+ }
+ case 2: {
+ //unclear
+ break;
+ }
+ case 3: {
+ uLCD.text_string("RESTART", 4, 14, FONT_7X8, BLACK);
+ break;
+ }
+ }
+}
+
+void drawMenuSelection(int color) {
+ uLCD.line(0,32*menuSelectionIndex,128,32*menuSelectionIndex, color);
+ uLCD.line(0,32*menuSelectionIndex,0,32*menuSelectionIndex+32, color);
+ uLCD.line(0,32*menuSelectionIndex+32,128,32*menuSelectionIndex+32, color);
+ uLCD.line(128,32*menuSelectionIndex+32,128,32*menuSelectionIndex, color);
+}
+
+
+void drawSelectionBox(int x, int y, int color) {
+ //draw 4 lines around the box in the color selected
+ if (x < 0 || x >= 8 || y < 0 || y >= 8) return;
+ int startX = x*boxWidth + 1;
+ int endX = (x+1)*boxWidth - 1;
+ int startY = y*boxWidth + 1;
+ int endY = (y+1)*boxWidth - 1;
+ uLCD.line(startX, startY, startX, endY-y/7, color);
+ uLCD.line(startX, endY-y/7, endX-x/7, endY-y/7, color);
+ uLCD.line(endX-x/7, endY-y/7, endX-x/7, startY, color);
+ uLCD.line(endX-x/7, startY, startX, startY, color);
+}
+
+void drawPiece(int x, int y, int piece) {
+ //draws a piece in a specific box (including NONE, which draws a black rectangle to erase)
+ uLCD.text_mode(TRANSPARENT);
+ int textColor = WHITE;
+ if (color[x][y] == black) textColor = RED;
+ switch (piece) {
+ case NONE: {
+ uLCD.filled_rectangle(x*boxWidth+2, y*boxWidth+2, x*boxWidth+boxWidth-2, y*boxWidth+boxWidth-2, BLACK);
+ break;
+ }
+ case KING: {
+ //uLCD.text_char('K', x*2.3+1, y*2+1, textColor);
+ int king[14*14] = {
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor,
+ BLACK, BLACK, textColor, textColor, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor,
+ BLACK, BLACK, textColor, textColor, BLACK, BLACK, textColor, BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor,
+ textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor,
+ textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, textColor, textColor, BLACK, BLACK, textColor, BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, textColor, textColor, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK
+ };
+ uLCD.BLIT(x*boxWidth+1, y*boxWidth+1, boxWidth-2-x/8, boxWidth-2-y/8, king);
+ break;
+ }
+ case QUEEN: {
+ //uLCD.text_char('Q', x*2.3+1, y*2+1, textColor);
+ int queen[14*14] = {
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, textColor, textColor, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor,
+ BLACK, BLACK, BLACK, textColor, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, textColor, textColor, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, textColor, textColor, BLACK, textColor, BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor,
+ BLACK, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor,
+ BLACK, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, textColor, textColor, BLACK, textColor, BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, textColor, textColor, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, textColor, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor,
+ BLACK, BLACK, textColor, textColor, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK
+ };
+ uLCD.BLIT(x*boxWidth+1, y*boxWidth+1, boxWidth-2-x/8, boxWidth-2-y/8, queen);
+ break;
+ }
+ case BISHOP: {
+ //uLCD.text_char('B', x*2.3+1, y*2+1, textColor);
+ int bishop[14*14] = {
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, textColor, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor, BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor, BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, textColor, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK
+ };
+ uLCD.BLIT(x*boxWidth+1, y*boxWidth+1, boxWidth-2-x/8, boxWidth-2-y/8, bishop);
+ break;
+ }
+ case KNIGHT: {
+ //uLCD.text_char('N', x*2.3+1, y*2+1, textColor);
+ int knight[14*14] = {
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, textColor, BLACK, textColor, BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor, BLACK, BLACK, textColor, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, textColor, BLACK, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor, textColor, textColor, BLACK, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor, BLACK, BLACK, BLACK, BLACK, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK
+ };
+ uLCD.BLIT(x*boxWidth+1, y*boxWidth+1, boxWidth-2-x/8, boxWidth-2-y/8, knight);
+ break;
+ }
+ case ROOK: {
+ //uLCD.text_char('R', x*2.3+1, y*2+1, textColor);
+ int rook[14*14] = {
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, textColor, textColor, textColor, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor,
+ BLACK, BLACK, BLACK, textColor, textColor, textColor, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, textColor, textColor, textColor, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, textColor, textColor, textColor, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK
+ };
+ uLCD.BLIT(x*boxWidth+1, y*boxWidth+1, boxWidth-2-x/8, boxWidth-2-y/8, rook);
+ break;
+ }
+ case PAWN: {
+ //uLCD.text_char('P', x*2.3+1, y*2+1, textColor);
+ int pawn[14*14] = {
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, BLACK, BLACK, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor, textColor, textColor, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, BLACK, BLACK, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, textColor, textColor,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
+ BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK
+ };
+ uLCD.BLIT(x*boxWidth+1, y*boxWidth+1, boxWidth-2-x/8, boxWidth-2-y/8, pawn);
+ break;
+ }
+ default:
+ return;
+ }
+}
+
+void drawGameBoard() {
+ uLCD.cls();
+ for (int i = 0; i < 9; i++) {
+ uLCD.line(i*boxWidth-i/8, 0, i*boxWidth-i/8, 128, 0xFFFFFF);
+ uLCD.line(0, i*boxWidth-i/8, 128, i*boxWidth-i/8, 0xFFFFFF);
+ }
+ for (int i = 0; i < 8; i++) {
+ for (int j = 0; j < 8; j++) {
+ drawPiece(i, j, board[i][j]);
+ }
+ }
+ if (pieceSelected) {
+ drawSelectionBox(selectedX, selectedY, RED);
+ }
+ drawSelectionBox(positionX, positionY, GREEN);
+}
+
+
+//MENU FUNCTIONS----------------------------------------------------------------------------------------------------------------------------------
+
+void closeMenu() {
+ uLCD.cls();
+ drawGameBoard();
+ menuOpen = false;
+ menuSelectionIndex = 0;
+}
+
+void openMenu() {
+ uLCD.cls();
+ for (int i = 0; i < 4; i++) {
+ drawMenuLine(i);
+ }
+ drawMenuSelection(GREEN);
+ menuOpen = true;
+}
+
+void menuSelectHandler() {
+ switch (menuSelectionIndex) {
+ case 0:
+ playSound = !playSound;
+ break;
+ case 1:
+ switch (programTimeSetting) {
+ case 300:
+ programTimeSetting = 600;
+ break;
+ case 600:
+ programTimeSetting = 900;
+ break;
+ case 900:
+ programTimeSetting = 1200;
+ break;
+ case 1200:
+ programTimeSetting = 1800;
+ break;
+ case 1800:
+ programTimeSetting = 3600;
+ break;
+ case 3600:
+ programTimeSetting = 300;
+ break;
+ default:
+ programTimeSetting = 600;
+ break;
+ }
+ break;
+ case 2:
+ //unclear
+ case 3:
+ initialize();
+ return;
+ default:
+ break;
+ }
+ drawMenuLine(menuSelectionIndex);
+}
+
+void moveMenuSelection(int direction) {
+ if (direction == RIGHT || direction == LEFT) return;
+ drawMenuSelection(BLACK);
+ if (direction == FORWARD) {
+ menuSelectionIndex++;
+ if (menuSelectionIndex > 3) menuSelectionIndex = 0;
+ }
+ if (direction == BACKWARD) {
+ menuSelectionIndex--;
+ if (menuSelectionIndex < 0) menuSelectionIndex = 3;
+ }
+ drawMenuSelection(GREEN);
+}
+
+void menuHandler() {
+ int move = waitForInput();
+ if (move == MENU) {
+ closeMenu();
+ return;
+ }
+ if (move == SELECT) {
+ menuSelectHandler();
+ return;
+ }
+ moveMenuSelection(move);
+}
+
+//GAME FUNCTIONS----------------------------------------------------------------------------------------------------------------------------------
+
+void removeSelectionBox() {
+ switch (currentPiece) {
+ case KING:
+ for (int i = selectedX - 1; i <= selectedX + 1; i++) {
+ for (int j = selectedY - 1; j <= selectedY + 1; j++) {
+ drawSelectionBox(i, j, BLACK);
+ }
+ }
+ break;
+ case QUEEN:
+ for (int i = 0; i < 8; i++) {
+ drawSelectionBox(selectedX, i, BLACK);
+ drawSelectionBox(i, selectedY, BLACK);
+ drawSelectionBox(selectedX + i, selectedY + i, BLACK);
+ drawSelectionBox(selectedX - i, selectedY - i, BLACK);
+ }
+ break;
+ case BISHOP:
+ for (int i = 0; i < 8; i++) {
+ drawSelectionBox(selectedX + i, selectedY + i, BLACK);
+ drawSelectionBox(selectedX - i, selectedY - i, BLACK);
+ }
+ break;
+ case KNIGHT:
+ drawSelectionBox(selectedX, selectedY, BLACK);
+ drawSelectionBox(selectedX + 2, selectedY + 1, BLACK);
+ drawSelectionBox(selectedX + 1, selectedY + 2, BLACK);
+ drawSelectionBox(selectedX - 2, selectedY + 1, BLACK);
+ drawSelectionBox(selectedX - 1, selectedY + 2, BLACK);
+ drawSelectionBox(selectedX + 2, selectedY - 1, BLACK);
+ drawSelectionBox(selectedX + 1, selectedY - 2, BLACK);
+ drawSelectionBox(selectedX - 2, selectedY - 1, BLACK);
+ drawSelectionBox(selectedX - 1, selectedY - 2, BLACK);
+ break;
+ case ROOK:
+ for (int i = 0; i < 8; i++) {
+ drawSelectionBox(selectedX, i, BLACK);
+ drawSelectionBox(i, selectedY, BLACK);
+ }
+ break;
+ case PAWN:
+ drawSelectionBox(selectedX, selectedY, BLACK);
+ drawSelectionBox(selectedX, selectedY + 1, BLACK);
+ drawSelectionBox(selectedX, selectedY + 2, BLACK);
+ drawSelectionBox(selectedX + 1, selectedY + 1, BLACK);
+ drawSelectionBox(selectedX - 1, selectedY + 1, BLACK);
+ break;
+ }
+ drawSelectionBox(positionX, positionY, GREEN);
+}
+
+int waitForInput() {
+ //main loop which waits for input while in game
+ float calx = 0.0; // joystick hysteresis calibration (optional)
+ float caly = 0.0;
+ while (true) {
+ if (JoyY > (0.6+caly)) {
+ while (JoyY > (0.6+caly)) { Thread::wait(10); }
+ return FORWARD;
+ }
+ if (JoyY < (0.4+caly)) {
+ while (JoyY < (0.4+caly)) { Thread::wait(10); }
+ return BACKWARD;
+ }
+ if (JoyX > (0.6+calx)) {
+ while (JoyX > (0.6+calx)) { Thread::wait(10); }
+ return RIGHT;
+ }
+ if (JoyX < (0.4+calx)) {
+ while (JoyX < (0.4+calx)) { Thread::wait(10); }
+ return LEFT;
+ }
+ if (!Select) {
+ while (!Select) { Thread::wait(10); }
+ return SELECT;
+ }
+ if (!Menu) {
+ while (!Menu) { Thread::wait(10); }
+ return MENU;
+ }
+ Thread::wait(10);
+ }
+}
+
+void displayPossibleMoves() {
+ //highlights squares where a selected piece can move
+ //use a for loop to iterate over all possible positions (diagonals, lines, etc.)
+ //if piece is already and not opposite team don't highlight
+ //make sure not to highlight edge conditions (off board)
+ /*switch (currentPiece) {
+ case NONE:
+ //return false;
+ case KING:
+ //make sure it's opposite player's team or none
+ //check for castling (queenside and short)
+ for (int i = positionX - 1; i <= positionX + 1; i++) {
+ for (int j = positionY - 1; j <= positionY + 1; j++) {
+ //if (checkValidMove(KING, i, j)) {
+ // drawSelectionBox(i, j, YELLOW);
+ //}
+ }
+ }
+ if (board[positionX][positionY] == NONE)
+ //return true;
+ if (color[positionX][positionY] != currentPlayer)
+ //return true;
+ //return false;
+ case QUEEN:
+ //check it's on the lines
+ //check it's on diagonal
+ //make sure no pieces are in the way
+ //return false;
+ case BISHOP:
+ //check it's on diagonals
+ //make sure no pieces are in the way
+ //return false;
+ case KNIGHT:
+ //check that it's knight position
+ //make sure it's opposite player's team or none
+ //return false;
+ case ROOK:
+ //check it's on the lines
+ //make sure no pieces are in the way
+ //return false;
+ case PAWN:
+ //check en passant
+ //check no pieces in way
+ //check for take on diagonal
+ //return false;
+ default:
+ //return false;
+ }*/
+}
+
+void showGameEnd() {
+ //shows the end of the game
+ uLCD.cls();
+}
+
+bool checkValidMove(int x, int y) {
+ if (board[x][y] != NONE && color[x][y] == currentPlayer) return false; //handles moving onto own piece (and same space)
+ switch (currentPiece) {
+ case NONE:
+ return false;
+ case KING:
+ //make sure it's opposite player's team or none
+ //check for castling (queenside and short)
+ if (abs(x-selectedX) <= 1 && abs(y-selectedY) <= 1) {
+ if (board[x][y] == NONE || color[x][y] != currentPlayer) {
+ return true;
+ }
+ }
+ return false;
+ case QUEEN:
+ //check it's on the lines
+ //check it's on diagonal
+ //make sure no pieces are in the way
+ if (board[x][y] != NONE) return false;
+ if (x == selectedX) {
+ //check y direction in a line
+ if (selectedY < y) {
+ //if position is forward
+ for (int i = selectedY; i < y; i++) {
+ if (board[selectedX][i] != NONE) return false;
+ }
+ }
+ else {
+ //if position is backward
+ for (int i = selectedY; i > y; i--) {
+ if (board[selectedX][i] != NONE) return false;
+ }
+ }
+ return true;
+ }
+ else if (y == selectedY) {
+ //check x direction in a line
+ if (selectedX < x) {
+ //if position is forward
+ for (int i = selectedX; i < x; i++) {
+ if (board[i][selectedY] != NONE) return false;
+ }
+ }
+ else {
+ //if position is backward
+ for (int i = selectedX; i > x; i--) {
+ if (board[i][selectedY] != NONE) return false;
+ }
+ }
+ return true;
+ }
+ else if (abs(x - selectedX) == abs(y - selectedY)) {
+ //check diagonals
+ if (selectedX < x) {
+ if (selectedY < y) {
+ for (int i = 1; i < x - selectedX; i++) {
+ if (board[selectedX + i][selectedY + i] != NONE) return false;
+ }
+ }
+ else {
+ for (int i = 1; i < x - selectedX; i++) {
+ if (board[selectedX + i][selectedY - i] != NONE) return false;
+ }
+ }
+ }
+ if (selectedX > x) {
+ if (selectedY < y) {
+ for (int i = 1; i < selectedX - x; i++) {
+ if (board[selectedX - i][selectedY + i] != NONE) return false;
+ }
+ }
+ else {
+ for (int i = 1; i < selectedX - x; i++) {
+ if (board[selectedX - i][selectedY - i] != NONE) return false;
+ }
+ }
+ }
+ return true;
+ }
+ else {
+ return true;
+ }
+ case BISHOP:
+ //check it's on diagonals
+ //make sure no pieces are in the way
+ if (abs(x - selectedX) == abs(y - selectedY)) {
+ //check diagonals
+ if (selectedX < x) {
+ if (selectedY < y) {
+ for (int i = 1; i < x - selectedX; i++) {
+ if (board[selectedX + i][selectedY + i] != NONE) return false;
+ }
+ }
+ else {
+ for (int i = 1; i < x - selectedX; i++) {
+ if (board[selectedX + i][selectedY - i] != NONE) return false;
+ }
+ }
+ }
+ if (selectedX > x) {
+ if (selectedY < y) {
+ for (int i = 1; i < selectedX - x; i++) {
+ if (board[selectedX - i][selectedY + i] != NONE) return false;
+ }
+ }
+ else {
+ for (int i = 1; i < selectedX - x; i++) {
+ if (board[selectedX - i][selectedY - i] != NONE) return false;
+ }
+ }
+ }
+ return true;
+ }
+ else {
+ return false;
+ }
+ case KNIGHT:
+ //check that it's knight position
+ //make sure it's opposite player's team or none
+ if (abs(y - selectedY) == 2) {
+ if (abs(x - selectedX) == 1) {
+ return true;
+ }
+ }
+ else if (abs(y - selectedY) == 1) {
+ if (abs(x - selectedX) == 2) {
+ return true;
+ }
+ }
+ return false;
+ case ROOK:
+ //check it's on the lines
+ //make sure no pieces are in the way
+ if (x == selectedX) {
+ //check y direction in a line
+ if (selectedY < y) {
+ //if position is forward
+ for (int i = selectedY; i < y; i++) {
+ if (board[selectedX][i] != NONE) return false;
+ }
+ }
+ else {
+ //if position is backward
+ for (int i = selectedY; i > y; i--) {
+ if (board[selectedX][i] != NONE) return false;
+ }
+ }
+ return true;
+ }
+ else if (y == selectedY) {
+ //check x direction in a line
+ if (selectedX < x) {
+ //if position is forward
+ for (int i = selectedX; i < x; i++) {
+ if (board[i][selectedY] != NONE) return false;
+ }
+ }
+ else {
+ //if position is backward
+ for (int i = selectedX; i > x; i--) {
+ if (board[i][selectedY] != NONE) return false;
+ }
+ }
+ return true;
+ }
+ else {
+ return true;
+ }
+ case PAWN:
+ //check en passant
+ //check no pieces in way
+ //check for take on diagonal
+ //check for 2 moves on first row
+ if (currentPlayer == white && y <= selectedY) return false;
+ if (currentPlayer == black && y >= selectedY) return false;
+ if (x != selectedX) {
+ if (abs(x - selectedX) != 1) return false; //must be one diagonal space away
+ if (abs(y - selectedY) != 1) return false;
+ if (board[x][y] == NONE) return false; //must be taking a piece
+ return true;
+ }
+ else {
+ if (currentPlayer == white) {
+ if (selectedY == 1) {
+ if (y == 2 && board[x][y] == NONE) return true;
+ else if (y == 3 && board[x][y] == NONE && board[x][y - 1] == NONE) return true;
+ else return false;
+ }
+ else {
+ if (y == selectedY + 1) {
+ if (board[x][y] == NONE) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+ else {
+ if (selectedY == 6) {
+ if (y == 5 && board[x][y] == NONE) return true;
+ else if (y == 4 && board[x][y] == NONE && board[x][y + 1] == NONE) return true;
+ else return false;
+ }
+ else {
+ if (y == selectedY - 1) {
+ if (board[x][y] == NONE) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+ }
+ default:
+ return false;
+ }
+}
+
+void movePiece() {
+ //new position is viable, update location and change current player
+ if (!gameActive) gameActive = true;
+ if (board[positionX][positionY] == KING) {
+ showGameEnd();
+ return;
+ }
+ removeSelectionBox();
+ drawPiece(selectedX, selectedY, NONE);
+ board[positionX][positionY] = board[selectedX][selectedY];
+ color[positionX][positionY] = currentPlayer;
+ board[selectedX][selectedY] = NONE;
+ drawPiece(positionX, positionY, board[positionX][positionY]);
+ pieceSelected = false;
+ if (currentPlayer == white) {
+ timerWhite.stop();
+ timerBlack.start();
+ }
+ if (currentPlayer == black) {
+ timerBlack.stop();
+ timerWhite.start();
+ }
+ speakerOut.PlayNote(2000, .1, .25);
+ currentPlayer = !currentPlayer;
+}
+
+void moveSelectionBox(int direction) {
+ if (direction == NONE) {
+ drawSelectionBox(positionX, positionY, GREEN);
+ return;
+ }
+ if (direction == FORWARD && positionY == 7) return;
+ if (direction == BACKWARD && positionY == 0) return;
+ if (direction == RIGHT && positionX == 7) return;
+ if (direction == LEFT && positionX == 0) return;
+ if (pieceSelected && positionX == selectedX && positionY == selectedY) {
+ drawSelectionBox(positionX, positionY, RED);
+ }
+ else {
+ drawSelectionBox(positionX, positionY, BLACK);
+ }
+ if (direction == FORWARD) {
+ positionY++;
+ }
+ if (direction == BACKWARD) {
+ positionY--;
+ }
+ if (direction == RIGHT) {
+ positionX++;
+ }
+ if (direction == LEFT) {
+ positionX--;
+ }
+ speakerOut.PlayNote(500, .1, .25);
+ drawSelectionBox(positionX, positionY, GREEN);
+}
+
+bool checkValidSelection() {
+ if (board[positionX][positionY] != NONE) {
+ if (color[positionX][positionY] == currentPlayer) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void selectPiece() {
+ selectedX = positionX;
+ selectedY = positionY;
+ pieceSelected = true;
+ currentPiece = board[positionX][positionY];
+ displayPossibleMoves();
+}
+
+void deselectPiece() {
+ pieceSelected = false;
+ currentPiece = NONE;
+ removeSelectionBox();
+ moveSelectionBox(NONE);
+}
+
+void selectHandler() {
+ if (pieceSelected) {
+ if (positionX == selectedX && positionY == selectedY) {
+ deselectPiece();
+ }
+ if (checkValidMove(positionX, positionY)) {
+ movePiece();
+ }
+ }
+ else {
+ if (checkValidSelection()) {
+ selectPiece();
+ }
+ }
+}
+
+void gameHandler() {
+ if (menuOpen) return;
+ int move = waitForInput();
+ switch (move) {
+ case MENU:
+ openMenu();
+ return;
+ case SELECT:
+ selectHandler();
+ break;
+ default:
+ moveSelectionBox(move);
+ break;
+ }
+}
+
+//MAIN----------------------------------------------------------------------------------------------------------------------------------
+
+int main() {
+
+ initialize();
+
+ Thread timerThread(timer);
+
+ while (true) {
+ if (menuOpen) menuHandler();
+ else gameHandler();
+ }
+
+}