|
|
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <locale.h>
enum square_states { PAWN = 0x1, KNIGHT = 0x2, BISHOP = 0x4, ROOK = 0x8, QUEEN = 0x10, KING = 0x20, LIGHT = 0x40, DARK = 0x80 };
typedef struct { uint8_t flags; } square;
static square *board[8][8] = { { /* A */ &(square) { ROOK | LIGHT }, &(square) { PAWN | LIGHT }, NULL, NULL, NULL, NULL, &(square) { PAWN | DARK }, &(square) { ROOK | DARK } }, { /* B */ &(square) { KNIGHT | LIGHT }, &(square) { PAWN | LIGHT }, NULL, NULL, NULL, NULL, &(square) { PAWN | DARK }, &(square) { KNIGHT | DARK } }, { /* C */ &(square) { BISHOP | LIGHT }, &(square) { PAWN | LIGHT }, NULL, NULL, NULL, NULL, &(square) { PAWN | DARK }, &(square) { BISHOP | DARK } }, { /* D */ &(square) { QUEEN | LIGHT }, &(square) { PAWN | LIGHT }, NULL, NULL, NULL, NULL, &(square) { PAWN | DARK }, &(square) { QUEEN | DARK } }, { /* E */ &(square) { KING | LIGHT }, &(square) { PAWN | LIGHT }, NULL, NULL, NULL, NULL, &(square) { PAWN | DARK }, &(square) { KING | DARK } }, { /* F */ &(square) { BISHOP | LIGHT }, &(square) { PAWN | LIGHT }, NULL, NULL, NULL, NULL, &(square) { PAWN | DARK }, &(square) { BISHOP | DARK } }, { /* G */ &(square) { KNIGHT | LIGHT }, &(square) { PAWN | LIGHT }, NULL, NULL, NULL, NULL, &(square) { PAWN | DARK }, &(square) { KNIGHT | DARK } }, { /* H */ &(square) { ROOK | LIGHT }, &(square) { PAWN | LIGHT }, NULL, NULL, NULL, NULL, &(square) { PAWN | DARK }, &(square) { ROOK | DARK } } };
void draw_board_unicode() { for (int i = 0; i < 8; i++) { printf("\t%c ", '0' + 8 - i);
for (int j = 0; j < 8; j++) { // reset the color settings
printf("\033[0m");
square* s = board[j][7 - i];
// color the background of the squares
if ((i + j + 1) % 2 == 0) { printf("\033[0;100m"); } else { printf("\033[0;107m"); }
// fill in the blanks
if (s == NULL) { printf(" "); continue; }
// else, print the unicode character for the piece on that square
switch (s->flags) { case PAWN | LIGHT: printf("%lc ", 0x2659); break; case ROOK | LIGHT: printf("%lc ", 0x2656); break; case KNIGHT | LIGHT: printf("%lc ", 0x2658); break; case BISHOP | LIGHT: printf("%lc ", 0x2657); break; case QUEEN | LIGHT: printf("%lc ", 0x2655); break; case KING | LIGHT: printf("%lc ", 0x2654); break;
case PAWN | DARK: printf("%lc ", 0x265F); break; case ROOK | DARK: printf("%lc ", 0x265C); break; case KNIGHT | DARK: printf("%lc ", 0x265E); break; case BISHOP | DARK: printf("%lc ", 0x265D); break; case QUEEN | DARK: printf("%lc ", 0x265B); break; case KING | DARK: printf("%lc ", 0x265A); break; } }
printf("\033[0m\n"); }
printf("\t a b c d e f g h\n"); }
char* flags_to_string(int flags) { switch (flags) { case PAWN | LIGHT: return "white pawn"; case ROOK | LIGHT: return "white rook"; case KNIGHT | LIGHT: return "white knight"; case BISHOP | LIGHT: return "white bishop"; case QUEEN | LIGHT: return "white queen"; case KING | LIGHT: return "white king";
case PAWN | DARK: return "black pawn"; case ROOK | DARK: return "black root"; case KNIGHT | DARK: return "black knight"; case BISHOP | DARK: return "black bishop"; case QUEEN | DARK: return "black queen"; case KING | DARK: return "black king"; } }
void print_square(int x, int y, square* s) { printf("%d,%d - %s", x, y, flags_to_string(s->flags)); }
// all pieces can't move to a square if another piece of the same color occupies it
int validate_move(int x1, int y1, int x2, int y2) { if (board[x2][y2] && ((board[x1][y1]->flags | LIGHT) | DARK) == (((board[x2][y2]->flags | LIGHT) | DARK))) { return 0; }
return 1; }
int validate_pawn_move(int x1, int y1, int x2, int y2) { return validate_move(x1, y1, x2, y2); }
int validate_knight_move(int x1, int y1, int x2, int y2) { return validate_move(x1, y1, x2, y2); }
int validate_bishop_move(int x1, int y1, int x2, int y2) { if (+(x2 - x1) != +(y2 - y1)) { return 0; }
return validate_move(x1, y1, x2, y2); }
int validate_rook_move(int x1, int y1, int x2, int y2) { return validate_move(x1, y1, x2, y2); }
int validate_queen_move(int x1, int y1, int x2, int y2) { return validate_move(x1, y1, x2, y2); }
int validate_king_move(int x1, int y1, int x2, int y2) { return validate_move(x1, y1, x2, y2); }
int file_to_board_index(char c) { if (c >= 'a') { return c - 'a';
} else { return c - 'A'; } }
int rank_to_board_index(char c) { return c - '0' - 1; }
typedef int (*piece_move_validator)(int, int, int, int);
int turn = 1;
int handle_move(char in[6]) { int ix1 = file_to_board_index(in[0]); int iy1 = rank_to_board_index(in[1]); int ix2 = file_to_board_index(in[2]); int iy2 = rank_to_board_index(in[3]);
square* source = board[ix1][iy1];
if (source == NULL) { return -1; }
if ((turn == 0) && (source->flags & DARK) == 0) { return -3;
} else if ((turn == 1) && (source->flags & LIGHT) == 0) { return -4; }
piece_move_validator validate = NULL; switch ((source->flags & ~LIGHT) & ~DARK) { case PAWN: validate = validate_pawn_move; break; case KNIGHT: validate = validate_knight_move; break; case BISHOP: validate = validate_bishop_move; break; case ROOK: validate = validate_rook_move; break; case QUEEN: validate = validate_queen_move; break; case KING: validate = validate_king_move; break; }
if (!validate(ix1, iy1, ix2, iy2)) { return -2; }
board[ix2][iy2] = source; board[ix1][iy1] = NULL;
return 0; }
int validate_coordinate_notation(char in[4]) { for (int i = 0; i < 2; i++) { switch (in[i * 2]) { default: return -1;
case 'a': case 'A': case 'b': case 'B': case 'c': case 'C': case 'd': case 'D': case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': case 'h': case 'H': break; }
switch (in[i * 2 + 1]) { default: return -2;
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; } }
return 0; }
int main(void) { setlocale(LC_CTYPE, "");
char in[6]; do { printf("\n\n"); draw_board_unicode();
printf("\n\tmake moves by typing them in non-hyphenated coordinate notation ('e2e4', for example)\n\t> \033[5m%lc%c\033[0m", 0x2588, 0x8);
if (fgets(in, 6, stdin) == NULL) { return 1; }
if (validate_coordinate_notation(in) != 0) { printf("\tinvalid coordinate notation.\n"); fflush(stdin); continue; }
switch (handle_move(in)) { case -1: printf("\tthere isn't a piece on that square!\n"); continue; case -2: printf("\tinvalid move\n"); continue; case -3: case -4: printf("\tnot your turn."); continue; default: turn = !turn; break; }
} while (1);
return 0; }
|