bool apply_move (Game *g, int from, int to, char promote_in) { if (g->result != IN_PROGRESS) return FALSE; Board *board = current_board (g); Board *new_board = NEW_BOARD; char capture = 0; char *move_done = castling (board, castling_type (board, from, to), new_board); if (!move_done) // If move is not a castling { if (!try_move (board, from, to, promote_in, new_board, &move_done, &capture)) { free (new_board); return FALSE; } } // Ok move is legal, update the game update_castling (new_board, from); update_en_passant (new_board, from, to); if (new_board->active_color) new_board->fullmove_number++; new_board->active_color = !new_board->active_color; if (capture || toupper (board->placement[from]) == 'P') new_board->halfmove_clock = 0; else new_board->halfmove_clock++; g->boards[g->current] = new_board; g->moves[g->current] = move_done; g->coord_moves[g->current] = ft_to_coord_move (from, to, promote_in); g->current++; // Test check or checkmate of opponent king if (king_in_check (new_board, new_board->active_color)) { if (king_in_checkmate (new_board, new_board->active_color)) { strcat (move_done, "#"); g->result = !new_board->active_color; } else strcat (move_done, "+"); } // Test insufficient material else if (insufficient_material (new_board)) g->result = DRAW; // Test stalemate else if (stalemate (new_board, new_board->active_color)) g->result = DRAW; return TRUE; }
void do_chess( CHAR_DATA * ch, const char *argument ) { char arg[MAX_INPUT_LENGTH]; argument = one_argument( argument, arg ); if ( IS_NPC( ch ) ) { send_to_char( "NPC's can't be in chess games.\r\n", ch ); return; } if ( !str_cmp( arg, "begin" ) ) { GAME_BOARD_DATA *board; if ( ch->pcdata->game_board ) { send_to_char( "You are already in a chess match.\r\n", ch ); return; } CREATE( board, GAME_BOARD_DATA, 1 ); init_board( board ); ch->pcdata->game_board = board; ch->pcdata->game_board->player1 = QUICKLINK( ch->name ); send_to_char( "You have started a game of chess.\r\n", ch ); return; } if ( !str_cmp( arg, "join" ) ) { GAME_BOARD_DATA *board = NULL; CHAR_DATA *vch; char arg2[MAX_INPUT_LENGTH]; if ( ch->pcdata->game_board ) { send_to_char( "You are already in a game of chess.\r\n", ch ); return; } argument = one_argument( argument, arg2 ); if ( arg2[0] == '\0' ) { send_to_char( "Join whom in a chess match?\r\n", ch ); return; } #ifdef IMC if ( strstr( arg2, "@" ) ) { if ( !str_cmp( imc_mudof( arg2 ), this_imcmud->localname ) ) { send_to_char( "You cannot join IMC chess on the local mud!\r\n", ch ); return; } if ( !str_cmp( imc_mudof( arg2 ), "*" ) ) { send_to_char( "* is not a valid mud name.\r\n", ch ); return; } if ( !str_cmp( imc_nameof( arg2 ), "*" ) ) { send_to_char( "* is not a valid player name.\r\n", ch ); return; } send_to_char( "Attempting to initiate IMC chess game...\r\n", ch ); CREATE( board, GAME_BOARD_DATA, 1 ); init_board( board ); board->type = TYPE_IMC; board->player1 = QUICKLINK( ch->name ); board->player2 = STRALLOC( arg2 ); board->turn = -1; ch->pcdata->game_board = board; imc_send_chess( ch->name, arg2, "start" ); return; } #endif if ( !( vch = get_char_world( ch, arg2 ) ) ) { send_to_char( "Cannot find that player.\r\n", ch ); return; } if ( IS_NPC( vch ) ) { send_to_char( "That player is an NPC, and cannot play games.\r\n", ch ); return; } board = vch->pcdata->game_board; if ( !board ) { send_to_char( "That player is not playing a game.\r\n", ch ); return; } if ( board->player2 ) { send_to_char( "That game already has two players.\r\n", ch ); return; } board->player2 = QUICKLINK( ch->name ); ch->pcdata->game_board = board; send_to_char( "You have joined a game of chess.\r\n", ch ); vch = get_char_world( ch, board->player1 ); ch_printf( vch, "%s has joined your game.\r\n", ch->name ); return; } if ( !ch->pcdata->game_board ) { send_to_char( "Usage: chess <begin|cease|status|board|move|join>\r\n", ch ); return; } if ( !str_cmp( arg, "cease" ) ) { free_game( ch->pcdata->game_board ); return; } if ( !str_cmp( arg, "status" ) ) { GAME_BOARD_DATA *board = ch->pcdata->game_board; if ( !board->player1 ) send_to_char( "There is no black player.\r\n", ch ); else if ( !str_cmp( board->player1, ch->name ) ) send_to_char( "You are black.\r\n", ch ); else ch_printf( ch, "%s is black.\r\n", board->player1 ); if ( king_in_checkmate( board, BLACK_KING ) ) send_to_char( "The black king is in checkmate!\r\n", ch ); else if ( king_in_check( board, BLACK_KING ) ) send_to_char( "The black king is in check.\r\n", ch ); if ( !board->player2 ) send_to_char( "There is no white player.\r\n", ch ); else if ( !str_cmp( board->player2, ch->name ) ) send_to_char( "You are white.\r\n", ch ); else ch_printf( ch, "%s is white.\r\n", board->player2 ); if ( king_in_checkmate( board, WHITE_KING ) ) send_to_char( "The white king is in checkmate!\r\n", ch ); else if ( king_in_check( board, WHITE_KING ) ) send_to_char( "The white king is in check.\r\n", ch ); if ( !board->player2 || !board->player1 ) return; ch_printf( ch, "%d turns.\r\n", board->turn ); if ( board->turn % 2 == 1 && !str_cmp( board->player1, ch->name ) ) { ch_printf( ch, "It is %s's turn.\r\n", board->player2 ); return; } else if ( board->turn % 2 == 0 && !str_cmp( board->player2, ch->name ) ) { ch_printf( ch, "It is %s's turn.\r\n", board->player1 ); return; } else { send_to_char( "It is your turn.\r\n", ch ); return; } return; } if ( !str_prefix( arg, "board" ) ) { send_to_char( print_big_board( ch, ch->pcdata->game_board ), ch ); return; } if ( !str_prefix( arg, "move" ) ) { CHAR_DATA *opp; char opp_name[MAX_INPUT_LENGTH]; char a, b; int x, y, dx, dy, ret; if ( !ch->pcdata->game_board->player1 || !ch->pcdata->game_board->player2 ) { send_to_char( "There is only 1 player.\r\n", ch ); return; } if ( ch->pcdata->game_board->turn < 0 ) { send_to_char( "The game hasn't started yet.\r\n", ch ); return; } if ( king_in_checkmate( ch->pcdata->game_board, BLACK_KING ) ) { send_to_char( "The black king has been checkmated, the game is over.\r\n", ch ); return; } if ( king_in_checkmate( ch->pcdata->game_board, WHITE_KING ) ) { send_to_char( "The white king has been checkmated, the game is over.\r\n", ch ); return; } if ( !*argument ) { send_to_char( "Usage: chess move [piece to move] [where to move]\r\n", ch ); return; } if ( ch->pcdata->game_board->turn % 2 == 1 && !str_cmp( ch->pcdata->game_board->player1, ch->name ) ) { send_to_char( "It is not your turn.\r\n", ch ); return; } if ( ch->pcdata->game_board->turn % 2 == 0 && !str_cmp( ch->pcdata->game_board->player2, ch->name ) ) { send_to_char( "It is not your turn.\r\n", ch ); return; } if ( sscanf( argument, "%c%d %c%d", &a, &y, &b, &dy ) != 4 ) { send_to_char( "Usage: chess move [dest] [source]\r\n", ch ); return; } if ( a < 'a' || a > 'h' || b < 'a' || b > 'h' || y < 1 || y > 8 || dy < 1 || dy > 8 ) { send_to_char( "Invalid move, use a-h, 1-8.\r\n", ch ); return; } x = a - 'a'; dx = b - 'a'; --y; --dy; ret = is_valid_move( ch, ch->pcdata->game_board, x, y, dx, dy ); if ( ret == MOVE_OK || ret == MOVE_TAKEN ) { GAME_BOARD_DATA *board; int piece, destpiece; board = ch->pcdata->game_board; piece = board->board[x][y]; destpiece = board->board[dx][dy]; board->board[dx][dy] = piece; board->board[x][y] = NO_PIECE; if ( king_in_check( board, IS_WHITE( board->board[dx][dy] ) ? WHITE_KING : BLACK_KING ) && ( board->board[dx][dy] != WHITE_KING && board->board[dx][dy] != BLACK_KING ) ) { board->board[dx][dy] = destpiece; board->board[x][y] = piece; ret = MOVE_INCHECK; } else { ++board->turn; #ifdef IMC if ( ch->pcdata->game_board->type == TYPE_IMC ) { snprintf( arg, LGST, "move %d%d %d%d", x, y, dx, dy ); imc_send_chess( ch->pcdata->game_board->player1, ch->pcdata->game_board->player2, arg ); } #endif } } if ( !str_cmp( ch->name, ch->pcdata->game_board->player1 ) ) { opp = get_char_world( ch, ch->pcdata->game_board->player2 ); if ( !opp ) mudstrlcpy( opp_name, ch->pcdata->game_board->player2, MAX_INPUT_LENGTH ); } else { opp = get_char_world( ch, ch->pcdata->game_board->player1 ); if ( !opp ) mudstrlcpy( opp_name, ch->pcdata->game_board->player1, MAX_INPUT_LENGTH ); } #ifdef IMC # define SEND_TO_OPP(arg,opp) \ if( opp ) \ { \ if( ch->pcdata->game_board->type == TYPE_LOCAL ) \ ch_printf( (opp), "%s\r\n", (arg) ); \ } \ else \ { \ if( ch->pcdata->game_board->type == TYPE_IMC ) \ imc_send_tell( ch->name, opp_name, (arg), 1 ); \ } #else # define SEND_TO_OPP(arg,opp) \ if( opp ) \ { \ if( ch->pcdata->game_board->type == TYPE_LOCAL ) \ ch_printf( (opp), "%s\r\n", (arg) ); \ } #endif switch ( ret ) { case MOVE_OK: send_to_char( "Ok.\r\n", ch ); snprintf( arg, MAX_INPUT_LENGTH, "%s has moved.\r\n", ch->name ); SEND_TO_OPP( arg, opp ); break; case MOVE_INVALID: send_to_char( "Invalid move.\r\n", ch ); break; case MOVE_BLOCKED: send_to_char( "You are blocked in that direction.\r\n", ch ); break; case MOVE_TAKEN: send_to_char( "You take the enemy's piece.\r\n", ch ); snprintf( arg, MAX_INPUT_LENGTH, "%s has taken one of your pieces!", ch->name ); SEND_TO_OPP( arg, opp ); break; case MOVE_CHECKMATE: send_to_char( "That move would result in a checkmate.\r\n", ch ); snprintf( arg, MAX_INPUT_LENGTH, "%s has attempted a move that would result in checkmate.", ch->name ); SEND_TO_OPP( arg, opp ); break; case MOVE_OFFBOARD: send_to_char( "That move would be off the board.\r\n", ch ); break; case MOVE_SAMECOLOR: send_to_char( "Your own piece blocks the way.\r\n", ch ); break; case MOVE_CHECK: send_to_char( "That move would result in a check.\r\n", ch ); snprintf( arg, MAX_INPUT_LENGTH, "%s has made a move that would result in a check.", ch->name ); SEND_TO_OPP( arg, opp ); break; case MOVE_WRONGCOLOR: send_to_char( "That is not your piece.\r\n", ch ); break; case MOVE_INCHECK: send_to_char( "You are in check, you must save your king.\r\n", ch ); break; default: bug( "%s: Unknown return value", __FUNCTION__ ); break; } #undef SEND_TO_OPP return; } send_to_char( "Usage: chess <begin|cease|status|board|move|join>\r\n", ch ); }
/* A FEN string is composed of 6 parts separated by " " (space). 1. Piece placement (from white's perspective). 2. Active color. "w" means white moves next, "b" means black. 3. Castling availability. If neither side can castle, this is "-". 4. En passant target square in algebraic notation. If there's no en passant target square, this is "-". 5. Halfmove clock: this is the number of halfmoves since the last pawn advance or capture. 6. Fullmove number: the number of the full move. It starts at 1, and is incremented after black's move. */ void set_fen (Game *g, const char *fen) { Board *board = NEW_BOARD; int i = 0, j, k, square; char *pch; char *s = (char *) malloc (sizeof (char) * (strlen (fen) + 1)); strcpy (s, fen); // Init board memset (board->placement, '\0', 64); board->pawns[WHITE] = 0x0; board->pawns[BLACK] = 0x0; board->rooks[WHITE] = 0x0; board->rooks[BLACK] = 0x0; board->knights[WHITE] = 0x0; board->knights[BLACK] = 0x0; board->bishops[WHITE] = 0x0; board->bishops[BLACK] = 0x0; board->queens[WHITE] = 0x0; board->queens[BLACK] = 0x0; board->king[WHITE] = 0x0; board->king[BLACK] = 0x0; pch = strtok (s, " /"); while (pch != NULL) { if (i < 8) { for (j = 0, k = 0; j < (int) strlen (pch); j++) { if (pch[j] - 48 > 8) { square = (abs (i - 7) * 8) + k; switch (pch[j]) { case 'P': board->placement[square] = pch[j]; board->pawns[WHITE] ^= 1ULL << square; break; case 'p': board->placement[square] = pch[j]; board->pawns[BLACK] ^= 1ULL << square; break; case 'R': board->placement[square] = pch[j]; board->rooks[WHITE] ^= 1ULL << square; break; case 'r': board->placement[square] = pch[j]; board->rooks[BLACK] ^= 1ULL << square; break; case 'N': board->placement[square] = pch[j]; board->knights[WHITE] ^= 1ULL << square; break; case 'n': board->placement[square] = pch[j]; board->knights[BLACK] ^= 1ULL << square; break; case 'B': board->placement[square] = pch[j]; board->bishops[WHITE] ^= 1ULL << square; break; case 'b': board->placement[square] = pch[j]; board->bishops[BLACK] ^= 1ULL << square; break; case 'Q': board->placement[square] = pch[j]; board->queens[WHITE] ^= 1ULL << square; break; case 'q': board->placement[square] = pch[j]; board->queens[BLACK] ^= 1ULL << square; break; case 'K': board->placement[square] = pch[j]; board->king[WHITE] ^= 1ULL << square; break; case 'k': board->placement[square] = pch[j]; board->king[BLACK] ^= 1ULL << square; break; } k++; } else k += pch[j] - 48; } } else if (i == 8) { board->active_color = pch[0] == 'b'; } else if (i == 9) { board->castling = 0x0000; for (j = 0; j < (int) strlen (pch); j++) { switch (pch[j]) { case 'K': board->castling |= 0x1000; break; case 'Q': board->castling |= 0x0100; break; case 'k': board->castling |= 0x0010; break; case 'q': board->castling |= 0x0001; break; } } } else if (i == 10) { board->en_passant = coord_to_square (pch); } else if (i == 11) { board->halfmove_clock = atoi (pch); } else if (i == 12) { board->fullmove_number = atoi (pch); } i++; pch = strtok (NULL, " /"); } set_occupied (board); g->boards[g->current] = board; g->moves[g->current] = (char *) malloc (11); g->coord_moves[g->current] = (char *) malloc (11); strcpy (g->moves[g->current], "SET BY FEN"); strcpy (g->coord_moves[g->current], "SET BY FEN"); g->current++; // check result if (king_in_checkmate (board, board->active_color)) g->result = !board->active_color; else if (stalemate (board, board->active_color) || insufficient_material (board)) g->result = DRAW; free (s); }