
ChessTAI is a chess board and a chess bot. The bot is still work in progress. Made in python.
from os import system
from copy import deepcopy
from random import randint
# move_num = monesko vuoro menossa (alkaa 1 ja kasvaa 1 joka valkoisen pelaajan vuoro)
# move_side = kumman nappuloiden vuoro (0 = white, 1 = black)
# player_side = kummalla puolella ihminen on (0 = white, 1 = black)
# player_pieces = mitkä nappulat ihmisellä
# white_castle_moved = (0 = ei, 1 = kyllä) [onko valkoinen kuningas, vasen torni, oikea torni liikkunut vielä]
# black_castle_moved = (0 = ei, 1 = kyllä) [onko musta kuningas, vasen torni, oikea torni liikkunut vielä]
# last_double_pawn_move = [x, y, pelaaja (0 = white, 1 = black)]
# last_advancing_move = milloin viimeksi syöty nappula tai liikutettu sotilasta [move_num, side]
# computer_last_move = (x, y) mihin tietokone vastustaja viimeksi liikutti
# all_positions = lista kaikista laudan aiemmista vaiheista
stats = {
"move_num": 0,
"move_side": 0,
"player_side": 0,
"player_pieces": "PNBRQK",
"opponent_pieces": "pnbrqk",
"white_castle_moved": [0, 0, 0],
"black_castle_moved": [0, 0, 0],
"last_double_pawn_move": [],
"last_advancing_move": (0, 0),
"computer_last_move": (-1, -1),
"all_positions": {}
}
board = [
["r", "n", "b", "q", "k", "b", "n", "r"],
["p", "p", "p", "p", "p", "p", "p", "p"],
[" ", " ", " ", " ", " ", " ", " ", " "],
[" ", " ", " ", " ", " ", " ", " ", " "],
[" ", " ", " ", " ", " ", " ", " ", " "],
[" ", " ", " ", " ", " ", " ", " ", " "],
["P", "P", "P", "P", "P", "P", "P", "P"],
["R", "N", "B", "Q", "K", "B", "N", "R"]
]
evaluation = {
"game_evaluation": 0,
"piece_value": {
"P": 100,
"N": 300,
"B": 300,
"R": 500,
"Q": 900,
"p": -100,
"n": -300,
"b": -300,
"r": -500,
"q": -900,
}, # nappuloiden arvot
"pawn_placement": [[2, 2, 2, 0, 0, 2, 2, 2],
[5, 5, 8, 10, 10, 5, 5, 5],
[8, 8, 14, 18, 18, 10, 8, 8],
[14, 15, 18, 25, 25, 16, 15, 14],
[18, 18, 25, 35, 35, 25, 18, 18],
[45, 45, 45, 45, 45, 45, 45, 45],
[65, 65, 65, 65, 65, 65, 65, 65]], # from first position to second last row
"multiple_pawn_in_column_per_over_pawn": -30, # kaksi tai enemmän pawnia samalla pystysuoralla kaksi -> -x, kolme -> -2x, neljä -> -3x
"isolated_pawn": -10, # pawnin viereisillä pystyriveillä ei ole pawnia
"pawn_wall": 10, # pawni suojelee toista pawnia
"knight_value_per_move": 8, # arvo jokaisesta knightin näkemästä ruudusta
"bishop_value_per_move": 7, # arvo jokaisesta bishopin näkemästä ruudusta
"rook_value_per_move": 7, # arvo jokaisesta rookin näkemästä ruudusta
"queen_value_per_move": 3, # arvo jokaisesta rookin näkemästä ruudusta
"castling_value": [10, -10, -25, -30], # arvo kun [voi castlata, ei voi vasemmalle, ei voi oikealle, ei voi ollenkaan]
"move_turn": 20, # paljonko saa lisäarvoa siitä, että liikuttaa seuraavaksi
}
"""connected rooks, protected pieces and pawns, """
# tekstin värit
colors = {
"basic": '\033[m',
"white": '\033[37m',
"red": '\033[31m',
"green": '\033[32m',
"yellow": '\033[33m',
"blue": '\033[34m',
"magenta": '\033[35m',
"cyan": '\033[36m',
"grey": '\033[90m',
"black": '\033[30m'
}
# tekstin taustavärit
bg_colors = {
"white": '\033[107m',
"red": '\033[41m',
"green": '\033[42m',
"yellow": '\033[43m',
"blue": '\033[44m',
"magenta": '\033[45m',
"cyan": '\033[46m',
"grey": '\033[100m',
"black": '\033[40m'
}
logo = f"""
{colors['yellow']} __ {colors['blue']}_________ ____
{colors['yellow']} _____/ /_ ___ _________{colors['blue']}/_ __/ | / _/
{colors['yellow']} / ___/ __ \/ _ \/ ___/ ___/{colors['blue']}/ / / /| | / /
{colors['yellow']}/ /__/ / / / __(__ |__ ){colors['blue']}/ / / ___ |_/ /
{colors['yellow']}\___/_/ /_/\___/____/____/{colors['blue']}/_/ /_/ |_/___/
{colors['basic']}
Version 1"""
start_menu = """
1) player vs AI
2) player vs player
3) train AI
4) quit
Choose: """
x_convert = {"A": 0, "B": 1, "C": 2, "D": 3, "E": 4, "F": 5, "G": 6, "H": 7}
y_convert = {"1": 7, "2": 6, "3": 5, "4": 4, "5": 3, "6": 2, "7": 1, "8": 0}
def clear_console():
system('cls')
# index alkaa 0
# 0: kumman vuoro (0 valkoinen, 1 musta)
# 1: player_side
# 2-65: pelilauta vasen->oikea ylös->alas
# 65-67: white_castle_moved
# 68-70: black_castle_moved
# 71-73: last_double_pawn_move
# 74-(kunnes piste): move_num
# (pisteen jälkeen)-(kunnes piste): last_advancing_move[0]
# (pisteen jälkeen): last_advancing_move[1]
# last_advancing_move[1] jälkeen: kuinka monta eri positionia on all_positions
# len(all_positions) jälkeen: repeat(position ja jälkeen määrä)
def save():
save_text = str(stats["move_side"])
for line in board:
for cell in line:
if cell != " ":
save_text += cell
else:
save_text += "#"
for cell in stats["white_castle_moved"]:
save_text += str(cell)
for cell in stats["black_castle_moved"]:
save_text += str(cell)
for cell in stats["last_double_pawn_move"]:
save_text += str(cell)
save_text += str(stats["move_num"])
save_text += "."
save_text += str(stats["last_advancing_move"][0])
save_text += "."
save_text += str(stats["last_advancing_move"][1])
save_text += str(len(stats["all_positions"]))
for item, value in stats["all_positions"]:
for row in item:
for cell in row:
if cell == " ":
save_text += "#"
else:
save_text += cell
save_text += str(value)
return save_text
def load(save_text):
pass
# x = 0-7, y = 0-7
def pawn_moves(x, y, own_pieces, opponent_pieces, i_board, i_stats, computer):
possible_moves = []
if i_board[y][x] == "p":
if i_board[y + 1][x] == " ":
possible_moves.append(((x, y), (x, y + 1)))
if y == 1 and i_board[y + 2][x] == " ":
possible_moves.append(((x, y), (x, y + 2)))
if x < 7 and i_board[y + 1][x + 1] in opponent_pieces:
possible_moves.append(((x, y), (x + 1, y + 1)))
if x > 0 and i_board[y + 1][x - 1] in opponent_pieces:
possible_moves.append(((x, y), (x - 1, y + 1)))
if len(i_stats["last_double_pawn_move"]) == 3:
if x + 1 == i_stats["last_double_pawn_move"][0] and y == i_stats["last_double_pawn_move"][1]:
possible_moves.append(((x, y), (x + 1, y + 1)))
elif x - 1 == i_stats["last_double_pawn_move"][0] and y == i_stats["last_double_pawn_move"][1]:
possible_moves.append(((x, y), (x - 1, y + 1)))
if y == 6 and computer:
promote_moves = []
for i in range(len(possible_moves)):
for j in range(1, 5):
promote_moves.append(((possible_moves[i][0][0], possible_moves[i][0][1]), (possible_moves[i][1][0], possible_moves[i][1][1], own_pieces[j])))
possible_moves = promote_moves
else:
if i_board[y - 1][x] == " ":
possible_moves.append(((x, y), (x, y - 1)))
if y == 6 and i_board[y - 2][x] == " ":
possible_moves.append(((x, y), (x, y - 2)))
if x < 7 and i_board[y - 1][x + 1] in opponent_pieces:
possible_moves.append(((x, y), (x + 1, y - 1)))
if x > 0 and i_board[y - 1][x - 1] in opponent_pieces:
possible_moves.append(((x, y), (x - 1, y - 1)))
if len(i_stats["last_double_pawn_move"]) == 3:
if x + 1 == i_stats["last_double_pawn_move"][0] and y == i_stats["last_double_pawn_move"][1]:
possible_moves.append(((x, y), (x + 1, y - 1)))
elif x - 1 == i_stats["last_double_pawn_move"][0] and y == i_stats["last_double_pawn_move"][1]:
possible_moves.append(((x, y), (x - 1, y - 1)))
if y == 1 and computer:
promote_moves = []
for i in range(len(possible_moves)):
for j in range(1, 5):
promote_moves.append(((possible_moves[i][0][0], possible_moves[i][0][1]), (possible_moves[i][1][0], possible_moves[i][1][1], own_pieces[j])))
possible_moves = promote_moves
return possible_moves
# x = 0-7, y = 0-7
def knight_moves(x, y, own_pieces, i_board):
possible_moves = []
# check 2up left
i_x = x - 1
i_y = y - 2
if (i_x > -1) and (i_y > -1) and (i_board[i_y][i_x] not in own_pieces):
possible_moves.append(((x, y), (i_x, i_y)))
# check up 2left
i_x = x - 2
i_y = y - 1
if (i_x > -1) and (i_y > -1) and (i_board[i_y][i_x] not in own_pieces):
possible_moves.append(((x, y), (i_x, i_y)))
# check 2up right
i_x = x + 1
i_y = y - 2
if (i_x < 8) and (i_y > -1) and (i_board[i_y][i_x] not in own_pieces):
possible_moves.append(((x, y), (i_x, i_y)))
# check up 2right
i_x = x + 2
i_y = y - 1
if (i_x < 8) and (i_y > -1) and (i_board[i_y][i_x] not in own_pieces):
possible_moves.append(((x, y), (i_x, i_y)))
# check down 2left
i_x = x - 2
i_y = y + 1
if (i_x > -1) and (i_y < 8) and (i_board[i_y][i_x] not in own_pieces):
possible_moves.append(((x, y), (i_x, i_y)))
# check 2down left
i_x = x - 1
i_y = y + 2
if (i_x > -1) and (i_y < 8) and (i_board[i_y][i_x] not in own_pieces):
possible_moves.append(((x, y), (i_x, i_y)))
# check 2down right
i_x = x + 1
i_y = y + 2
if (i_x < 8) and (i_y < 8) and (i_board[i_y][i_x] not in own_pieces):
possible_moves.append(((x, y), (i_x, i_y)))
# check down 2right
i_x = x + 2
i_y = y + 1
if (i_x < 8) and (i_y < 8) and (i_board[i_y][i_x] not in own_pieces):
possible_moves.append(((x, y), (i_x, i_y)))
return possible_moves
# x = 0-7, y = 0-7
def rook_moves(x, y, opponent_pieces, i_board):
possible_moves = []
# moves to right
i = x + 1
while i < 8:
if i_board[y][i] == " ":
possible_moves.append(((x, y), (i, y)))
i += 1
continue
elif i_board[y][i] in opponent_pieces:
possible_moves.append(((x, y), (i, y)))
break
# moves to left
i = x - 1
while i > -1:
if i_board[y][i] == " ":
possible_moves.append(((x, y), (i, y)))
i -= 1
continue
elif i_board[y][i] in opponent_pieces:
possible_moves.append(((x, y), (i, y)))
break
# moves to up
i = y - 1
while i > -1:
if i_board[i][x] == " ":
possible_moves.append(((x, y), (x, i)))
i -= 1
continue
elif i_board[i][x] in opponent_pieces:
possible_moves.append(((x, y), (x, i)))
break
# moves to down
i = y + 1
while i < 8:
if i_board[i][x] == " ":
possible_moves.append(((x, y), (x, i)))
i += 1
continue
elif i_board[i][x] in opponent_pieces:
possible_moves.append(((x, y), (x, i)))
break
return possible_moves
# x = 0-7, y = 0-7
def bishop_moves(x, y, opponent_pieces, i_board):
possible_moves = []
# moves up right
i_x = x + 1
i_y = y - 1
while i_x < 8 and i_y > -1:
if i_board[i_y][i_x] == " ":
possible_moves.append(((x, y), (i_x, i_y)))
i_x += 1
i_y -= 1
continue
elif i_board[i_y][i_x] in opponent_pieces:
possible_moves.append(((x, y), (i_x, i_y)))
break
# moves up left
i_x = x - 1
i_y = y - 1
while i_x > -1 and i_y > -1:
if i_board[i_y][i_x] == " ":
possible_moves.append(((x, y), (i_x, i_y)))
i_x -= 1
i_y -= 1
continue
elif i_board[i_y][i_x] in opponent_pieces:
possible_moves.append(((x, y), (i_x, i_y)))
break
# moves down left
i_x = x - 1
i_y = y + 1
while i_x > -1 and i_y < 8:
if i_board[i_y][i_x] == " ":
possible_moves.append(((x, y), (i_x, i_y)))
i_x -= 1
i_y += 1
continue
elif i_board[i_y][i_x] in opponent_pieces:
possible_moves.append(((x, y), (i_x, i_y)))
break
# moves down right
i_x = x + 1
i_y = y + 1
while i_x < 8 and i_y < 8:
if i_board[i_y][i_x] == " ":
possible_moves.append(((x, y), (i_x, i_y)))
i_x += 1
i_y += 1
continue
elif i_board[i_y][i_x] in opponent_pieces:
possible_moves.append(((x, y), (i_x, i_y)))
break
return possible_moves
# x = 0-7, y = 0-7
def king_moves(x, y, own_pieces, opponent_pieces, check_castle, i_board, i_stats):
possible_moves = []
# check up left
i_x = x - 1
i_y = y - 1
if (i_x > -1) and (i_y > -1) and (i_board[i_y][i_x] not in own_pieces):
possible_moves.append(((x, y), (i_x, i_y)))
# check up
i_x = x
i_y = y - 1
if (i_y > -1) and (i_board[i_y][i_x] not in own_pieces):
possible_moves.append(((x, y), (i_x, i_y)))
# check up right
i_x = x + 1
i_y = y - 1
if (i_x < 8) and (i_y > -1) and (i_board[i_y][i_x] not in own_pieces):
possible_moves.append(((x, y), (i_x, i_y)))
# check left
i_x = x - 1
i_y = y
if (i_x > -1) and (i_board[i_y][i_x] not in own_pieces):
possible_moves.append(((x, y), (i_x, i_y)))
# check right
i_x = x + 1
i_y = y
if (i_x < 8) and (i_board[i_y][i_x] not in own_pieces):
possible_moves.append(((x, y), (i_x, i_y)))
# check down left
i_x = x - 1
i_y = y + 1
if (i_x > -1) and (i_y < 8) and (i_board[i_y][i_x] not in own_pieces):
possible_moves.append(((x, y), (i_x, i_y)))
# check down
i_x = x
i_y = y + 1
if (i_y < 8) and (i_board[i_y][i_x] not in own_pieces):
possible_moves.append(((x, y), (i_x, i_y)))
# check down right
i_x = x + 1
i_y = y + 1
if (i_x < 8) and (i_y < 8) and (i_board[i_y][i_x] not in own_pieces):
possible_moves.append(((x, y), (i_x, i_y)))
if not check_castle:
return possible_moves
if i_board[y][x] == "k" and i_stats["black_castle_moved"][0] == 0:
if i_stats["black_castle_moved"][1] == 0 and i_board[0][1] == " " and i_board[0][2] == " " and i_board[0][3] == " " and check_opponent_moves(own_pieces, opponent_pieces, i_board, i_stats, [(2, 0), (3, 0)]):
possible_moves.append(((x, y), (2, 0)))
if i_stats["black_castle_moved"][2] == 0 and i_board[0][5] == " " and i_board[0][6] == " " and check_opponent_moves(own_pieces, opponent_pieces, i_board, i_stats, [(5, 0), (6, 0)]):
possible_moves.append(((x, y), (6, 0)))
if i_board[y][x] == "K" and i_stats["white_castle_moved"][0] == 0:
if i_stats["white_castle_moved"][1] == 0 and i_board[7][1] == " " and i_board[7][2] == " " and i_board[7][3] == " " and check_opponent_moves(own_pieces, opponent_pieces, i_board, i_stats, [(2, 7), (3, 7)]):
possible_moves.append(((x, y), (2, 7)))
if i_stats["white_castle_moved"][2] == 0 and i_board[7][5] == " " and i_board[7][6] == " " and check_opponent_moves(own_pieces, opponent_pieces, i_board, i_stats, [(5, 7), (6, 7)]):
possible_moves.append(((x, y), (6, 7)))
return possible_moves
def show_board(start, side=-1, possible_moves=None, piece_pos=()):
if possible_moves is None:
possible_moves = []
print(" A B C D E F G H")
x = 0
y = 0
for row in board:
row_string = f"{colors['white']} {8 - y} "
for cell in row:
text_color = colors["black"]
if board[y][x] in "RNBQKP":
text_color = colors["white"]
if start and stats["computer_last_move"] == (x, y):
back_color = bg_colors["red"]
elif (piece_pos, (x, y)) in possible_moves:
back_color = bg_colors["yellow"]
elif (x, y) == piece_pos:
back_color = bg_colors["magenta"]
elif (x + y) % 2 == 0:
back_color = bg_colors["green"]
else:
back_color = bg_colors["cyan"]
row_string += f"{back_color}{text_color} {cell} "
x += 1
row_string += f"{bg_colors['black']}{colors['basic']} {str(8 - y)}"
if y == 1:
row_string += f" Turn: {stats['move_num']}"
elif y == 2:
if side == 0:
row_string += " White turn"
elif side == 1:
row_string += " Black turn"
elif y == 3:
row_string += f" {evaluation['game_evaluation']}"
print(row_string)
y += 1
x = 0
print(" A B C D E F G H\n")
def check_possible_moves(piece, target_pieces, other_pieces, start_x, start_y, check_castle, i_board, i_stats, computer):
possible_moves = []
if piece == target_pieces[0]:
possible_moves = pawn_moves(start_x, start_y, target_pieces, other_pieces, i_board, i_stats, computer)
elif piece == target_pieces[1]:
possible_moves = knight_moves(start_x, start_y, target_pieces, i_board)
elif piece == target_pieces[2]:
possible_moves = bishop_moves(start_x, start_y, other_pieces, i_board)
elif piece == target_pieces[3]:
possible_moves = rook_moves(start_x, start_y, other_pieces, i_board)
elif piece == target_pieces[4]:
possible_moves = rook_moves(start_x, start_y, other_pieces, i_board) + bishop_moves(start_x, start_y, other_pieces, i_board)
elif piece == target_pieces[5]:
possible_moves = king_moves(start_x, start_y, target_pieces, other_pieces, check_castle, i_board, i_stats)
return possible_moves
def add_position_repetiotion(i_board, i_stats, checking=False):
tuple_board = (tuple(i_board[0]), tuple(i_board[1]), tuple(i_board[2]), tuple(i_board[3]), tuple(i_board[4]), tuple(i_board[5]), tuple(i_board[6]), tuple(i_board[7]))
if tuple_board in i_stats["all_positions"]:
i_stats["all_positions"][tuple_board] += 1
else:
i_stats["all_positions"][tuple_board] = 1
for value in i_stats["all_positions"].values():
if value > 2:
if not checking:
input("Stalemate.")
raise KeyboardInterrupt
else:
return True
return False
# side 0 white, 1 black
def player_turn(side):
if side == 0:
own_pieces = stats["player_pieces"]
opponent_pieces = stats["opponent_pieces"]
else:
own_pieces = stats["opponent_pieces"]
opponent_pieces = stats["player_pieces"]
# disable the ability to en passant after opponent's turn
if len(stats["last_double_pawn_move"]) == 3 and stats["last_double_pawn_move"][2] == side:
stats["last_double_pawn_move"] = []
i_board = deepcopy(board)
i_stats = deepcopy(stats)
possible_moves = check_moves(own_pieces, opponent_pieces, i_board, i_stats)
if not possible_moves:
if check_opponent_moves(opponent_pieces, own_pieces, i_board, i_stats): # stalemate
print("Stalemate")
raise KeyboardInterrupt
else: # checkmate
print("Checkmate,", "white" if side == 1 else "black", "won")
raise KeyboardInterrupt
while True:
try:
clear_console()
show_board(True, side)
start_square = input("From which square: ")
if start_square == "stats":
input(stats)
continue
elif start_square == "quit":
raise KeyboardInterrupt
elif start_square == "save":
input("\n" + save() + "\n")
continue
start_x = x_convert[start_square[0].upper()]
start_y = y_convert[start_square[1]]
piece = board[start_y][start_x]
if piece not in own_pieces:
input("That is either an empty square or your opponent's piece.")
continue
able_to_move = False
for possible_move in possible_moves:
if (start_x, start_y) == possible_move[0]:
able_to_move = True
break
if not able_to_move:
input("That piece has no possible moves")
continue
if len(start_square) != 4:
clear_console()
show_board(False, side, possible_moves, (start_x, start_y))
end_square = input("To which square: ")
end_x = x_convert[end_square[0].upper()]
end_y = y_convert[end_square[1]]
else:
end_x = x_convert[start_square[2].upper()]
end_y = y_convert[start_square[3]]
if ((start_x, start_y), (end_x, end_y)) in possible_moves:
move_piece(start_x, start_y, end_x, end_y, board, stats, False)
add_position_repetiotion(board, stats)
clear_console()
show_board(False, 1-side)
break
else:
input("That move is not possible")
except (KeyError, IndexError):
input("You typed wrong. First letter (A-H) then number (1-8), for example F7.")
def evaluate_position(i_board, i_stats, side, own_pieces, oppponent_pieces):
score = 0
y = 0
white_pawn_x = []
black_pawn_x = []
for row in i_board:
x = 0
for cell in row:
if cell != " ":
score += evaluation["piece_value"].get(cell, 0)
if cell == "P":
score += evaluation["pawn_placement"][6-y][x]
if x in white_pawn_x:
score += evaluation["multiple_pawn_in_column_per_over_pawn"]
else:
white_pawn_x.append(x)
elif cell == "p":
score -= evaluation["pawn_placement"][y-1][x]
if x in black_pawn_x:
score -= evaluation["multiple_pawn_in_column_per_over_pawn"]
else:
black_pawn_x.append(x)
elif cell == "B":
score += len(bishop_moves(x, y, oppponent_pieces, i_board)) * evaluation["bishop_value_per_move"]
elif cell == "b":
score -= len(bishop_moves(x, y, own_pieces, i_board)) * evaluation["bishop_value_per_move"]
elif cell == "N":
score += len(knight_moves(x, y, own_pieces, i_board)) * evaluation["knight_value_per_move"]
elif cell == "n":
score -= len(knight_moves(x, y, oppponent_pieces, i_board)) * evaluation["knight_value_per_move"]
elif cell == "R":
score += len(rook_moves(x, y, oppponent_pieces, i_board)) * evaluation["rook_value_per_move"]
elif cell == "r":
score -= len(rook_moves(x, y, own_pieces, i_board)) * evaluation["rook_value_per_move"]
elif cell == "Q":
score += len(rook_moves(x, y, oppponent_pieces, i_board) + bishop_moves(x, y, oppponent_pieces, i_board)) * evaluation["queen_value_per_move"]
elif cell == "q":
score -= len(rook_moves(x, y, own_pieces, i_board) + bishop_moves(x, y, own_pieces, i_board)) * evaluation["queen_value_per_move"]
x += 1
y += 1
# isolated_pawn
for x in white_pawn_x:
if x == 0:
if 1 not in white_pawn_x:
score += evaluation["isolated_pawn"]
elif x == 7:
if 6 not in white_pawn_x:
score += evaluation["isolated_pawn"]
else:
if (x-1 not in white_pawn_x) or (x+1 not in white_pawn_x):
score += evaluation["isolated_pawn"]
for x in black_pawn_x:
if x == 0:
if 1 not in black_pawn_x:
score += evaluation["isolated_pawn"]
elif x == 7:
if 6 not in black_pawn_x:
score += evaluation["isolated_pawn"]
else:
if (x-1 not in black_pawn_x) or (x+1 not in black_pawn_x):
score += evaluation["isolated_pawn"]
# Castling values
if i_stats["white_castle_moved"][0] == 1 or (i_stats["white_castle_moved"][1] == 1 and i_stats["white_castle_moved"][2] == 1):
score += evaluation["castling_value"][3]
elif i_stats["white_castle_moved"][1] == 1:
score += evaluation["castling_value"][1]
elif i_stats["white_castle_moved"][2] == 1:
score += evaluation["castling_value"][2]
else:
score += evaluation["castling_value"][0]
if i_stats["black_castle_moved"][0] == 1 or (i_stats["black_castle_moved"][1] == 1 and i_stats["black_castle_moved"][2] == 1):
score += evaluation["castling_value"][3]
elif i_stats["black_castle_moved"][1] == 1:
score += evaluation["castling_value"][1]
elif i_stats["black_castle_moved"][2] == 1:
score += evaluation["castling_value"][2]
else:
score += evaluation["castling_value"][0]
"""
"pawn_wall": 10, # pawni suojelee toista pawnia
"""
# move_first
if side == i_stats["move_side"]:
score += evaluation["move_turn"] * (1 if side == 0 else -1)
return score
def evaluate_moves(possible_moves, own_pieces, opponent_pieces, side, depth):
evaluations = []
for possible_move in possible_moves:
i_board = deepcopy(board)
i_stats = deepcopy(stats)
promote = ""
start_x, start_y, end_x, end_y = possible_move[0][0], possible_move[0][1], possible_move[1][0], possible_move[1][1]
if i_board[start_y][start_x] == own_pieces[0] and len(possible_move[1]) == 3:
promote = possible_move[1][2]
move_piece(start_x, start_y, end_x, end_y, i_board, i_stats, False, promote)
add_position_repetiotion(i_board, i_stats, True)
i_stats["move_side"] = 1 - i_stats["move_side"]
if not i_stats["move_side"]:
i_stats["move_num"] += 1
# disable the ability to en passant after opponent's turn
if len(i_stats["last_double_pawn_move"]) == 3 and i_stats["last_double_pawn_move"][2] == i_stats["move_side"]:
i_stats["last_double_pawn_move"] = ()
opponent_possible_moves = check_moves(opponent_pieces, own_pieces, i_board, i_stats, True)
if (not opponent_possible_moves) and depth == 1:
if check_opponent_moves(opponent_pieces, own_pieces, i_board, i_stats): # stalemate
evaluations.append(0)
else: # checkmate
input("checkmate found #001") # testing
evaluations.append(10000000 * (1 if side == 0 else -1))
continue
scores = []
for opponent_possible_move in opponent_possible_moves:
j_board = deepcopy(i_board)
j_stats = deepcopy(i_stats)
promote = ""
start_x, start_y, end_x, end_y = opponent_possible_move[0][0], opponent_possible_move[0][1], opponent_possible_move[1][0], opponent_possible_move[1][1]
if j_board[start_y][start_x] == opponent_pieces[0] and len(opponent_possible_move[1]) == 3:
promote = opponent_possible_move[1][2]
move_piece(start_x, start_y, end_x, end_y, j_board, j_stats, False, promote)
j_stats["move_side"] = 1 - j_stats["move_side"]
if not j_stats["move_side"]:
j_stats["move_num"] += 1
# disable the ability to en passant after opponent's turn
if len(j_stats["last_double_pawn_move"]) == 3 and j_stats["last_double_pawn_move"][2] == j_stats["move_side"]:
j_stats["last_double_pawn_move"] = []
scores.append(evaluate_position(j_board, j_stats, j_stats["move_side"], own_pieces, opponent_pieces))
evaluations.append(scores)
if side == 0:
i = 0
i_max = 0
# j_max = 0
max_score = -100000000000000
for move_scores in evaluations:
move_max = min(move_scores)
if move_max > max_score:
i_max = i
max_score = move_max
# input(f"new max move found: {max_score} #004") # testing
# j_max = move_scores.index(move_max)
i += 1
# input(f"best move {possible_moves[i_max]} with the score {max_score} #005") # testing
evaluation["game_evaluation"] = max_score
return possible_moves[i_max]
else:
i = 0
i_min = 0
# j_min = 0
min_score = 100000000000000
for move_scores in evaluations:
move_min = max(move_scores)
if move_min < min_score:
i_min = i
min_score = move_min
# input(f"new min move found: {min_score} #003") # testing
# j_min = move_scores.index(move_min)
i += 1
# input(f"best move {possible_moves[i_min]} with the score {min_score} #002") # testing
evaluation["game_evaluation"] = min_score
return possible_moves[i_min]
def computer_turn(side):
if side == 0:
own_pieces = stats["player_pieces"]
opponent_pieces = stats["opponent_pieces"]
else:
own_pieces = stats["opponent_pieces"]
opponent_pieces = stats["player_pieces"]
# disable the ability to en passant after opponent's turn
if len(stats["last_double_pawn_move"]) == 3 and stats["last_double_pawn_move"][2] == side:
stats["last_double_pawn_move"] = []
i_board = deepcopy(board)
i_stats = deepcopy(stats)
possible_moves = check_moves(own_pieces, opponent_pieces, i_board, i_stats, True)
if not possible_moves:
if check_opponent_moves(opponent_pieces, own_pieces, i_board, i_stats): # stalemate
print("Stalemate")
raise KeyboardInterrupt
else: # checkmate
print("Checkmate,", "white" if side == 1 else "black", "won")
raise KeyboardInterrupt
selected_move = evaluate_moves(possible_moves, own_pieces, opponent_pieces, side, 1)
start_x, start_y, end_x, end_y = selected_move[0][0], selected_move[0][1], selected_move[1][0], selected_move[1][1]
promote = ""
if board[start_y][start_x] == own_pieces[0] and len(selected_move[1]) == 3:
promote = selected_move[1][2]
stats["computer_last_move"] = (end_x, end_y)
move_piece(start_x, start_y, end_x, end_y, board, stats, False, promote)
add_position_repetiotion(board, stats)
# x = 0-7, y = 0-7
def move_piece(start_x, start_y, end_x, end_y, i_board, i_stats, checking, promote=""):
# en passant
if (i_board[start_y][start_x] in "pP") and (i_board[end_y][end_x] == " ") and (start_x != end_x):
i_board[start_y][end_x] = " "
# actual moving of the piece
i_board[end_y][end_x] = i_board[start_y][start_x]
i_board[start_y][start_x] = " "
# double pawn move for stats and the ability for opponent to en passant
if i_board[end_y][end_x] == "p" and end_y - start_y == 2:
i_stats["last_double_pawn_move"] = (end_x, end_y, 1)
elif i_board[end_y][end_x] == "P" and start_y - end_y == 2:
i_stats["last_double_pawn_move"] = (end_x, end_y, 0)
# pawn promotion
if not checking:
if promote != "":
i_board[end_y][end_x] = promote
if i_board[end_y][end_x] == "p" and end_y == 7:
while True:
choice = input("What piece to promoto to (nbrq): ").lower()
if len(choice) == 1 and choice in "nbrq":
i_board[end_y][end_x] = choice
break
elif i_board[end_y][end_x] == "P" and end_y == 0:
while True:
choice = input("What piece to promoto to (NBRQ): ").upper()
if len(choice) == 1 and choice in "NBRQ":
i_board[end_y][end_x] = choice
break
# castle
if i_board[end_y][end_x] in "kK" and abs(end_x - start_x) == 2:
if end_x == 2:
move_piece(0, end_y, 3, end_y, i_board, i_stats, True)
else:
move_piece(7, end_y, 5, end_y, i_board, i_stats, True)
# stop castling rights
if not checking:
if i_board[end_y][end_x] == "k":
i_stats["black_castle_moved"][0] = 1
elif i_board[end_y][end_x] == "r":
if start_x == 0 and start_y == 0:
i_stats["black_castle_moved"][1] = 1
elif start_x == 7 and start_y == 0:
i_stats["black_castle_moved"][2] = 1
elif i_board[end_y][end_x] == "K":
i_stats["white_castle_moved"][0] = 1
elif i_board[end_y][end_x] == "R":
if start_x == 0 and start_y == 7:
i_stats["white_castle_moved"][1] = 1
elif start_x == 7 and start_y == 7:
i_stats["white_castle_moved"][2] = 1
# returns all moves that are possible ((start_x, start_y), (end_x, end_y))
def check_moves(own_pieces, opponent_pieces, i_board, i_stats, computer=False):
moves = []
y = 0
for row in i_board:
x = 0
for cell in row:
if cell in own_pieces:
possible_moves = check_possible_moves(cell, own_pieces, opponent_pieces, x, y, True, i_board, i_stats, computer)
for possible_move in possible_moves:
check_board = deepcopy(i_board)
check_stats = deepcopy(i_stats)
move_piece(possible_move[0][0], possible_move[0][1], possible_move[1][0], possible_move[1][1], check_board, check_stats, True)
if check_opponent_moves(own_pieces, opponent_pieces, check_board, check_stats):
moves.append(possible_move)
x += 1
y += 1
return moves
# returns True if opponent can't move to king's position, otherwise False
def check_opponent_moves(own_pieces, opponent_pieces, i_board, i_stats, positions=None):
if positions is None:
positions = []
y = 0
all_possible_moves = set()
king_pos = (-1, -1)
for row in i_board:
x = 0
for cell in row:
if cell in opponent_pieces:
new_possible_moves = check_possible_moves(cell, opponent_pieces, own_pieces, x, y, False, i_board, i_stats, False)
for new_possible_move in new_possible_moves:
all_possible_moves.update([new_possible_move[1]])
elif cell == own_pieces[5]:
king_pos = (x, y)
x += 1
y += 1
if king_pos == (-1, -1):
input("Error. King not found.")
raise KeyboardInterrupt
elif king_pos in all_possible_moves:
return False
for position in positions:
if position in all_possible_moves:
return False
return True
def main():
try:
system("title chessTAI")
print(logo)
choice = input(start_menu)
if choice == "1":
color = input("\nYou are playing against a computer.\nWhat color do you want to play (white/black/random)\n").lower()
if color == "w" or color == "white":
p_side = 0
elif color == "b" or color == "black":
p_side = 1
else:
p_side = randint(0, 1)
input(f"You are playing {'white' if p_side == 0 else 'black'}.")
while True:
if not stats["move_side"]:
stats["move_num"] += 1
if stats["move_side"] == p_side:
player_turn(p_side)
else:
computer_turn(stats["move_side"])
stats["move_side"] = 1 - stats["move_side"]
elif choice == "2":
while True:
if not stats["move_side"]:
stats["move_num"] += 1
player_turn(stats["move_side"])
stats["move_side"] = 1 - stats["move_side"]
elif choice == "3":
pass
except KeyboardInterrupt:
print("\nYou stopped the code")
input("Exiting...")
if __name__ == '__main__':
main()
Leave a comment