diff --git a/headers/help.h b/headers/help.h new file mode 100644 index 0000000..56a533d --- /dev/null +++ b/headers/help.h @@ -0,0 +1,11 @@ +#ifndef HELP_H +#define HELP_H +#include "types.h" + +long long fullSet(sets *s); +long long fullSetBoth(game *g); +void print_bitboard(long long bitboard); +long long *findSet(game *g, long long bit); +long long *charToSet(game *g, char c); + +#endif diff --git a/headers/moves.h b/headers/moves.h new file mode 100644 index 0000000..298db2b --- /dev/null +++ b/headers/moves.h @@ -0,0 +1,6 @@ +#ifndef MOVES_H +#define MOVES_H +#include "types.h" +int pawnMove(game *g, move *moves); +int knightMove(game *g, move* moves); +#endif diff --git a/headers/types.h b/headers/types.h new file mode 100644 index 0000000..a1a7e84 --- /dev/null +++ b/headers/types.h @@ -0,0 +1,25 @@ +#ifndef TYPES_H +#define TYPES_H +#include + +typedef struct { + long long pawns; + long long knights; + long long bishops; + long long rooks; + long long queen; + long long king; +} sets; + +typedef struct { + sets white; + sets black; + bool whiteToMove; +} game; + +typedef struct { + int From; + int To; +} move; + +#endif diff --git a/main.c b/main.c deleted file mode 100644 index 0190fc5..0000000 --- a/main.c +++ /dev/null @@ -1,325 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#define BUFF_SIZE 4096 - -typedef struct { - long long pawns; - long long knights; - long long bishops; - long long rooks; - long long queen; - long long king; -} sets; - -typedef struct { - sets white; - sets black; - bool whiteToMove; -} game; - -typedef struct { - int From; - int To; -} move; - -game *fenGame(char *str); -void playMoves(game *g, char *moves); -long long *findSet(game *g, long long bit); -long long *charToSet(game *g, char c); -int pawnMove(game *g, move *moves); -int knightMove(game *g, move* moves); - -long long fullSet(sets *s) { - return s->bishops ^ s->king ^ s->knights ^ s->pawns ^ s->queen ^ s->rooks; -} - -long long fullSetBoth(game *g) { - return fullSet(&g->white) ^ fullSet(&g->black); -} - -void print_bitboard(long long bitboard) { - for (int i = 63; i >= 0; i--) { - // Check if the i-th bit is set - if ((bitboard >> i) & 1) { - printf("1 "); - } else { - printf("0 "); - } - // Print a newline every 8 bits (for rows) - if (i % 8 == 0) { - printf("\n"); - } - } - printf("\n"); -} - -int main() { - setbuf(stdin, NULL); - setbuf(stdout, NULL); - game *g = NULL; - - char line[BUFF_SIZE]; - char *lineRest, *token; - char ltz[] = "abcdefgh"; - int cnt = 0; - while (1) { - (void)fgets(line, sizeof(line), stdin); - size_t len = strlen(line); - if (len - 1) - line[len - 1] = '\0'; - token = strtok_r(line, " ", &lineRest); - if (!strcmp("uci", token)) { - printf("id name RatChess 0.0\n"); - printf("id author rat<3\n"); - printf("uciok\n"); - } else if (!strcmp("quit", token)) { - return 0; - } else if (!strcmp("setoption", token)) { - } else if (!strcmp("position", token)) { - token = strtok_r(lineRest, " ", &lineRest); - if (!strcmp("fen", token)) { - g = fenGame(lineRest + 1); - for (int i = 0; i < 6; i++) - token = strtok_r(lineRest, " ", &lineRest); - } else { - g = fenGame("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); - } - playMoves(g, lineRest); - } else if (!strcmp("ucinewgame", token)) { - } else if (!strcmp("isready", token)) { - printf("readyok\n"); - } else if (!strcmp("go", token)) { - - move mov[200]; - int cnt = knightMove(g, mov); - move *m = &mov[0]; - - char *end = ""; - int yTo, xTo, yFrom, xFrom; - xTo = m->To % 8; - yTo = m->To / 8 + 1; - xFrom = m->From % 8; - yFrom = m->From / 8 + 1; - - if ((g->whiteToMove && yTo == 8) || (!g->whiteToMove && yTo == 1)) { - // end = "q\n"; - end = "\n"; - } else { - end = "\n"; - } - printf("bestmove %c%d%c%d%s", ltz[xFrom], yFrom, ltz[xTo], yTo, end); - } - } -} - -long long *charToSet(game *g, char c) { - switch (c) { - case 'P': - return &g->white.pawns; - case 'N': - return &g->white.knights; - case 'B': - return &g->white.bishops; - case 'R': - return &g->white.rooks; - case 'Q': - return &g->white.queen; - case 'K': - return &g->white.king; - case 'p': - return &g->black.pawns; - case 'n': - return &g->black.knights; - case 'b': - return &g->black.bishops; - case 'r': - return &g->black.rooks; - case 'q': - return &g->black.queen; - case 'k': - return &g->black.king; - default: - return NULL; - } -} - -game *fenGame(char *str) { - int rank = 7; - int file = 0; - size_t pos = 0; - game *g; - g = malloc(sizeof(game)); - memset(g, 0, sizeof(game)); - - while (str[pos] != '\0' && str[pos] != ' ') { - char current_char = *str; - - if (isdigit(*str)) { - int empty_squares = *str - '0'; - file += empty_squares; - str++; - continue; - } - - if (current_char == '/') { - rank--; - file = 0; - str++; - continue; - } - - long long bit = 1LL << (rank * 8 + file); - long long *set = charToSet(g, *str); - if (set) - *set |= bit; - file++; - str++; - } - str++; - g->whiteToMove = (*str == 'w') ? true : false; - return g; -} - -void playMoves(game *g, char *moves) { - char *move; - move = strtok_r(moves, " ", &moves); - move = strtok_r(moves, " ", &moves); - while (move) { - long long bit = 1LL << ((move[1] - '0' - 1) * 8 + (move[0] - 'a')); - long long *set = findSet(g, bit); - if (!set) { - printf("info fuck\n"); - return; - } - *set &= (~bit); - bit = 1LL << ((move[3] - '0' - 1) * 8 + (move[2] - 'a')); - long long *tmp = findSet(g, bit); - if (tmp) - *tmp &= (~bit); - if (strlen(move) == 5) { - char c = move[4]; - if (g->whiteToMove) - c = toupper(c); - set = charToSet(g, c); - } - *set |= bit; - - move = strtok_r(moves, " ", &moves); - g->whiteToMove = !g->whiteToMove; - } -} - -long long *findSet(game *g, long long bit) { - if (g->white.pawns & bit) { - return &g->white.pawns; - } else if (g->white.knights & bit) { - return &g->white.knights; - } else if (g->white.bishops & bit) { - return &g->white.bishops; - } else if (g->white.rooks & bit) { - return &g->white.rooks; - } else if (g->white.queen & bit) { - return &g->white.queen; - } else if (g->white.king & bit) { - return &g->white.king; - } else if (g->black.pawns & bit) { - return &g->black.pawns; - } else if (g->black.knights & bit) { - return &g->black.knights; - } else if (g->black.bishops & bit) { - return &g->black.bishops; - } else if (g->black.rooks & bit) { - return &g->black.rooks; - } else if (g->black.queen & bit) { - return &g->black.queen; - } else if (g->black.king & bit) { - return &g->black.king; - } else { - return NULL; - } -} - -int knightMove(game *g, move *moves) { - long long knights = g->whiteToMove ? g->white.knights : g->black.knights; - long long occupied = g->whiteToMove ? fullSet(&g->white) : fullSet(&g->black); - - int kMoves[] = { - -17, -15, - -10, -6, - 6, 10, - 15, 17 - }; - int index = 0; - - for (int i = 0; i < 64; i++) { - long long bit = 1LL << i; - if (!(knights & bit)) - continue; - - for (int j = 0; j < 8; ++j) { - int to = i + kMoves[j]; - if (to < 0 || to > 64) - continue; - - int fromFile = i % 8; - int toFile = to % 8; - int fromRank = i / 8; - int toRank = to / 8; - - int fileDiff = abs(fromFile - toFile); - int rankDiff = abs(fromRank - toRank); - if (!((fileDiff == 1 && rankDiff == 2) || (fileDiff == 2 && rankDiff == 1))) - continue; - - long long destBit = 1LL << to; - if (occupied & destBit) // Skip if destination has friendly piece - continue; - - moves[index++] = (move){.From = i, .To = to}; - } - } - return index; -} - -int pawnMove(game *g, move *moves) { - long long pawns = g->whiteToMove ? g->white.pawns : g->black.pawns; - long long enemy = g->whiteToMove ? fullSet(&g->black) : fullSet(&g->white); - long long occupied = fullSetBoth(g); - - int movdir = g->whiteToMove ? 8 : -8; - int capLeft = g->whiteToMove ? 7 : -9; - int capRight = g->whiteToMove ? 9 : -7; - - size_t index = 0; - - for (int i = 0; i < 64; ++i) { - long long bit = 1LL << i; - if (!(pawns & bit)) - continue; - - // forword - int to = i + movdir; - if (to >= 0 && to < 64 && !(occupied & (1LL << to))) { - moves[index++] = (move){.From = i, .To = to}; - } - - // left - to = i + capLeft; - if (i % 8 > 0 && (to >= 0 && to < 64) && (enemy & (1LL << to))) { - moves[index++] = (move){.From = i, .To = to}; - } - - // right - to = i + capRight; - if (i % 8 < 7 && (to >= 0 && to < 64) && (enemy & (1LL << to))) { - moves[index++] = (move){.From = i, .To = to}; - } - } - return index; -} diff --git a/src/help.c b/src/help.c new file mode 100644 index 0000000..89ed7d8 --- /dev/null +++ b/src/help.c @@ -0,0 +1,87 @@ +#include +#include "types.h" + +long long fullSet(sets *s) { + return s->bishops ^ s->king ^ s->knights ^ s->pawns ^ s->queen ^ s->rooks; +} + +long long fullSetBoth(game *g) { + return fullSet(&g->white) ^ fullSet(&g->black); +} + +void print_bitboard(long long bitboard) { + for (int i = 63; i >= 0; i--) { + // Check if the i-th bit is set + if ((bitboard >> i) & 1) { + printf("1 "); + } else { + printf("0 "); + } + // Print a newline every 8 bits (for rows) + if (i % 8 == 0) { + printf("\n"); + } + } + printf("\n"); +} + +long long *findSet(game *g, long long bit) { + if (g->white.pawns & bit) { + return &g->white.pawns; + } else if (g->white.knights & bit) { + return &g->white.knights; + } else if (g->white.bishops & bit) { + return &g->white.bishops; + } else if (g->white.rooks & bit) { + return &g->white.rooks; + } else if (g->white.queen & bit) { + return &g->white.queen; + } else if (g->white.king & bit) { + return &g->white.king; + } else if (g->black.pawns & bit) { + return &g->black.pawns; + } else if (g->black.knights & bit) { + return &g->black.knights; + } else if (g->black.bishops & bit) { + return &g->black.bishops; + } else if (g->black.rooks & bit) { + return &g->black.rooks; + } else if (g->black.queen & bit) { + return &g->black.queen; + } else if (g->black.king & bit) { + return &g->black.king; + } else { + return NULL; + } +} + +long long *charToSet(game *g, char c) { + switch (c) { + case 'P': + return &g->white.pawns; + case 'N': + return &g->white.knights; + case 'B': + return &g->white.bishops; + case 'R': + return &g->white.rooks; + case 'Q': + return &g->white.queen; + case 'K': + return &g->white.king; + case 'p': + return &g->black.pawns; + case 'n': + return &g->black.knights; + case 'b': + return &g->black.bishops; + case 'r': + return &g->black.rooks; + case 'q': + return &g->black.queen; + case 'k': + return &g->black.king; + default: + return NULL; + } +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..094594a --- /dev/null +++ b/src/main.c @@ -0,0 +1,143 @@ +#include +#include +#include +#include +#include +#include +#include +#include "moves.h" +#include "types.h" +#include "help.h" + +#define BUFF_SIZE 4096 + +game *fenGame(char *str); +void playMoves(game *g, char *moves); +long long *findSet(game *g, long long bit); +long long *charToSet(game *g, char c); + +int main() { + setbuf(stdin, NULL); + setbuf(stdout, NULL); + game *g = NULL; + + char line[BUFF_SIZE]; + char *lineRest, *token; + char ltz[] = "abcdefgh"; + int cnt = 0; + while (1) { + (void)fgets(line, sizeof(line), stdin); + size_t len = strlen(line); + if (len - 1) + line[len - 1] = '\0'; + token = strtok_r(line, " ", &lineRest); + if (!strcmp("uci", token)) { + printf("id name RatChess 0.0\n"); + printf("id author rat<3\n"); + printf("uciok\n"); + } else if (!strcmp("quit", token)) { + return 0; + } else if (!strcmp("setoption", token)) { + } else if (!strcmp("position", token)) { + token = strtok_r(lineRest, " ", &lineRest); + if (!strcmp("fen", token)) { + g = fenGame(lineRest + 1); + for (int i = 0; i < 6; i++) + token = strtok_r(lineRest, " ", &lineRest); + } else { + g = fenGame("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); + } + playMoves(g, lineRest); + } else if (!strcmp("ucinewgame", token)) { + } else if (!strcmp("isready", token)) { + printf("readyok\n"); + } else if (!strcmp("go", token)) { + + move mov[200]; + int cnt = knightMove(g, mov); + move *m = &mov[0]; + + char *end = ""; + int yTo, xTo, yFrom, xFrom; + xTo = m->To % 8; + yTo = m->To / 8 + 1; + xFrom = m->From % 8; + yFrom = m->From / 8 + 1; + + if ((g->whiteToMove && yTo == 8) || (!g->whiteToMove && yTo == 1)) { + // end = "q\n"; + end = "\n"; + } else { + end = "\n"; + } + printf("bestmove %c%d%c%d%s", ltz[xFrom], yFrom, ltz[xTo], yTo, end); + } + } +} + +game *fenGame(char *str) { + int rank = 7; + int file = 0; + size_t pos = 0; + game *g; + g = malloc(sizeof(game)); + memset(g, 0, sizeof(game)); + + while (str[pos] != '\0' && str[pos] != ' ') { + char current_char = *str; + + if (isdigit(*str)) { + int empty_squares = *str - '0'; + file += empty_squares; + str++; + continue; + } + + if (current_char == '/') { + rank--; + file = 0; + str++; + continue; + } + + long long bit = 1LL << (rank * 8 + file); + long long *set = charToSet(g, *str); + if (set) + *set |= bit; + file++; + str++; + } + str++; + g->whiteToMove = (*str == 'w') ? true : false; + return g; +} + +void playMoves(game *g, char *moves) { + char *move; + move = strtok_r(moves, " ", &moves); + move = strtok_r(moves, " ", &moves); + while (move) { + long long bit = 1LL << ((move[1] - '0' - 1) * 8 + (move[0] - 'a')); + long long *set = findSet(g, bit); + if (!set) { + printf("info fuck\n"); + return; + } + *set &= (~bit); + bit = 1LL << ((move[3] - '0' - 1) * 8 + (move[2] - 'a')); + long long *tmp = findSet(g, bit); + if (tmp) + *tmp &= (~bit); + if (strlen(move) == 5) { + char c = move[4]; + if (g->whiteToMove) + c = toupper(c); + set = charToSet(g, c); + } + *set |= bit; + + move = strtok_r(moves, " ", &moves); + g->whiteToMove = !g->whiteToMove; + } +} + diff --git a/src/moves.c b/src/moves.c new file mode 100644 index 0000000..2284924 --- /dev/null +++ b/src/moves.c @@ -0,0 +1,85 @@ +#include "types.h" +#include "moves.h" +#include "help.h" +#include +#include + +int pawnMove(game *g, move *moves) { + long long pawns = g->whiteToMove ? g->white.pawns : g->black.pawns; + long long enemy = g->whiteToMove ? fullSet(&g->black) : fullSet(&g->white); + long long occupied = fullSetBoth(g); + + int movdir = g->whiteToMove ? 8 : -8; + int capLeft = g->whiteToMove ? 7 : -9; + int capRight = g->whiteToMove ? 9 : -7; + + size_t index = 0; + + for (int i = 0; i < 64; ++i) { + long long bit = 1LL << i; + if (!(pawns & bit)) + continue; + + // forword + int to = i + movdir; + if (to >= 0 && to < 64 && !(occupied & (1LL << to))) { + moves[index++] = (move){.From = i, .To = to}; + } + + // left + to = i + capLeft; + if (i % 8 > 0 && (to >= 0 && to < 64) && (enemy & (1LL << to))) { + moves[index++] = (move){.From = i, .To = to}; + } + + // right + to = i + capRight; + if (i % 8 < 7 && (to >= 0 && to < 64) && (enemy & (1LL << to))) { + moves[index++] = (move){.From = i, .To = to}; + } + } + return index; +} + + +int knightMove(game *g, move *moves) { + long long knights = g->whiteToMove ? g->white.knights : g->black.knights; + long long occupied = g->whiteToMove ? fullSet(&g->white) : fullSet(&g->black); + + int kMoves[] = { + -17, -15, + -10, -6, + 6, 10, + 15, 17 + }; + int index = 0; + + for (int i = 0; i < 64; i++) { + long long bit = 1LL << i; + if (!(knights & bit)) + continue; + + for (int j = 0; j < 8; ++j) { + int to = i + kMoves[j]; + if (to < 0 || to > 64) + continue; + + int fromFile = i % 8; + int toFile = to % 8; + int fromRank = i / 8; + int toRank = to / 8; + + int fileDiff = abs(fromFile - toFile); + int rankDiff = abs(fromRank - toRank); + if (!((fileDiff == 1 && rankDiff == 2) || (fileDiff == 2 && rankDiff == 1))) + continue; + + long long destBit = 1LL << to; + if (occupied & destBit) // Skip if destination has friendly piece + continue; + + moves[index++] = (move){.From = i, .To = to}; + } + } + return index; +}