931 lines
19 KiB
C++
931 lines
19 KiB
C++
#include <algorithm>
|
|
#include <sstream>
|
|
#include <cstring>
|
|
|
|
#ifdef USE_NCURSES
|
|
#include <ncurses.h>
|
|
#else
|
|
#include <curses.h>
|
|
#endif
|
|
|
|
#include "chess.h"
|
|
#include "pawn.h"
|
|
#include "king.h"
|
|
#include "queen.h"
|
|
#include "bishop.h"
|
|
#include "rook.h"
|
|
#include "knight.h"
|
|
|
|
#define W_PAWN "\xe2\x99\x99"
|
|
#define W_KNIGHT "\xe2\x99\x98"
|
|
#define W_BISHOP "\xe2\x99\x97"
|
|
#define W_ROOK "\xe2\x99\x96"
|
|
#define W_QUEEN "\xe2\x99\x95"
|
|
#define W_KING "\xe2\x99\x94"
|
|
|
|
#define B_PAWN "\xe2\x99\x9f"
|
|
#define B_KNIGHT "\xe2\x99\x9e"
|
|
#define B_BISHOP "\xe2\x99\x9d"
|
|
#define B_ROOK "\xe2\x99\x9c"
|
|
#define B_QUEEN "\xe2\x99\x9b"
|
|
#define B_KING "\xe2\x99\x9a"
|
|
|
|
WINDOW *win;
|
|
|
|
void chess::menu()
|
|
{
|
|
switch (status) {
|
|
case MOVING:
|
|
return;
|
|
case CASTLING:
|
|
wprintw(win, "Castling with:\n"
|
|
"1. Left rook.\n"
|
|
"2. Right rook.\n"
|
|
"\tINPUT: "
|
|
);
|
|
return;
|
|
case INCORRECT_INPUT:
|
|
wprintw(win, "Incorrect input!\n");
|
|
break;
|
|
case MOVE_SUCCESSFUL:
|
|
wprintw(win, "Move successful!\n");
|
|
break;
|
|
case MOVE_IMPOSSIBLE:
|
|
wprintw(win, "No such move!\n");
|
|
break;
|
|
case MOVE_NO_CHANGE:
|
|
wprintw(win, "You can't move to the same spot!\n");
|
|
break;
|
|
case MOVE_PATH_PROBLEM:
|
|
wprintw(win, "An element is in the way!\n");
|
|
break;
|
|
case MOVE_PAWN_IMPOSSIBLE:
|
|
wprintw(win, "First move, already made on this pawn!\n");
|
|
break;
|
|
case MOVE_PAWN_PROMOTION:
|
|
wprintw(win, "Promote pawn to:\n\n"
|
|
"1. Bishop.\n"
|
|
"2. Rook.\n"
|
|
"3. Knight.\n"
|
|
"4. Queen.\n\n"
|
|
"\tINPUT: "
|
|
);
|
|
return;
|
|
case MOVE_PAWN_PROMOTED:
|
|
wprintw(win, "Pawn, successfully promoted!\n");
|
|
break;
|
|
case MOVE_WRONG_TURN:
|
|
wprintw(win, "That's not your piece!\n"
|
|
"It's %s's turn.\n",
|
|
nickname[turn].c_str()
|
|
);
|
|
break;
|
|
case CASTLING_FORBIDDEN_LEFT:
|
|
wprintw(win, "Left rook is forbidden to castle!\n");
|
|
break;
|
|
case CASTLING_FORBIDDEN_RIGHT:
|
|
wprintw(win, "Right rook is forbidden to castle!\n");
|
|
break;
|
|
case CASTLING_UNDER_CHECK:
|
|
wprintw(win, "Careful! Castling area is attackable.\n");
|
|
break;
|
|
case CASTLING_PATH_PROBLEM:
|
|
wprintw(win, "Path for castling isn't clear!\n");
|
|
break;
|
|
case CHECK_PREVENT:
|
|
wprintw(win, "Careful! That move leads to check!\n");
|
|
break;
|
|
case CHECK_WARNING:
|
|
wprintw(win, "Your king is under check!\n");
|
|
break;
|
|
case CHECKMATE:
|
|
wprintw(win, "\n\tCheckmate!!!\n\n"
|
|
"\t%s has won the game!",
|
|
nickname[!turn].c_str()
|
|
);
|
|
return;
|
|
}
|
|
|
|
wprintw(win, "\n"
|
|
"1. Move.\n"
|
|
"2. Castling.\n"
|
|
"3. Forfeit.\n\n"
|
|
"\tINPUT: "
|
|
);
|
|
}
|
|
|
|
chess::chess(const char *player1_name, const char *player2_name)
|
|
{
|
|
nickname[0] = player1_name;
|
|
nickname[1] = player2_name;
|
|
last_move = "N/A";
|
|
|
|
turn = WHITE;
|
|
status = MENU;
|
|
|
|
for (int i = 2; i < 6; ++i)
|
|
for (int j = 0; j < 8; ++j)
|
|
spot[i][j] = 0;
|
|
|
|
spot[0][0] = new rook(0, 0, WHITE);
|
|
spot[0][1] = new knight(0, 1, WHITE);
|
|
spot[0][2] = new bishop(0, 2, WHITE);
|
|
spot[0][3] = new queen(0, 3, WHITE);
|
|
spot[0][4] = new king(0, 4, WHITE);
|
|
spot[0][5] = new bishop(0, 5, WHITE);
|
|
spot[0][6] = new knight(0, 6, WHITE);
|
|
spot[0][7] = new rook(0, 7, WHITE);
|
|
|
|
for (int i = 0; i < 8; ++i)
|
|
spot[1][i] = new pawn(1, i, WHITE);
|
|
|
|
spot[7][0] = new rook(7, 0, BLACK);
|
|
spot[7][1] = new knight(7, 1, BLACK);
|
|
spot[7][2] = new bishop(7, 2, BLACK);
|
|
spot[7][3] = new queen(7, 3, BLACK);
|
|
spot[7][4] = new king(7, 4, BLACK);
|
|
spot[7][5] = new bishop(7, 5, BLACK);
|
|
spot[7][6] = new knight(7, 6, BLACK);
|
|
spot[7][7] = new rook(7, 7, BLACK);
|
|
|
|
for (int i = 0; i < 8; ++i)
|
|
spot[6][i] = new pawn(6, i, BLACK);
|
|
|
|
King[WHITE] = spot[0][4];
|
|
King[BLACK] = spot[7][4];
|
|
}
|
|
|
|
chess::~chess()
|
|
{
|
|
for (int i = 0; i < 8; ++i)
|
|
for (int j = 0; j < 8; ++j)
|
|
if (spot[i][j])
|
|
delete spot[i][j];
|
|
}
|
|
|
|
void chess::play()
|
|
{
|
|
char a[3], b[3];
|
|
char choice[2];
|
|
int from_x, from_y, to_x, to_y;
|
|
|
|
setlocale(LC_ALL, "");
|
|
initscr();
|
|
start_color();
|
|
noqiflush();
|
|
init_pair(1,COLOR_BLACK, COLOR_WHITE);
|
|
init_pair(2,COLOR_BLACK, (has_colors() && can_change_color()) ? 8 : 3);
|
|
win = newwin(0,0,0,0);
|
|
|
|
for (;;) {
|
|
wattroff(win, COLOR_PAIR(A_REVERSE));
|
|
refresh();
|
|
wrefresh(win);
|
|
wattron(win, COLOR_PAIR(A_REVERSE));
|
|
|
|
wclear(win);
|
|
draw_chess_board();
|
|
menu();
|
|
|
|
if (status == CHECKMATE) {
|
|
getch();
|
|
wattroff(win, COLOR_PAIR(A_REVERSE));
|
|
refresh();
|
|
wrefresh(win);
|
|
delwin(win);
|
|
endwin();
|
|
return;
|
|
}
|
|
|
|
if (status == CASTLING) {
|
|
wgetstr(win, choice);
|
|
|
|
if (choice[0] == '1')
|
|
status = castling(CASTLING_LEFT);
|
|
else if (choice[0] == '2')
|
|
status = castling(CASTLING_RIGHT);
|
|
|
|
continue;
|
|
}
|
|
|
|
if (status != MOVING) {
|
|
wgetstr(win, choice);
|
|
if (choice[0] == '1') {
|
|
status = MOVING;
|
|
continue;
|
|
}
|
|
|
|
if (choice[0] == '2') {
|
|
status = CASTLING;
|
|
continue;
|
|
}
|
|
|
|
if (choice[0] == '3') {
|
|
wprintw(win, "Are you sure? [y\\n]: ");
|
|
wgetstr(win, choice);
|
|
|
|
if (choice[0] == 'y' || choice[0] == 'Y')
|
|
break;
|
|
|
|
continue;
|
|
}
|
|
} else {
|
|
wprintw(win, "From: ");
|
|
wgetnstr(win, a, 2);
|
|
wprintw(win, "To: ");
|
|
wgetnstr(win, b, 2);
|
|
|
|
if (strlen(a) != 2 || strlen(b) != 2) {
|
|
status = INCORRECT_INPUT;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
from_x = a[1] - '1';
|
|
from_y = tolower(a[0]) - 'a';
|
|
to_x = b[1] - '1';
|
|
to_y = tolower(b[0]) - 'a';
|
|
|
|
if (input_is_correct(from_x, from_y, to_x, to_y)) {
|
|
if (spot[from_x][from_y]->team_is() != turn) {
|
|
status = MOVE_WRONG_TURN;
|
|
continue;
|
|
}
|
|
|
|
status = path_status(from_x, from_y, to_x, to_y);
|
|
|
|
if (status == MOVE_OK)
|
|
move(from_x, from_y, to_x, to_y);
|
|
} else
|
|
status = INCORRECT_INPUT;
|
|
}
|
|
wattroff(win, COLOR_PAIR(A_REVERSE));
|
|
refresh();
|
|
wrefresh(win);
|
|
delwin(win);
|
|
endwin();
|
|
}
|
|
|
|
bool chess::input_is_correct(int from_x, int from_y, int to_x, int to_y)
|
|
{
|
|
if (from_x < 0 || from_x > 7 || from_y < 0 || from_y > 7)
|
|
return false;
|
|
|
|
if (to_x < 0 || to_x > 7 || to_y < 0 || to_y > 7)
|
|
return false;
|
|
|
|
if (!spot[from_x][from_y])
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool chess::king_is_safe(int to_x, int to_y)
|
|
{
|
|
int x, y, i, j, spot_rank, spot_team;
|
|
|
|
if (status == KING_MOVING) {
|
|
x = to_x;
|
|
y = to_y;
|
|
|
|
if (x + 2 < 8) {
|
|
if (y + 1 < 8)
|
|
if (spot[x+2][y+1] && spot[x+2][y+1]->team_is() != turn && spot[x+2][y+1]->rank_is() == KNIGHT)
|
|
return false;
|
|
|
|
if (y - 1 >= 0)
|
|
if (spot[x+2][y-1] && spot[x+2][y-1]->team_is() != turn && spot[x+2][y-1]->rank_is() == KNIGHT)
|
|
return false;
|
|
}
|
|
|
|
if (x - 2 >= 0) {
|
|
if (y + 1 < 8)
|
|
if (spot[x-2][y+1] && spot[x-2][y+1]->team_is() != turn && spot[x-2][y+1]->rank_is() == KNIGHT)
|
|
return false;
|
|
|
|
if (y - 1 >= 0)
|
|
if (spot[x-2][y-1] && spot[x-2][y-1]->team_is() != turn && spot[x-2][y-1]->rank_is() == KNIGHT)
|
|
return false;
|
|
}
|
|
|
|
if (x + 1 < 8) {
|
|
if (y + 2 < 8)
|
|
if (spot[x+1][y+2] && spot[x+1][y+2]->team_is() != turn && spot[x+1][y+2]->rank_is() == KNIGHT)
|
|
return false;
|
|
|
|
if (y - 2 >= 0)
|
|
if (spot[x+1][y-2] && spot[x+1][y-2]->team_is() != turn && spot[x+1][y-2]->rank_is() == KNIGHT)
|
|
return false;
|
|
}
|
|
|
|
if (x - 1 >= 0) {
|
|
if (y + 2 < 8)
|
|
if (spot[x-1][y+2] && spot[x-1][y+2]->team_is() != turn && spot[x-1][y+2]->rank_is() == KNIGHT)
|
|
return false;
|
|
|
|
if (y - 2 >= 0)
|
|
if (spot[x-1][y-2] && spot[x-1][y-2]->team_is() != turn && spot[x-1][y-2]->rank_is() == KNIGHT)
|
|
return false;
|
|
}
|
|
} else
|
|
King[turn]->get_coords(x, y);
|
|
|
|
// Diagonal: right-up
|
|
for (i = x + 1, j = y + 1; i < 8 && j < 8; ++i, ++j) {
|
|
if (spot[i][j]) {
|
|
spot_rank = spot[i][j]->rank_is();
|
|
spot_team = spot[i][j]->team_is();
|
|
|
|
if (spot_rank == KING && spot_team == turn)
|
|
continue;
|
|
|
|
if (spot_team != turn) {
|
|
if (spot_rank == QUEEN)
|
|
return false;
|
|
if (spot_rank == BISHOP)
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (to_x == i && to_y == j)
|
|
break;
|
|
}
|
|
// Diagonal: right-down
|
|
for (i = x - 1, j = y + 1; i >= 0 && j < 8; --i, ++j) {
|
|
if (spot[i][j]) {
|
|
spot_rank = spot[i][j]->rank_is();
|
|
spot_team = spot[i][j]->team_is();
|
|
|
|
if (spot_rank == KING && spot_team == turn)
|
|
continue;
|
|
|
|
if (spot_team != turn) {
|
|
if (spot_rank == QUEEN)
|
|
return false;
|
|
if (spot_rank == BISHOP)
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (to_x == i && to_y == j)
|
|
break;
|
|
}
|
|
// Diagonal: left-up
|
|
for (i = x + 1, j = y - 1; i < 8 && j >= 0; ++i, --j) {
|
|
if (spot[i][j]) {
|
|
spot_rank = spot[i][j]->rank_is();
|
|
spot_team = spot[i][j]->team_is();
|
|
|
|
if (spot_rank == KING && spot_team == turn)
|
|
continue;
|
|
|
|
if (spot_team != turn) {
|
|
if (spot_rank == QUEEN)
|
|
return false;
|
|
if (spot_rank == BISHOP)
|
|
return false;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (to_x == i && to_y == j)
|
|
break;
|
|
}
|
|
// Diagonal: left-down
|
|
for (i = x - 1, j = y - 1; i >= 0 && j >= 0; --i, --j) {
|
|
if (spot[i][j]) {
|
|
spot_rank = spot[i][j]->rank_is();
|
|
spot_team = spot[i][j]->team_is();
|
|
|
|
if (spot_rank == KING && spot_team == turn)
|
|
continue;
|
|
|
|
if (spot_team != turn) {
|
|
if (spot_rank == QUEEN)
|
|
return false;
|
|
if (spot_rank == BISHOP)
|
|
return false;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (to_x == i && to_y == j)
|
|
break;
|
|
}
|
|
// Upward path
|
|
for (i = x + 1, j = y; i < 8; ++i) {
|
|
if (spot[i][j]) {
|
|
spot_rank = spot[i][j]->rank_is();
|
|
spot_team = spot[i][j]->team_is();
|
|
|
|
if (spot_rank == KING && spot_team == turn)
|
|
continue;
|
|
|
|
if (spot_team != turn) {
|
|
if (spot_rank == QUEEN)
|
|
return false;
|
|
if (spot_rank == ROOK)
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (to_x == i && to_y == j)
|
|
break;
|
|
}
|
|
// Downward path
|
|
for (i = x - 1; i >= 0; --i) {
|
|
if (spot[i][j]) {
|
|
spot_rank = spot[i][j]->rank_is();
|
|
spot_team = spot[i][j]->team_is();
|
|
|
|
if (spot_rank == KING && spot_team == turn)
|
|
continue;
|
|
|
|
if (spot_team != turn) {
|
|
if (spot_rank == QUEEN)
|
|
return false;
|
|
if (spot_rank == ROOK)
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (to_x == i && to_y == j)
|
|
break;
|
|
}
|
|
// Right path
|
|
for (i = x, j = y + 1; j < 8; ++j) {
|
|
if (spot[i][j]) {
|
|
spot_rank = spot[i][j]->rank_is();
|
|
spot_team = spot[i][j]->team_is();
|
|
|
|
if (spot_rank == KING && spot_team == turn)
|
|
continue;
|
|
|
|
if (spot_team != turn) {
|
|
if (spot_rank == QUEEN)
|
|
return false;
|
|
if (spot_rank == ROOK)
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (to_x == i && to_y == j)
|
|
break;
|
|
}
|
|
// Left path
|
|
for (j = y - 1; j >= 0; --j) {
|
|
if (spot[i][j]) {
|
|
spot_rank = spot[i][j]->rank_is();
|
|
spot_team = spot[i][j]->team_is();
|
|
|
|
if (spot_rank == KING && spot_team == turn)
|
|
continue;
|
|
|
|
if (spot_team != turn) {
|
|
if (spot_rank == QUEEN)
|
|
return false;
|
|
if (spot_rank == ROOK)
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (to_x == i && to_y == j)
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int chess::path_status(int a_x, int a_y, int b_x, int b_y)
|
|
{
|
|
#define SPOT_CHECK() do { \
|
|
if (i == b_x && j == b_y) { \
|
|
if (flag) \
|
|
return MOVE_PATH_PROBLEM; \
|
|
\
|
|
if (king_is_safe(i, j)) \
|
|
return MOVE_OK; \
|
|
\
|
|
return CHECK_PREVENT; \
|
|
} \
|
|
\
|
|
if (spot[i][j] && i != b_x && j != b_y) \
|
|
flag = 1; \
|
|
} while (0) // macro end
|
|
|
|
int i, j, flag;
|
|
int rank_a = spot[a_x][a_y]->rank_is();
|
|
|
|
if (a_x == b_x && a_y == b_y)
|
|
return MOVE_NO_CHANGE;
|
|
|
|
if (spot[b_x][b_y])
|
|
if (spot[a_x][a_y]->team_is() == spot[b_x][b_y]->team_is())
|
|
return MOVE_PATH_PROBLEM;
|
|
|
|
switch (rank_a) {
|
|
case KING:
|
|
status = KING_MOVING;
|
|
|
|
if (a_x + 1 == b_x || a_x - 1 == b_x || a_x == b_x)
|
|
if (a_y + 1 == b_y || a_y - 1 == b_y || a_y == b_y) {
|
|
if (king_is_safe(b_x, b_y))
|
|
return MOVE_OK;
|
|
|
|
return CHECK_PREVENT;
|
|
}
|
|
|
|
return MOVE_IMPOSSIBLE;
|
|
case QUEEN:
|
|
for (flag = 0, i = a_x + 1, j = a_y + 1; i < 8 && j < 8; ++i, ++j)
|
|
SPOT_CHECK();
|
|
|
|
for (flag = 0, i = a_x - 1, j = a_y + 1; i >= 0 && j < 8; --i, ++j)
|
|
SPOT_CHECK();
|
|
|
|
for (flag = 0, i = a_x + 1, j = a_y - 1; i < 8 && j >= 0; ++i, --j)
|
|
SPOT_CHECK();
|
|
|
|
for (flag = 0, i = a_x - 1, j = a_y - 1; i >= 0 && j >= 0; --i, --j)
|
|
SPOT_CHECK();
|
|
|
|
for (flag = 0, i = a_x + 1, j = a_y; i < 8; ++i)
|
|
SPOT_CHECK();
|
|
|
|
for (flag = 0, i = a_x - 1; i >= 0; --i)
|
|
SPOT_CHECK();
|
|
|
|
for (flag = 0, i = a_x, j = a_y + 1; j < 8; ++j)
|
|
SPOT_CHECK();
|
|
|
|
for (flag = 0, j = a_y - 1; j >= 0; --j)
|
|
SPOT_CHECK();
|
|
|
|
return MOVE_IMPOSSIBLE;
|
|
case KNIGHT:
|
|
if (a_x + 2 == b_x || a_x - 2 == b_x)
|
|
if (a_y + 1 == b_y || a_y - 1 == b_y) {
|
|
if (king_is_safe(b_x, b_y))
|
|
return MOVE_OK;
|
|
|
|
return CHECK_PREVENT;
|
|
}
|
|
|
|
if (a_x + 1 == b_x || a_x - 1 == b_x)
|
|
if (a_y + 2 == b_y || a_y - 2 == b_y) {
|
|
if (king_is_safe(b_x, b_y))
|
|
return MOVE_OK;
|
|
|
|
return CHECK_PREVENT;
|
|
}
|
|
|
|
return MOVE_IMPOSSIBLE;
|
|
case BISHOP:
|
|
for (flag = 0, i = a_x + 1, j = a_y + 1; i < 8 && j < 8; ++i, ++j)
|
|
SPOT_CHECK();
|
|
|
|
for (flag = 0, i = a_x - 1, j = a_y + 1; i >= 0 && j < 8; --i, ++j)
|
|
SPOT_CHECK();
|
|
|
|
for (flag = 0, i = a_x + 1, j = a_y - 1; i < 8 && j >= 0; ++i, --j)
|
|
SPOT_CHECK();
|
|
|
|
for (flag = 0, i = a_x - 1, j = a_y - 1; i >= 0 && j >= 0; --i, --j)
|
|
SPOT_CHECK();
|
|
|
|
return MOVE_IMPOSSIBLE;
|
|
case ROOK:
|
|
for (flag = 0, i = a_x + 1, j = a_y; i < 8; ++i)
|
|
SPOT_CHECK();
|
|
|
|
for (flag = 0, i = a_x - 1; i >= 0; --i)
|
|
SPOT_CHECK();
|
|
|
|
for (flag = 0, i = a_x, j = a_y + 1; j < 8; ++j)
|
|
SPOT_CHECK();
|
|
|
|
for (flag = 0, j = a_y - 1; j >= 0; --j)
|
|
SPOT_CHECK();
|
|
|
|
return MOVE_IMPOSSIBLE;
|
|
default: // case PAWN:
|
|
pawn *Pawn = static_cast<pawn *>(spot[a_x][a_y]);
|
|
|
|
switch (turn) {
|
|
case WHITE:
|
|
if (a_x + 1 == b_x && a_y == b_y && !spot[b_x][b_y]) {
|
|
if (king_is_safe(b_x, b_y))
|
|
return MOVE_OK;
|
|
|
|
return CHECK_PREVENT;
|
|
}
|
|
|
|
if (a_x + 1 == b_x && (a_y + 1 == b_y || a_y - 1 == b_y))
|
|
if (spot[b_x][b_y] && spot[b_x][b_y]->team_is() != turn) {
|
|
if (king_is_safe(b_x, b_y))
|
|
return MOVE_OK;
|
|
|
|
return CHECK_PREVENT;
|
|
}
|
|
|
|
if (a_x + 2 == b_x && a_y == b_y && !spot[b_x][b_y]) {
|
|
if (Pawn->first_move() == false)
|
|
return MOVE_PAWN_IMPOSSIBLE;
|
|
|
|
if (king_is_safe(b_x, b_y))
|
|
return MOVE_OK;
|
|
|
|
return CHECK_PREVENT;
|
|
}
|
|
|
|
break;
|
|
case BLACK:
|
|
if (a_x - 1 == b_x && a_y == b_y && !spot[b_x][b_y]) {
|
|
if (king_is_safe(b_x, b_y))
|
|
return MOVE_OK;
|
|
|
|
return CHECK_PREVENT;
|
|
}
|
|
|
|
if (a_x - 1 == b_x && (a_y + 1 == b_y || a_y - 1 == b_y))
|
|
if (spot[b_x][b_y] && spot[b_x][b_y]->team_is() != turn) {
|
|
if (king_is_safe(b_x, b_y))
|
|
return MOVE_OK;
|
|
|
|
return CHECK_PREVENT;
|
|
}
|
|
|
|
if (a_x - 2 == b_x && a_y == b_y && !spot[b_x][b_y]) {
|
|
if (Pawn->first_move() == false)
|
|
return MOVE_PAWN_IMPOSSIBLE;
|
|
|
|
if (king_is_safe(b_x, b_y))
|
|
return MOVE_OK;
|
|
|
|
return CHECK_PREVENT;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return MOVE_IMPOSSIBLE;
|
|
}
|
|
}
|
|
|
|
int chess::castling(int choice)
|
|
{
|
|
king *King[2] = {
|
|
static_cast<king *>(this->King[0]),
|
|
static_cast<king *>(this->King[1])
|
|
};
|
|
|
|
if (King[turn]->can_castle(choice) == false)
|
|
return choice == CASTLING_LEFT ? CASTLING_FORBIDDEN_LEFT : CASTLING_FORBIDDEN_RIGHT;
|
|
|
|
int row = turn == WHITE ? 0 : 7;
|
|
|
|
if (choice == CASTLING_LEFT) {
|
|
if (spot[row][1] || spot[row][2] || spot[row][3])
|
|
return CASTLING_PATH_PROBLEM;
|
|
|
|
for (int i = 0; i < 5; ++i)
|
|
if (!king_is_safe(row, i))
|
|
return CASTLING_UNDER_CHECK;
|
|
|
|
King[turn]->move(row, 2);
|
|
spot[row][2] = King[turn];
|
|
spot[row][4] = 0;
|
|
spot[row][3] = spot[row][0];
|
|
spot[row][0] = 0;
|
|
} else {
|
|
if (spot[row][5] || spot[row][6])
|
|
return CASTLING_PATH_PROBLEM;
|
|
|
|
for (int i = 4; i < 8; ++i)
|
|
if (!king_is_safe(row, i))
|
|
return CASTLING_UNDER_CHECK;
|
|
|
|
King[turn]->move(row, 6);
|
|
spot[row][6] = King[turn];
|
|
spot[row][4] = 0;
|
|
spot[row][5] = spot[row][0];
|
|
spot[row][7] = 0;
|
|
}
|
|
|
|
turn = turn == WHITE ? BLACK : WHITE;
|
|
last_move = choice == CASTLING_LEFT ? "Castling (Left rook)" : "Castling (Right rook)";
|
|
|
|
return MOVE_SUCCESSFUL;
|
|
}
|
|
|
|
void chess::check_for_checkmate()
|
|
{
|
|
int x, y, checks = 0;
|
|
|
|
King[!turn]->get_coords(x, y);
|
|
|
|
if (!king_is_safe(x, y)) {
|
|
status = CHECK_WARNING;
|
|
|
|
if (x + 1 < 8) {
|
|
if (y + 1 < 8) {
|
|
if (!king_is_safe(x+1, y+1))
|
|
checks++;
|
|
} else checks++;
|
|
|
|
if (y - 1 >= 0) {
|
|
if (!king_is_safe(x+1, y-1))
|
|
checks++;
|
|
} else checks++;
|
|
|
|
if (!king_is_safe(x+1, y))
|
|
checks++;
|
|
} else
|
|
checks += 3;
|
|
|
|
if (x - 1 >= 0) {
|
|
if (y + 1 < 8) {
|
|
if (!king_is_safe(x-1, y+1))
|
|
checks++;
|
|
} else checks++;
|
|
|
|
if (y - 1 >= 0) {
|
|
if (!king_is_safe(x-1, y-1))
|
|
checks++;
|
|
} else checks++;
|
|
|
|
if (!king_is_safe(x-1, y))
|
|
checks++;
|
|
} else
|
|
checks += 3;
|
|
|
|
if (y + 1 < 8) {
|
|
if (!king_is_safe(x, y+1))
|
|
checks++;
|
|
} else checks++;
|
|
|
|
if (y - 1 >= 0) {
|
|
if (!king_is_safe(x, y-1))
|
|
checks++;
|
|
} else checks++;
|
|
|
|
if (checks == 8)
|
|
status = CHECKMATE;
|
|
}
|
|
}
|
|
|
|
const char* chess::symbol(int x, int y, bool rm)
|
|
{
|
|
if ( (rm && spot[x][y]->team_is() == BLACK) || (!rm && spot[x][y]->team_is() == WHITE))
|
|
switch (spot[x][y]->rank_is()) {
|
|
case QUEEN: return W_QUEEN;
|
|
case KING: return W_KING;
|
|
case ROOK: return W_ROOK;
|
|
case BISHOP: return W_BISHOP;
|
|
case PAWN: return W_PAWN;
|
|
default: return W_KNIGHT;
|
|
}
|
|
else
|
|
switch (spot[x][y]->rank_is()) {
|
|
case QUEEN: return B_QUEEN;
|
|
case KING: return B_KING;
|
|
case ROOK: return B_ROOK;
|
|
case BISHOP: return B_BISHOP;
|
|
case PAWN: return B_PAWN;
|
|
default: return B_KNIGHT;
|
|
}
|
|
}
|
|
|
|
void chess::move(int a_x, int a_y, int b_x, int b_y)
|
|
{
|
|
piece *&last_pos = spot[a_x][a_y];
|
|
piece *&new_pos = spot[b_x][b_y];
|
|
|
|
if (new_pos) {
|
|
removed[!turn] += std::string(symbol(b_x, b_y, true)) + " ";
|
|
delete new_pos;
|
|
}
|
|
|
|
new_pos = last_pos;
|
|
new_pos->move(b_x, b_y);
|
|
last_pos = NULL;
|
|
|
|
if (new_pos->rank_is() == PAWN && (b_x == 0 || b_x == 7)) {
|
|
status = MOVE_PAWN_PROMOTION;
|
|
int val;
|
|
|
|
for (;;) {
|
|
char *e, choice[2];
|
|
|
|
wattroff(win, COLOR_PAIR(A_REVERSE));
|
|
refresh();
|
|
wrefresh(win);
|
|
wattron(win, COLOR_PAIR(A_REVERSE));
|
|
wclear(win);
|
|
|
|
draw_chess_board();
|
|
menu();
|
|
wgetnstr(win, choice, 2);
|
|
|
|
val = strtol(choice, &e, 10);
|
|
|
|
if (*e == '\0' && val > 0 && val < 5)
|
|
break;
|
|
}
|
|
|
|
delete new_pos;
|
|
|
|
std::ostringstream __out;
|
|
__out << (char)(a_y + 'A') << a_x + 1 << " -> "
|
|
<< (char)(b_y + 'A') << b_x + 1 << " (Pawn promoted to ";
|
|
switch (val) {
|
|
case 1:
|
|
new_pos = new bishop(b_x, b_y, turn);
|
|
__out << "bishop";
|
|
break;
|
|
case 2:
|
|
new_pos = new rook(b_x, b_y, turn);
|
|
__out << "rook";
|
|
break;
|
|
case 3:
|
|
new_pos = new knight(b_x, b_y, turn);
|
|
__out << "knight";
|
|
break;
|
|
case 4:
|
|
new_pos = new queen(b_x, b_y, turn);
|
|
__out << "queen";
|
|
break;
|
|
}
|
|
__out << ").";
|
|
last_move = __out.str();
|
|
|
|
status = MOVE_PAWN_PROMOTED;
|
|
} else {
|
|
if (new_pos->rank_is() == KING)
|
|
King[turn] = new_pos;
|
|
status = MOVE_SUCCESSFUL;
|
|
|
|
std::ostringstream __out;
|
|
__out << (char)(a_y + 'A') << a_x + 1 << " -> "
|
|
<< (char)(b_y + 'A') << b_x + 1;
|
|
last_move = __out.str();
|
|
}
|
|
|
|
turn = !turn;
|
|
|
|
//check_for_checkmate();
|
|
}
|
|
|
|
void chess::draw_chess_board()
|
|
{
|
|
static const char *idxs = "\t A B C D E F G H";
|
|
|
|
wprintw(win, "\t*** Smirky-Chess v3.0 (beta) ***\n"
|
|
"\t\t%s vs %s\n\n%s\n",
|
|
nickname[0].c_str(), nickname[1].c_str(), idxs
|
|
);
|
|
wattroff(win, COLOR_PAIR(A_REVERSE));
|
|
|
|
for (int i = 7; i >= 0; --i) {
|
|
wprintw(win, "\t%d ", i + 1);
|
|
|
|
for (int j = 0; j < 8; j++) {
|
|
std::ostringstream __out;
|
|
wattron(win, COLOR_PAIR((i+j) % 2 ? 1 : 2));
|
|
__out << " " << (spot[i][j] ? symbol(i, j, false) : " ") << " ";
|
|
wprintw(win, "%s", __out.str().c_str());
|
|
wattroff(win, COLOR_PAIR((i+j) % 2 ? 1 : 2));
|
|
}
|
|
wattron(win, COLOR_PAIR(A_REVERSE));
|
|
|
|
wprintw(win, " %d\t", i + 1);
|
|
switch (i) {
|
|
case 7:
|
|
wprintw(win, "Removed pieces:");
|
|
break;
|
|
case 5:
|
|
wprintw(win, "%s", removed[0].c_str());
|
|
break;
|
|
case 4:
|
|
wprintw(win, "%s", removed[1].c_str());
|
|
break;
|
|
case 2:
|
|
wprintw(win, "Last move: %s", last_move.c_str());
|
|
break;
|
|
}
|
|
|
|
wprintw(win, "\n");
|
|
wattroff(win, COLOR_PAIR(A_REVERSE));
|
|
}
|
|
|
|
wprintw(win, "%s\t%s's turn!\n", idxs, nickname[turn].c_str());
|
|
}
|