summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/chess.c440
-rw-r--r--src/chess.h17
-rw-r--r--src/chesshelpers.c154
-rw-r--r--src/chesshelpers.h31
-rw-r--r--src/console.c105
-rw-r--r--src/console.h12
-rw-r--r--src/fscomch.c97
-rw-r--r--src/fscomch.h24
-rw-r--r--src/vector.c48
-rw-r--r--src/vector.h21
10 files changed, 949 insertions, 0 deletions
diff --git a/src/chess.c b/src/chess.c
new file mode 100644
index 0000000..530bc79
--- /dev/null
+++ b/src/chess.c
@@ -0,0 +1,440 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "vector.h"
+#include "console.h"
+#include "chesshelpers.h"
+#include "fscomch.h"
+#include "chess.h"
+
+int main(int argc, char **argv) {
+ if(argc == 2) {
+ if(strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "--version") == 0) {
+ printf("Version 1.0.0\n");
+ exit(0);
+ }
+ }
+ //set up the board
+ int boardA[8][8] = {
+ { rook + 6, pawn + 6, 0, 0, 0, 0, pawn, rook },
+ { knight + 6, pawn + 6, 0, 0, 0, 0, pawn, knight },
+ { bishop + 6, pawn + 6, 0, 0, 0, 0, pawn, bishop },
+ { queen + 6, pawn + 6, 0, 0, 0, 0, pawn, queen },
+ { king + 6, pawn + 6, 0, 0, 0, 0, pawn, king },
+ { bishop + 6, pawn + 6, 0, 0, 0, 0, pawn, bishop },
+ { knight + 6, pawn + 6, 0, 0, 0, 0, pawn, knight },
+ { rook + 6, pawn + 6, 0, 0, 0, 0, pawn, rook }
+ };
+ //convert the array to pointers
+ int** pieces = malloc(8 * sizeof(int*));
+ for(int r = 0; r < 8; r++) {
+ pieces[r] = malloc(8 * sizeof(int));
+ for(int c = 0; c < 8; c++) {
+ pieces[r][c] = boardA[r][c];
+ }
+ }
+ board_t board = init_board(pieces);
+ /* try to acquire a lock on the local matchfile */
+ FILE* matchFile = try_lock_match();
+ match_t match;
+ if (matchFile != NULL) {
+ /* we are acting as the host--await a connection */
+ printf("awaiting connection\n");
+ match = await_match(matchFile, NULL);
+ printf("connection completed. match is %s\n", match.uuid);
+ }
+ else {
+ /* we are joining an existing match */
+ printf("attempting to join existing match\n");
+ match = join_match();
+ if (match.uuid != NULL) {
+ printf("joined match %s\n", match.uuid);
+ }
+ else {
+ printf("error joining match. reload the program\n");
+ }
+ }
+ exit(0);
+ int turn = 0;
+ while(1) {
+ //draw the board, write some info
+ clear_screen();
+ draw_board(board.pieces);
+ printf(turn == 0 ? "\nWhite's turn\n" : "\nBlack's turn\n");
+ if(is_in_check(board, turn)) {
+ vectorpp_t allMoves = get_all_moves(board, turn, 0);
+ int checkmate = 0;
+ for(int i = 0; i < allMoves.length; i++) {
+ if(allMoves.vectorps[i].length > 0) {
+ checkmate = 0;
+ break;
+ }
+ else {
+ checkmate = 1;
+ }
+ }
+ if(checkmate) {
+ printf("You've been checkmated!\n");
+ break;
+ }
+ else {
+ printf("You're in check!\n");
+ }
+ }
+ printf("Enter the coordinates of the piece you want to move\n");
+ //get the selection for the piece to be moved
+ vector_t selection = user_input_pos();
+ int selectedPiece = board.pieces[selection.mx][selection.my];
+ //check if the piece is of the right colour, and that there is a piece there
+ if(selectedPiece == 0 || (selectedPiece > 6 && turn == 0) || (selectedPiece <= 6 && turn == 1)) {
+ warn_user("Invalid selection!");
+ continue;
+ }
+ printf("Selected piece: ");
+ printf("%d", selectedPiece);
+ printf("\n");
+ vectorp_t moves = get_moves_final(board, selection, selectedPiece);
+ if(moves.length == 0) {
+ warn_user("That piece has no valid moves!");
+ continue;
+ }
+ printf("Valid moves: ");
+ //write all the valid moves
+ for(int i = 0; i < moves.length; i++) {
+ char* readable_coords = get_move_name(board, selection, moves.vectors[i]);
+ printf(readable_coords);
+ free(readable_coords);
+ printf("; ");
+ }
+ printf("\nEnter the coordinates you would like to move that piece to, or enter < to go back\n");
+ //get the selection for the location to move the piece to
+ vector_t target = user_input_pos();
+ if(target.mx == -1) {
+ continue;
+ }
+ //check if target is in list of valid moves
+ int match = 0;
+ for(int i = 0; i < moves.length; i++) {
+ if(moves.vectors[i].mx == target.mx && moves.vectors[i].my == target.my) {
+ match = 1;
+ break;
+ }
+ }
+ if(!match) {
+ warn_user("Invalid move");
+ continue;
+ }
+ board = make_move(board, selection, target);
+ free(moves.vectors);
+ printf("\n");
+ turn = !turn;
+ }
+ return 0;
+}
+//this function returns moves that will place the player in check!
+vectorp_t get_moves(board_t board, vector_t position, piece_t piece) {
+ int color = 0;
+ if(piece > 6) {
+ color = 1;
+ piece -= 6;
+ }
+ if(piece == pawn) {
+ return get_pawn_moves(board, position, color);
+ }
+ else if(piece == knight) {
+ return get_knight_moves(board, position, color);
+ }
+ else if(piece == bishop) {
+ return get_bishop_moves(board, position, color);
+ }
+ else if(piece == rook) {
+ return get_rook_moves(board, position, color);
+ }
+ else if(piece == queen) {
+ return get_queen_moves(board, position, color);
+ }
+ else if(piece == king) {
+ return get_king_moves(board, position, color);
+ }
+ else {
+ return init_vectorp(0, 0);
+ }
+}
+//array of arrays representing all the moves each piece of color can make
+//excludeKing flag prevents recursion with castling checks
+vectorpp_t get_all_moves(board_t board, int color, int excludeKing) {
+ vectorp_t* allMoves = malloc(16 * sizeof(vectorp_t));
+ int pieceCount = 0;
+ for(int r = 0; r < 8; r++) {
+ for(int c = 0; c < 8; c++) {
+ vector_t v = init_vector(c, r);
+ if(is_color(board, v, color) && (!excludeKing || (board.pieces[v.mx][v.my] != king && board.pieces[v.mx][v.my] != king + 6))) {
+ allMoves[pieceCount] = get_moves(board, v, board.pieces[c][r]);
+ pieceCount++;
+ }
+ }
+ }
+ allMoves = realloc(allMoves, pieceCount * sizeof(vectorp_t));
+ return init_vectorpp(allMoves, pieceCount);
+}
+//returns the position of color's king
+vector_t get_king_position(board_t board, int color) {
+ for(int r = 0; r < 8; r++) {
+ for(int c = 0; c < 8; c++) {
+ if(board.pieces[c][r] == (king + color * 6)) {
+ return init_vector(c, r);
+ }
+ }
+ }
+}
+//returns true if the player of color is currently in check
+int is_in_check(board_t board, int color) {
+ int returnV = 0;
+ vector_t kingPos = get_king_position(board, color);
+ //get all the moves for the opponent
+ vectorpp_t allMoves = get_all_moves(board, !color, 1);
+ for(int i = 0; i < allMoves.length; i++) {
+ vectorp_t moves = allMoves.vectorps[i];
+ for(int j = 0; j < moves.length; j++) {
+ if(moves.vectors[j].mx == kingPos.mx && moves.vectors[j].my == kingPos.my) {
+ returnV = 1;
+ }
+ }
+ free(moves.vectors);
+ }
+ free(allMoves.vectorps);
+ return returnV;
+}
+//this function removes moves that place you in check
+vectorp_t get_moves_final(board_t board, vector_t position, piece_t piece) {
+ int color = 0;
+ if(piece > 6) {
+ color = 1;
+ }
+ vectorp_t moves = get_moves(board, position, piece);
+ //try making that move, see if it puts the player in check
+ int* invalidMoves = malloc(moves.length * sizeof(int));
+ int invalidMovesCount = 0;
+ for(int i = 0; i < moves.length; i++) {
+ board_t tempBoard = make_move(clone_board(board), position, moves.vectors[i]);
+ if(is_in_check(tempBoard, color)) {
+ invalidMoves[invalidMovesCount] = i;
+ invalidMovesCount++;
+ }
+ free(tempBoard.pieces);
+ }
+ vectorp_t finalMoves = remove_vectors(moves, invalidMoves, invalidMovesCount);
+ free(invalidMoves);
+ free(moves.vectors);
+ return finalMoves;
+}
+vectorp_t get_pawn_moves(board_t board, vector_t position, int color) {
+ vector_t* moves = malloc(6 * sizeof(vector_t));
+ int moveCount = 0;
+ int forwardDir = (color == 0 ? -1 : 1);
+ vector_t move1 = init_vector(position.mx, position.my + forwardDir);
+ if(in_board(move1) && is_empty(board, move1)) {
+ moves[moveCount] = move1;
+ moveCount++;
+ if(position.my == (color == 0 ? 6 : 1)) {
+ vector_t move2 = init_vector(position.mx, position.my + (forwardDir * 2));
+ if(is_empty(board, move2)) {
+ moves[moveCount] = move2;
+ moveCount++;
+ }
+ }
+ }
+ vector_t captureL = init_vector(position.mx - 1, position.my + forwardDir);
+ if(in_board(captureL) && (is_color(board, captureL, !color) || would_have_been_pawn(board, captureL, !color))) {
+ moves[moveCount] = captureL;
+ moveCount++;
+ }
+ vector_t captureR = init_vector(position.mx + 1, position.my + forwardDir);
+ if(in_board(captureR) && (is_color(board, captureR, !color) || would_have_been_pawn(board, captureR, !color))) {
+ moves[moveCount] = captureR;
+ moveCount++;
+ }
+ return init_vectorp(moves, moveCount);
+}
+vectorp_t get_knight_moves(board_t board, vector_t position, int color) {
+ vector_t* moves = malloc(8 * sizeof(vector_t));
+ int moveCount = 0;
+ for(int i = 0; i < 8; i++) {
+ int h = ((i == 0 || i == 1) ? 2 : (i == 2 || i == 3) ? -2 : (i == 4 || i == 5) ? 1 : -1);
+ int v = ((i == 0 || i == 2) ? -1 : (i == 1 || i == 3) ? 1 : (i == 4 || i == 6) ? 2 : -2);
+ vector_t move = init_vector(position.mx + h, position.my + v);
+ if(in_board(move) && (is_empty(board, move) || is_color(board, move, !color))) {
+ moves[moveCount] = move;
+ moveCount++;
+ }
+ }
+ return init_vectorp(moves, moveCount);
+}
+vectorp_t get_bishop_moves(board_t board, vector_t position, int color) {
+ vector_t* moves = malloc(14 * sizeof(vector_t));
+ int moveCount = 0;
+ for(int i = 0; i < 4; i++) {
+ int h = i < 2 ? 1 : -1;
+ int v = (i == 0 || i == 2) ? 1 : -1;
+ vector_t checkPos = init_vector(position.mx, position.my);
+ for(int d = 0; d < 7; d++) {
+ checkPos.mx += h;
+ checkPos.my += v;
+ if(in_board(checkPos)) {
+ if(is_empty(board, checkPos)) {
+ moves[moveCount] = init_vector(checkPos.mx, checkPos.my);
+ moveCount++;
+ }
+ else if(is_color(board, checkPos, !color)) {
+ moves[moveCount] = init_vector(checkPos.mx, checkPos.my);
+ moveCount++;
+ break;
+ }
+ else {
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ }
+ }
+ return init_vectorp(moves, moveCount);
+}
+vectorp_t get_rook_moves(board_t board, vector_t position, int color) {
+ vector_t* moves = malloc(14 * sizeof(vector_t));
+ int moveCount = 0;
+ for(int i = 0; i < 4; i++) {
+ int h = (i == 0 || i == 2) ? 0 : i == 1 ? 1 : -1;
+ int v = (i == 1 || i == 3) ? 0 : i == 2 ? 1 : -1;
+ vector_t checkPos = init_vector(position.mx, position.my);
+ for(int d = 0; d < 7; d++) {
+ checkPos.mx += h;
+ checkPos.my += v;
+ if(in_board(checkPos)) {
+ if(is_empty(board, checkPos)) {
+ moves[moveCount] = init_vector(checkPos.mx, checkPos.my);
+ moveCount++;
+ }
+ else if(is_color(board, checkPos, !color)) {
+ moves[moveCount] = init_vector(checkPos.mx, checkPos.my);
+ moveCount++;
+ break;
+ }
+ else {
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ }
+ }
+ return init_vectorp(moves, moveCount);
+}
+vectorp_t get_queen_moves(board_t board, vector_t position, int color) {
+ vector_t* moves = malloc(28 * sizeof(vector_t));
+ int moveCount = 0;
+ for(int i = 0; i < 8; i++) {
+ int h;
+ int v;
+ //diagonal moves
+ if(i < 4) {
+ h = i < 2 ? 1 : -1;
+ v = (i == 0 || i == 2) ? 1 : -1;
+ }
+ //straight moves
+ else {
+ h = (i == 4 || i == 6) ? 0 : i == 5 ? 1 : -1;
+ v = (i == 5 || i == 7) ? 0 : i == 6 ? 1 : -1;
+ }
+ vector_t checkPos = init_vector(position.mx, position.my);
+ for(int d = 0; d < 7; d++) {
+ checkPos.mx += h;
+ checkPos.my += v;
+ if(in_board(checkPos)) {
+ if(is_empty(board, checkPos)) {
+ moves[moveCount] = init_vector(checkPos.mx, checkPos.my);
+ moveCount++;
+ }
+ else if(is_color(board, checkPos, !color)) {
+ moves[moveCount] = init_vector(checkPos.mx, checkPos.my);
+ moveCount++;
+ break;
+ }
+ else {
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ }
+ }
+ return init_vectorp(moves, moveCount);
+}
+//TODO: don't allow king to move next to opposing king
+vectorp_t get_king_moves(board_t board, vector_t position, int color) {
+ //TODO: change size to 8
+ vector_t* moves = malloc(20 * sizeof(vector_t));
+ int moveCount = 0;
+ for(int i = 0; i < 8; i++) {
+ int h;
+ int v;
+ //diagonal moves
+ if(i < 4) {
+ h = i < 2 ? 1 : -1;
+ v = (i == 0 || i == 2) ? 1 : -1;
+ }
+ //straight moves
+ else {
+ h = (i == 4 || i == 6) ? 0 : i == 5 ? 1 : -1;
+ v = (i == 5 || i == 7) ? 0 : i == 6 ? 1 : -1;
+ }
+ vector_t move = init_vector(position.mx + h, position.my + v);
+ if(in_board(move) && (is_empty(board, move) || is_color(board, move, !color))) {
+ moves[moveCount] = move;
+ moveCount++;
+ }
+ }
+ //castling
+ if(!is_in_check(board, color)) {
+ //kingside castling
+ if((color == 0 && board.whiteCanCastleKingside) || (color == 1 && board.blackCanCastleKingside)) {
+ //check that the squares are free
+ vector_t s1 = init_vector(5, color == 0 ? 7 : 0);
+ vector_t s2 = init_vector(6, color == 0 ? 7 : 0);
+ if(is_empty(board, s1) && is_empty(board, s2)) {
+ //check that the squares are not threatened
+ board_t tempBoard1 = make_move(clone_board(board), position, s1);
+ board_t tempBoard2 = make_move(clone_board(board), position, s2);
+ if(!is_in_check(tempBoard1, color) && !is_in_check(tempBoard2, color)) {
+ //add the move
+ moves[moveCount] = s2;
+ moveCount++;
+ }
+ free(tempBoard1.pieces);
+ free(tempBoard2.pieces);
+ }
+ }
+ //queenside castling
+ if((color == 0 && board.whiteCanCastleQueenside) || (color == 1 && board.blackCanCastleQueenside)) {
+ //check that the squares are free
+ vector_t s1 = init_vector(3, color == 0 ? 7 : 0);
+ vector_t s2 = init_vector(2, color == 0 ? 7 : 0);
+ if(is_empty(board, s1) && is_empty(board, s2)) {
+ //check that the squares are not threatened
+ board_t tempBoard1 = make_move(clone_board(board), position, s1);
+ board_t tempBoard2 = make_move(clone_board(board), position, s2);
+ if(!is_in_check(tempBoard1, color) && !is_in_check(tempBoard2, color)) {
+ //add the move
+ moves[moveCount] = s2;
+ moveCount++;
+ }
+ free(tempBoard1.pieces);
+ free(tempBoard2.pieces);
+ }
+ }
+ }
+ return init_vectorp(moves, moveCount);
+}
diff --git a/src/chess.h b/src/chess.h
new file mode 100644
index 0000000..1d88a6e
--- /dev/null
+++ b/src/chess.h
@@ -0,0 +1,17 @@
+#include "vector.h"
+#include "console.h"
+#include "chesshelpers.h"
+#ifndef CHESS
+#define CHESS
+vectorp_t get_pawn_moves(board_t board, vector_t position, int color);
+vectorp_t get_knight_moves(board_t board, vector_t position, int color);
+vectorp_t get_bishop_moves(board_t board, vector_t position, int color);
+vectorp_t get_rook_moves(board_t board, vector_t position, int color);
+vectorp_t get_queen_moves(board_t board, vector_t position, int color);
+vectorp_t get_king_moves(board_t board, vector_t position, int color);
+vectorp_t get_moves(board_t board, vector_t position, piece_t piece);
+vectorpp_t get_all_moves(board_t board, int color, int excludeKing);
+vector_t get_king_position(board_t board, int color);
+int is_in_check(board_t board, int color);
+vectorp_t get_moves_final(board_t board, vector_t position, piece_t piece);
+#endif
diff --git a/src/chesshelpers.c b/src/chesshelpers.c
new file mode 100644
index 0000000..b64a0f4
--- /dev/null
+++ b/src/chesshelpers.c
@@ -0,0 +1,154 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "vector.h"
+#include "chesshelpers.h"
+
+board_t init_board(int** pieces) {
+ board_t board;
+ board.pieces = pieces;
+ board.whiteCanCastleKingside = 1;
+ board.whiteCanCastleQueenside = 1;
+ board.blackCanCastleKingside = 1;
+ board.blackCanCastleQueenside = 1;
+ board.lastPawnMove = -1;
+ return board;
+}
+//function applies side effects to board values like king move state
+board_t make_move(board_t board, vector_t origin, vector_t end) {
+ int piece = board.pieces[origin.mx][origin.my];
+ int captured = board.pieces[end.mx][end.my];
+ board.pieces[origin.mx][origin.my] = 0;
+ board.pieces[end.mx][end.my] = piece;
+ //white king moved
+ if(piece == king) {
+ board.whiteCanCastleQueenside = 0;
+ board.whiteCanCastleKingside = 0;
+ //if the king moved farther than it normally could, move must have been castling. move the rook as well
+ if(origin.mx == 4 && end.mx == 6) {
+ board = make_move(board, init_vector(7, 7), init_vector(5, 7));
+ }
+ else if(origin.mx == 4 && end.mx == 2) {
+ board = make_move(board, init_vector(0, 7), init_vector(3, 7));
+ }
+ }
+ //white kingside rook moved
+ else if(origin.mx == 7 && origin.my == 7) {
+ board.whiteCanCastleKingside = 0;
+ }
+ //white queenside rook moved
+ else if(origin.mx == 0 && origin.my == 7) {
+ board.whiteCanCastleQueenside = 0;
+ }
+ //black king moved
+ else if(piece == king + 6) {
+ board.blackCanCastleQueenside = 0;
+ board.blackCanCastleKingside = 0;
+ //if the king moved farther than it normally could, move must have been castling. move the rook as well
+ if(origin.mx == 4 && end.mx == 6) {
+ board = make_move(board, init_vector(7, 0), init_vector(5, 0));
+ }
+ else if(origin.mx == 4 && end.mx == 2) {
+ board = make_move(board, init_vector(0, 0), init_vector(3, 0));
+ }
+ }
+ //black kingside rook moved
+ else if(origin.mx == 7 && origin.my == 0) {
+ board.blackCanCastleKingside = 0;
+ }
+ //black queenside rook moved
+ else if(origin.mx == 0 && origin.my == 0) {
+ board.blackCanCastleQueenside = 0;
+ }
+ //this is not an else if! lastPawnMove must be reset
+ if(piece == pawn || piece == pawn + 6) {
+ board.lastPawnMove = origin.mx;
+ //check if move was an en passant capture
+ if(captured == 0 && origin.mx != end.mx) {
+ //kill the enemy pawn
+ board.pieces[end.mx][origin.my] = 0;
+ }
+ }
+ else {
+ //en passant no longer possible
+ board.lastPawnMove = -1;
+ }
+ return board;
+}
+board_t clone_board(board_t board) {
+ board_t newBoard = board;
+ int** pieces = malloc(8 * sizeof(int*));
+ for(int r = 0; r < 8; r++) {
+ pieces[r] = malloc(8 * sizeof(int));
+ for(int c = 0; c < 8; c++) {
+ pieces[r][c] = board.pieces[r][c];
+ }
+ }
+ newBoard.pieces = pieces;
+ return newBoard;
+}
+int in_board(vector_t position) {
+ return position.mx < 8 && position.mx >= 0 && position.my < 8 && position.my >= 0;
+}
+int is_empty(board_t board, vector_t position) {
+ return board.pieces[position.mx][position.my] == 0;
+}
+int is_color(board_t board, vector_t position, int color) {
+ if(color == 0) {
+ return board.pieces[position.mx][position.my] >= 1 && board.pieces[position.mx][position.my] <= 6;
+ }
+ else {
+ return board.pieces[position.mx][position.my] >= 7;
+ }
+}
+//returns true if a pawn that moved two squares would have been here if it moved one square
+int would_have_been_pawn(board_t board, vector_t position, int color) {
+ if(board.lastPawnMove == position.mx) {
+ if((position.my == 6 && color == 0) || (position.my == 2 && color == 1)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+//converts board coordinates into algebraic notation
+char* get_readable_coords(vector_t position) {
+ char* output = malloc(3 * sizeof(char));
+ output[0] = 'a' + position.mx;
+ output[1] = '8' - position.my;
+ output[2] = '\0';
+ return output;
+}
+//gets the proper algebraic notation for the move
+char* get_move_name(board_t board, vector_t origin, vector_t end) {
+ int piece = board.pieces[origin.mx][origin.my];
+ if(piece > 6) {
+ piece -= 6;
+ }
+ if(piece != 1) {
+ char cPiece = piece == pawn ? 'P' : piece == knight ? 'N' : piece == bishop ? 'B' : piece == rook ? 'R' : piece == queen ? 'Q' : 'K';
+ int isCapture = board.pieces[end.mx][end.my] != 0;
+ char* output = calloc(isCapture ? 5 : 4, sizeof(char));
+ output[0] = cPiece;
+ if(isCapture) {
+ output[1] = 'x';
+ }
+ char* rEnd = get_readable_coords(end);
+ strcat(output, rEnd);
+ free(rEnd);
+ output[isCapture ? 4 : 3] = '\0';
+ return output;
+ }
+ else {
+ int isCapture = board.pieces[end.mx][end.my] != 0;
+ char* output = calloc(isCapture ? 5 : 3, sizeof(char));
+ if(isCapture) {
+ output[0] = 'a' + origin.mx;
+ output[1] = 'x';
+ }
+ char* rEnd = get_readable_coords(end);
+ strcat(output, rEnd);
+ free(rEnd);
+ output[isCapture ? 4 : 2] = '\0';
+ return output;
+ }
+}
diff --git a/src/chesshelpers.h b/src/chesshelpers.h
new file mode 100644
index 0000000..b3a3d21
--- /dev/null
+++ b/src/chesshelpers.h
@@ -0,0 +1,31 @@
+#include "vector.h"
+#ifndef CHESS_HELPERS
+#define CHESS_HELPERS
+typedef enum {
+ pawn = 1,
+ knight = 2,
+ bishop = 3,
+ rook = 4,
+ queen = 5,
+ king = 6,
+} piece_t;
+typedef struct BoardState {
+ int** pieces;
+ //only falsified by moving the king or pawn
+ //does not consider check or empty squares
+ int whiteCanCastleKingside;
+ int whiteCanCastleQueenside;
+ int blackCanCastleKingside;
+ int blackCanCastleQueenside;
+ int lastPawnMove;
+} board_t;
+board_t init_board(int** pieces);
+board_t make_move(board_t board, vector_t origin, vector_t end);
+board_t clone_board(board_t board);
+int in_board(vector_t position);
+int is_empty(board_t board, vector_t position);
+int is_color(board_t board, vector_t position, int color);
+int would_have_been_pawn(board_t board, vector_t position, int color);
+char* get_readable_coords(vector_t position);
+char* get_move_name(board_t board, vector_t origin, vector_t end);
+#endif
diff --git a/src/console.c b/src/console.c
new file mode 100644
index 0000000..e675ba2
--- /dev/null
+++ b/src/console.c
@@ -0,0 +1,105 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "vector.h"
+#include "chesshelpers.h"
+#include "console.h"
+
+void draw_board(int** board) {
+ printf(" A B C D E F G H\n");
+ int tileColor = 0;
+ for(int r = 0; r < 8; r++) {
+ tileColor = !tileColor;
+ char* line = calloc(2 + (8 * 16) + 9, sizeof(char));
+ line[0] = '8' - r;
+ line[1] = ' ';
+ for(int c = 0; c < 8; c++) {
+ tileColor = !tileColor;
+ strcat(line, tileColor == 0 ? COLOR_CHESS_WHITE : COLOR_CHESS_BLACK);
+ if(board[c][r] <= 6) {
+ switch(board[c][r]) {
+ case 0:
+ strcat(line, " ");
+ break;
+ case pawn:
+ strcat(line, "P");
+ break;
+ case knight:
+ strcat(line, "N");
+ break;
+ case bishop:
+ strcat(line, "B");
+ break;
+ case rook:
+ strcat(line, "R");
+ break;
+ case queen:
+ strcat(line, "Q");
+ break;
+ case king:
+ strcat(line, "K");
+ break;
+ }
+ }
+ else {
+ switch(board[c][r] - 6) {
+ case pawn:
+ strcat(line, "p");
+ break;
+ case knight:
+ strcat(line, "n");
+ break;
+ case bishop:
+ strcat(line, "b");
+ break;
+ case rook:
+ strcat(line, "r");
+ break;
+ case queen:
+ strcat(line, "q");
+ break;
+ case king:
+ strcat(line, "k");
+ break;
+ }
+ }
+ strcat(line, COLOR_RESET " ");
+ }
+ printf(line);
+ printf("\n" COLOR_RESET);
+ free(line);
+ }
+}
+vector_t user_input_pos() {
+ char* inputString = malloc(3 * sizeof(char));
+ vector_t pos;
+ printf("Enter coordinates: ");
+ scanf("%2s", inputString);
+ for(int i = 0; i < 2; i++) {
+ if(inputString[i] <= '9' && inputString[i] >= '0') {
+ pos.my = 8 - (inputString[i] - '0');
+ }
+ else if(inputString[i] <= 'Z' && inputString[i] >= 'A') {
+ pos.mx = inputString[i] - 'A';
+ }
+ else if(inputString[i] <= 'z' && inputString[i] >= 'a') {
+ pos.mx = inputString[i] - 'a';
+ }
+ else {
+ return init_vector(-1, -1);
+ }
+ }
+ free(inputString);
+ return pos;
+}
+void clear_screen() {
+ system("@cls||clear");
+}
+void warn_user(char* message) {
+ clear_screen();
+ printf("\n" COLOR_WARN);
+ printf(message);
+ printf(COLOR_RESET "\nPress any key to continue...\n");
+ while(getchar() != '\n');
+ getchar();
+}
diff --git a/src/console.h b/src/console.h
new file mode 100644
index 0000000..c0ca9f7
--- /dev/null
+++ b/src/console.h
@@ -0,0 +1,12 @@
+#ifndef CONSOLE
+#define CONSOLE
+#define COLOR_CHESS_WHITE "\033[1;93;107m"
+#define COLOR_CHESS_BLACK "\033[1;93;100m"
+#define COLOR_WARN "\033[5;31;49m"
+#define COLOR_RESET "\033[0m"
+
+void draw_board(int** board);
+vector_t user_input_pos();
+void clear_screen();
+void warn_user(char* message);
+#endif
diff --git a/src/fscomch.c b/src/fscomch.c
new file mode 100644
index 0000000..a9fc27b
--- /dev/null
+++ b/src/fscomch.c
@@ -0,0 +1,97 @@
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/stat.h>
+#include "fscomch.h"
+
+match_t init_match(char* uuid, FILE* streamIn, FILE* streamOut) {
+ match_t match;
+ match.uuid = uuid;
+ match.streamIn = streamIn;
+ match.streamOut = streamOut;
+ return match;
+}
+void destroy_match(match_t match) {
+ free(match.uuid);
+ fclose(match.streamIn);
+ fclose(match.streamOut);
+}
+FILE* try_lock_match() {
+ mkdir("/tmp/chess/", 0777);
+ mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ int fd = open("/tmp/chess/match", O_RDONLY | O_CREAT | O_EXCL, mode);
+ if (fd == -1) {
+ return NULL;
+ }
+ return fdopen(fd, "r");
+}
+match_t await_match(FILE* matchFile, char* cancelToken) {
+ /* await match UUID */
+ char* uuid = calloc(37, sizeof(char));
+ while (cancelToken == NULL || *cancelToken) {
+ if (fgets(uuid, 37, matchFile) != NULL) {
+ break;
+ }
+ fseek(matchFile, 0, SEEK_SET);
+ struct timespec req;
+ req.tv_sec = 0;
+ req.tv_nsec = awaitMatchNs;
+ printf("sleeping\n");
+ nanosleep(&req, NULL);
+ }
+ /* connect to files created by joining player */
+ char aName[256];
+ char bName[256];
+ snprintf(aName, 256, "/tmp/chess/%s.a", uuid);
+ snprintf(bName, 256, "/tmp/chess/%s.b", uuid);
+ FILE* streamIn = fopen(aName, "r");
+ FILE* streamOut = fopen(bName, "w");
+ /* connection complete, delete the match file and the join lock */
+ remove("/tmp/chess/match");
+ remove("/tmp/chess/matchjoin");
+ return init_match(uuid, streamIn, streamOut);
+}
+match_t join_match() {
+ /* create a join lock so that no one else can join this match */
+ mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ int fd = open("/tmp/chess/matchjoin", O_WRONLY | O_CREAT | O_EXCL, mode);
+ if (fd == -1) {
+ /* another process is in the process of joining this game */
+ match_t match;
+ return match;
+ }
+ /* this is definitely the only process joining the game
+ proceed to generate a uuid */
+ char* uuid = make_uuid();
+ /* make the .a and .b files based on the uuid */
+ char aName[256];
+ char bName[256];
+ snprintf(aName, 256, "/tmp/chess/%s.a", uuid);
+ snprintf(bName, 256, "/tmp/chess/%s.b", uuid);
+ FILE* streamIn = fopen(bName, "w+");
+ FILE* streamOut = fopen(aName, "w");
+ match_t match = init_match(uuid, streamIn, streamOut);
+ /* send uuid to the host */
+ FILE* matchFile = fopen("/tmp/chess/match", "a");
+ fputs(uuid, matchFile);
+ /* joining match complete, close the descriptor */
+ close(fd);
+ return match;
+}
+char* make_uuid() {
+ char sym[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f'};
+ char* out = calloc(37, sizeof(char));
+ srand(time(NULL));
+ for (int i = 0; i < 36; i++) {
+ if (i == 8 || i == 13 || i == 18 || i == 23) {
+ out[i] = '-';
+ }
+ else {
+ out[i] = sym[rand() % 16];
+ }
+ }
+ out[37] = '\0';
+ return out;
+}
diff --git a/src/fscomch.h b/src/fscomch.h
new file mode 100644
index 0000000..b7900e3
--- /dev/null
+++ b/src/fscomch.h
@@ -0,0 +1,24 @@
+#include <stdio.h>
+#ifndef FSCOMCH
+#define FSCOMCH
+
+/* 1/2 second */
+static const unsigned long int awaitMatchNs = 500000000L;
+/* 1/4 second */
+static const unsigned long int awaitMoveNs = 250000000L;
+
+typedef struct Match {
+ char* uuid;
+ FILE* streamIn;
+ FILE* streamOut;
+} match_t;
+match_t init_match(char* uuid, FILE* streamIn, FILE* streamOut);
+void destroy_match(match_t match);
+/* returns null if the matchfile is already extant */
+FILE* try_lock_match();
+/* creates a new match, waits for it to be joined by another player */
+match_t await_match(FILE* matchFile, char* cancelToken);
+/* joins an existing match */
+match_t join_match();
+char* make_uuid();
+#endif
diff --git a/src/vector.c b/src/vector.c
new file mode 100644
index 0000000..6ab3bf2
--- /dev/null
+++ b/src/vector.c
@@ -0,0 +1,48 @@
+#include <stdlib.h>
+#include "vector.h"
+vector_t init_vector(int mx, int my) {
+ vector_t vector;
+ vector.mx = mx;
+ vector.my = my;
+ return vector;
+}
+vectorp_t init_vectorp(vector_t* vectors, int length) {
+ vectorp_t vectorP;
+ vectorP.vectors = vectors;
+ vectorP.length = length;
+ return vectorP;
+}
+vectorp_t remove_vector(vectorp_t vectorp, int index) {
+ vector_t* vectors = malloc((vectorp.length - 1) * sizeof(vector_t));
+ for(int i = 0; i < vectorp.length - 1; i++) {
+ int correctedIndex = i > index ? i - 1 : i;
+ if(i != index) {
+ vectors[correctedIndex] = vectorp.vectors[i];
+ }
+ }
+ return init_vectorp(vectors, vectorp.length - 1);
+}
+vectorp_t remove_vectors(vectorp_t vectorp, int* indexes, int indexCount) {
+ vector_t* vectors = malloc((vectorp.length - indexCount) * sizeof(vector_t));
+ int correctedIndex = 0;
+ for(int i = 0; i < vectorp.length - indexCount; i++) {
+ int toRemove = 0;
+ for(int j = 0; j < indexCount; j++) {
+ if(i == indexes[j]) {
+ toRemove = 1;
+ break;
+ }
+ }
+ if(!toRemove) {
+ vectors[correctedIndex] = vectorp.vectors[i];
+ correctedIndex++;
+ }
+ }
+ return init_vectorp(vectors, vectorp.length - indexCount);
+}
+vectorpp_t init_vectorpp(vectorp_t* vectorps, int length) {
+ vectorpp_t vectorPP;
+ vectorPP.vectorps = vectorps;
+ vectorPP.length = length;
+ return vectorPP;
+}
diff --git a/src/vector.h b/src/vector.h
new file mode 100644
index 0000000..ea2ddcd
--- /dev/null
+++ b/src/vector.h
@@ -0,0 +1,21 @@
+#ifndef VECTOR
+#define VECTOR
+typedef struct Vector {
+ int mx;
+ int my;
+} vector_t;
+vector_t init_vector(int mx, int my);
+typedef struct VectorP {
+ vector_t* vectors;
+ int length;
+} vectorp_t;
+vectorp_t init_vectorp(vector_t* vectors, int length);
+//removes a vector from vectorp
+vectorp_t remove_vector(vectorp_t vectorp, int index);
+vectorp_t remove_vectors(vectorp_t vectorp, int* indexes, int indexCount);
+typedef struct VectorPP {
+ vectorp_t* vectorps;
+ int length;
+} vectorpp_t;
+vectorpp_t init_vectorpp(vectorp_t* vectorps, int length);
+#endif