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
main.cpp
- Committer:
- jsmith687
- Date:
- 2020-04-28
- Revision:
- 0:d9dcc0c3cd64
- Child:
- 1:4af874b42e33
File content as of revision 0:d9dcc0c3cd64:
/*
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();
}
}