Skip to content

Commit 0e1de1b

Browse files
committed
change AI class to use composition
1 parent 7d3fa91 commit 0e1de1b

File tree

4 files changed

+96
-41
lines changed

4 files changed

+96
-41
lines changed

chess.py

+48-37
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from chessai import RandomPlayer
12
from chesslogic import *
23
import random
34
import argparse
@@ -40,50 +41,67 @@ def ask_promote(board, file_moves):
4041
return CHAR_PROMOTE[choice]
4142

4243

44+
def end_game(game_status):
45+
return (game_status == BoardStatus.Checkmate or
46+
game_status == BoardStatus.Stalemate
47+
)
48+
49+
4350
if __name__=="__main__":
4451
parser = argparse.ArgumentParser()
4552
parser.add_argument("-t", "--test", help="path to test file")
4653
parser.add_argument("-ai", "--ai", help="play against AI: r - random")
47-
# TODO add argument to choose color
48-
args = parser.parse_args()
54+
parser.add_argument("-c", "--color",
55+
help="color of human player: b - black, w - white"
56+
)
4957

50-
board = Board()
5158
print(INTRO)
5259
print("move: 'e2 e4' or 'a7 a8 Q' revert: 'r' exit: '0'")
53-
print("help: 'python chess.py -h'\n")
60+
print("help: 'python chess.py -h'")
61+
args = parser.parse_args()
62+
63+
board = Board()
5464
print(board)
5565

56-
file_moves = []
66+
computer_turn = False
67+
ai_player = None
68+
if args.ai == "r":
69+
# TODO change to composition
70+
ai_player = RandomPlayer(board, False)
71+
# if args.color == "b":
72+
# computer_turn = True
73+
74+
75+
moves_input = []
5776
if args.test:
5877
with open(args.test) as f:
5978
for line in f:
6079
print(line)
61-
file_moves.append(line.strip())
62-
63-
ai_enabled = False
64-
if args.ai == "r":
65-
ai_enabled = True
80+
moves_input.append(line.strip())
6681

67-
# TODO remove this - take turn only from board itself
68-
white_turn = True
69-
computer_turn = False
7082
# TODO refactor this
7183
while True:
72-
if computer_turn == white_turn and ai_enabled:
73-
moves = board.generate_moves()
74-
move = random.choice(moves)
75-
# move = minmax(depth = 5)
76-
board.move_piece(move[0], move[1], move[2])
77-
print("computer's move")
78-
print(board)
79-
white_turn = not white_turn
84+
if ai_player and ai_player.is_white == board.white_turn:
85+
# TODO change so AI plays and returns status and move
86+
move = ai_player.get_ai_move()
87+
try:
88+
origin, target, promotion = move
89+
game_status = board.move_piece(origin, target, promotion)
90+
print("computer's move")
91+
print(board)
92+
if end_game(game_status):
93+
break
94+
except Exception as e:
95+
print(e)
96+
continue
8097
else:
8198
print("enter move")
82-
move_input = file_moves.pop(0) if len(file_moves) > 0 else input()
99+
move_input = moves_input.pop(0) if len(moves_input) > 0 else input()
83100
if move_input == 'r':
84101
try:
85102
board.revert_last_move()
86-
if ai_enabled:
103+
# TODO differnetiate if black or white
104+
if ai_player:
87105
board.revert_last_move()
88106
except Exception as e:
89107
print(e)
@@ -103,24 +121,17 @@ def ask_promote(board, file_moves):
103121
origin = text_to_coords(start)
104122
target = text_to_coords(end)
105123
promotion = text_to_promotion(promote_choice)
106-
move_return = board.move_piece(origin, target, promotion)
124+
game_status = board.move_piece(origin, target, promotion)
107125
print(board)
108-
if (move_return == BoardStatus.Checkmate or
109-
move_return == BoardStatus.Stalemate
110-
):
111-
break
112-
white_turn = not white_turn
126+
if end_game(game_status):
127+
break
113128
except MissingPromotionChoice as e:
114-
promotion = ask_promote(board, file_moves)
129+
promotion = ask_promote(board, moves_input)
115130
if promotion == None:
116131
break
117-
move_return = board.move_piece(origin, target, promotion)
132+
game_status = board.move_piece(origin, target, promotion)
118133
print(board)
119-
if (move_return == BoardStatus.Checkmate or
120-
move_return == BoardStatus.Stalemate
121-
):
122-
break
123-
white_turn = not white_turn
124-
134+
if end_game(game_status):
135+
break
125136
except ValueError as e:
126137
print(e)

chessai.py

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from chesslogic import *
2+
import random
3+
4+
5+
# Base class for AIs
6+
class BaseAI:
7+
def __init__(self, board, is_white, name):
8+
# Composition
9+
self.board = board
10+
self.name = name
11+
self.is_white = is_white
12+
13+
# Virtual function
14+
def get_ai_move(self):
15+
raise NotImplementedError("AI should implement get_ai_move function")
16+
17+
18+
# Plays moves randomly
19+
class RandomPlayer(BaseAI):
20+
def __init__(self, board, is_white):
21+
super().__init__(board, is_white, "random player")
22+
23+
def get_ai_move(self):
24+
moves = self.board.generate_moves()
25+
return random.choice(moves)
26+
27+
28+
class MinMaxPlayer(BaseAI):
29+
pass
30+
31+
32+
class NegaMax(BaseAI):
33+
pass
34+
35+
36+
class MonteCarlo(BaseAI):
37+
pass
38+
39+
40+
class MinMaxMonteCarlo(BaseAI):
41+
pass

chesslogic.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
from exceptions import *
44
from functools import partial
55
from collections import deque
6-
import sys
7-
import random
6+
87

98
# Search "API START" for interface functions
109

@@ -19,6 +18,7 @@ def __init__(self, white_turn = True, position = None):
1918
self.passant_pawn = None
2019
self.moves_record = deque()
2120
self.game_status = BoardStatus.Normal
21+
self.moves_counter = 0
2222

2323
# Store coordinates for each piece type
2424
self.white_pieces = dict((piece, set()) for piece in self.piece_types)
@@ -548,6 +548,7 @@ def revert_last_move(self):
548548
try:
549549
self._revert()
550550
self.white_turn = not self.white_turn
551+
self.moves_counter -= 1
551552
except Exception as e:
552553
print(e)
553554

@@ -584,6 +585,7 @@ def move_piece(self, origin, target, promotion) -> BoardStatus:
584585
self.white_turn = not self.white_turn
585586
target_piece = self._get_piece(target)
586587
game_status = self.update_status(origin_piece.color)
588+
self.moves_counter += 1
587589
return game_status
588590
else:
589591
raise IllegalMoveException(f"illegal move {origin, target}")
@@ -607,4 +609,4 @@ def generate_moves(self):
607609
if __name__=="__main__":
608610
print(INTRO)
609611
print("GUI: python chessgui.py")
610-
print("Terminal: python chess.py")
612+
print("Terminal: python chess.py")

definitions.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,5 @@ def __str__(self) -> str:
149149
if __name__=="__main__":
150150
print(Record(Coords(1,2), Pawn(Colors.Black)))
151151
print(Record(Coords(1,2), None))
152-
print(CHAR_PROMOTE)
152+
print(CHAR_PROMOTE)
153+

0 commit comments

Comments
 (0)