-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbot.py
147 lines (108 loc) · 4.75 KB
/
bot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import teams
import chess_utils
import pieces
import exceptions
MAXIMUM_SCORE = 10_000_000
MINIMUM_SCORE = -1 * MAXIMUM_SCORE
def move(player_team: teams.Team, bot_team: teams.Team, depth=2):
# This function is the move off the bot team.
# It's finding the best move by using the 'maxi' and 'mini' functions.
did_castling, king = try_castling(player_team, bot_team)
if did_castling:
return king
if chess_utils.is_checkmated(bot_team, player_team) or chess_utils.is_tie(bot_team, player_team):
raise chess_utils.Checkmated
score, best_move = mini(player_team, bot_team, depth, MINIMUM_SCORE)
piece_moved, move_square = best_move
chess_utils.try_to_move(piece_moved, move_square, bot_team, player_team)
return piece_moved
def mini(player_team: teams.Team, bot_team: teams.Team, depth, max_from_previous_moves):
best_score = MAXIMUM_SCORE + depth
best_move = None
if chess_utils.is_checkmated(bot_team, player_team):
return best_score, None
if chess_utils.is_tie(bot_team, player_team):
return 0, None
if depth == 0:
return teams.get_score_difference(player_team, bot_team), None
for piece in bot_team.pieces:
if piece.is_eaten:
continue
valid_moves = piece.get_valid_move_squares()
for move_square in valid_moves:
try:
# If didn't move, code wouldn't crash, just move to next move.
score_after_move = future_move(piece, move_square, player_team, bot_team, depth, best_score,
is_bot_future_turn=True)
if score_after_move <= max_from_previous_moves:
best_move = (piece, move_square)
best_score = score_after_move
return best_score, best_move
if score_after_move < best_score:
best_move = (piece, move_square)
best_score = score_after_move
except exceptions.MoveError:
pass
return best_score, best_move
def maxi(player_team: teams.Team, bot_team: teams.Team, depth, min_from_previous_moves):
best_move = None
best_score = MINIMUM_SCORE - depth
if chess_utils.is_checkmated(player_team, bot_team):
return best_score, None
if chess_utils.is_tie(player_team, bot_team):
return 0, None
if depth == 0:
return teams.get_score_difference(player_team, bot_team), best_move
for piece in player_team.pieces:
if piece.is_eaten:
continue
valid_moves = piece.get_valid_move_squares()
for move_square in valid_moves:
try:
# If didn't move code wouldn't crash, just move to next move.
score_after_move = future_move(piece, move_square, player_team, bot_team, depth, best_score,
is_bot_future_turn=False)
if score_after_move >= min_from_previous_moves:
best_move = (piece, move_square)
best_score = score_after_move
return best_score, best_move
if score_after_move > best_score:
best_move = (piece, move_square)
best_score = score_after_move
except exceptions.MoveError:
pass
return best_score, best_move
def future_move(piece, move_square, player_team, bot_team, depth, min_or_max, is_bot_future_turn):
next_move = maxi if is_bot_future_turn else mini
team_got_turn = bot_team if is_bot_future_turn else player_team
team_doesnt_got_turn = player_team if team_got_turn is bot_team else bot_team
with chess_utils.SaveMove(piece, move_square):
chess_utils.try_to_move(piece, move_square, team_got_turn, team_doesnt_got_turn)
score_after_move, _ = next_move(player_team, bot_team, depth - 1, min_or_max)
return score_after_move
def try_castling(player_team, bot_team):
king = None
rook1_square = None
rook2_square = None
for piece in bot_team.pieces:
if isinstance(piece, pieces.King):
king = piece
continue
if isinstance(piece, pieces.Rook):
if rook1_square is None:
rook1_square = piece.square
continue
rook2_square = piece.square
if rook1_square is not None:
try:
chess_utils.try_to_move(king, rook1_square, bot_team, player_team)
return True, king
except exceptions.MoveError:
pass
if rook2_square is not None:
try:
chess_utils.try_to_move(king, rook2_square, bot_team, player_team)
return True, king
except exceptions.MoveError:
pass
return False, king