From e33dc4755fb08ed08f30b5e1af65457556d5bcb7 Mon Sep 17 00:00:00 2001 From: Kai Stevenson Date: Sun, 19 Mar 2023 23:20:53 -0700 Subject: fscomch--communication between multiple chess processes --- src/chess.c | 440 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/chess.h | 17 +++ src/chesshelpers.c | 154 +++++++++++++++++++ src/chesshelpers.h | 31 ++++ src/console.c | 105 +++++++++++++ src/console.h | 12 ++ src/fscomch.c | 97 ++++++++++++ src/fscomch.h | 24 +++ src/vector.c | 48 ++++++ src/vector.h | 21 +++ 10 files changed, 949 insertions(+) create mode 100644 src/chess.c create mode 100644 src/chess.h create mode 100644 src/chesshelpers.c create mode 100644 src/chesshelpers.h create mode 100644 src/console.c create mode 100644 src/console.h create mode 100644 src/fscomch.c create mode 100644 src/fscomch.h create mode 100644 src/vector.c create mode 100644 src/vector.h (limited to 'src') 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 +#include +#include +#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 +#include +#include +#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 +#include +#include +#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 +#include +#include +#include +#include +#include +#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 +#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 +#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 -- cgit v1.3.1