Josh Smith / Mbed 2 deprecated MobileChessStation

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

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();
+    }
+ 
+}