added cpu chess moving
This commit is contained in:
parent
39a3e33a06
commit
94befd04ee
|
@ -1,5 +1,6 @@
|
||||||
from os import path
|
from os import path
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
|
import time
|
||||||
import re
|
import re
|
||||||
import itertools
|
import itertools
|
||||||
from cinput import ControlInput, Button
|
from cinput import ControlInput, Button
|
||||||
|
@ -9,37 +10,56 @@ from . import sunfish
|
||||||
|
|
||||||
class GameState(Enum):
|
class GameState(Enum):
|
||||||
MAIN_MENU = auto()
|
MAIN_MENU = auto()
|
||||||
PLAYING = auto()
|
|
||||||
THINKING = auto()
|
THINKING = auto()
|
||||||
CHOOSE_ROW = auto()
|
CHOOSE_ROW = auto()
|
||||||
CHOOSE_COL = auto()
|
CHOOSE_COL = auto()
|
||||||
GAME_OVER = auto()
|
GAME_OVER = auto()
|
||||||
|
|
||||||
SAVE_FILE = path.join("data", "chess_state.fen")
|
SAVE_FILE = path.join("data", "chess_state.fen")
|
||||||
|
MAX_THINKING_SECONDS = 3
|
||||||
|
|
||||||
def execute(cinput: ControlInput, graphics: Graphics, _):
|
def execute(cinput: ControlInput, graphics: Graphics, _):
|
||||||
graphics.clear()
|
graphics.clear()
|
||||||
draw = Draw(graphics)
|
draw = Draw(graphics)
|
||||||
pos: sunfish.Position
|
hist: list[sunfish.Position]
|
||||||
|
searcher = sunfish.Searcher()
|
||||||
|
|
||||||
if path.exists(SAVE_FILE):
|
if path.exists(SAVE_FILE):
|
||||||
with open(SAVE_FILE, "r") as fen:
|
with open(SAVE_FILE, "r") as fen:
|
||||||
fenstr = fen.read()
|
fenstr = fen.read()
|
||||||
pos = parseFEN(fenstr)
|
hist = [parseFEN(fenstr)]
|
||||||
else:
|
else:
|
||||||
pos = sunfish.Position(
|
hist = [sunfish.Position(
|
||||||
sunfish.initial, 0, (True,True), (True,True), 0, 0)
|
sunfish.initial, 0, (True,True), (True,True), 0, 0)]
|
||||||
|
|
||||||
draw.draw_board(pos.board)
|
player_color = 'wb'[get_color(hist[-1])]
|
||||||
|
draw.draw_board(hist[-1].board if player_color == 'w' else hist[-1].rotate().board)
|
||||||
|
|
||||||
state = GameState.MAIN_MENU
|
state = GameState.MAIN_MENU
|
||||||
menu_index = 0
|
menu_index = 0
|
||||||
|
move = None
|
||||||
|
score = None
|
||||||
|
last_move = "Begin!"
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
if state == GameState.MAIN_MENU:
|
if state == GameState.MAIN_MENU:
|
||||||
draw.draw_menu(menu_index)
|
draw.draw_menu(menu_index)
|
||||||
elif state == GameState.PLAYING:
|
elif state == GameState.THINKING:
|
||||||
draw.draw_state()
|
draw.draw_thinking()
|
||||||
|
start = time.time()
|
||||||
|
for _, move, score in searcher.search(hist[-1], hist):
|
||||||
|
if time.time() - start > MAX_THINKING_SECONDS:
|
||||||
|
break
|
||||||
|
hist.append(hist[-1].move(move))
|
||||||
|
draw.draw_board(hist[-1].board if player_color == 'b' else hist[-1].rotate().board)
|
||||||
|
shift = -119 if player_color == 'b' else 0
|
||||||
|
last_move = sunfish.render(shift+move[0]) + " -> " + sunfish.render(shift+move[1])
|
||||||
|
if score == sunfish.MATE_UPPER:
|
||||||
|
draw.draw_checkmate(last_move, False)
|
||||||
|
state = GameState.GAME_OVER
|
||||||
|
else:
|
||||||
|
draw.draw_rowsel(last_move)
|
||||||
|
state = GameState.CHOOSE_ROW
|
||||||
|
|
||||||
key = cinput.get_one_shot()
|
key = cinput.get_one_shot()
|
||||||
if state == GameState.MAIN_MENU:
|
if state == GameState.MAIN_MENU:
|
||||||
|
@ -53,20 +73,22 @@ def execute(cinput: ControlInput, graphics: Graphics, _):
|
||||||
menu_index = 3
|
menu_index = 3
|
||||||
elif key == Button.BTN_B:
|
elif key == Button.BTN_B:
|
||||||
if menu_index == 0:
|
if menu_index == 0:
|
||||||
state = GameState.PLAYING
|
state = GameState.CHOOSE_ROW
|
||||||
elif menu_index == 1:
|
elif menu_index == 1:
|
||||||
with open(SAVE_FILE, "w") as fen:
|
with open(SAVE_FILE, "w") as fen:
|
||||||
fen.write(renderFEN(pos))
|
fen.write(renderFEN(hist[-1]))
|
||||||
return
|
return
|
||||||
elif menu_index == 2 or menu_index == 3:
|
elif menu_index == 2 or menu_index == 3:
|
||||||
pos = sunfish.Position(
|
pos = sunfish.Position(
|
||||||
sunfish.initial, 0, (True,True), (True,True), 0, 0)
|
sunfish.initial, 0, (True,True), (True,True), 0, 0)
|
||||||
if menu_index == 3:
|
if menu_index == 3:
|
||||||
pos = pos.rotate()
|
state = GameState.THINKING
|
||||||
|
else:
|
||||||
|
state = GameState.CHOOSE_ROW
|
||||||
|
hist = [pos]
|
||||||
draw.draw_board(pos.board)
|
draw.draw_board(pos.board)
|
||||||
state = GameState.PLAYING
|
|
||||||
|
|
||||||
elif state == GameState.PLAYING:
|
else:
|
||||||
if key == Button.BTN_A:
|
if key == Button.BTN_A:
|
||||||
state = GameState.MAIN_MENU
|
state = GameState.MAIN_MENU
|
||||||
|
|
||||||
|
@ -74,7 +96,6 @@ def get_color(pos):
|
||||||
return 1 if pos.board.startswith('\n') else 0
|
return 1 if pos.board.startswith('\n') else 0
|
||||||
|
|
||||||
def parseFEN(fen):
|
def parseFEN(fen):
|
||||||
""" Parses a string in Forsyth-Edwards Notation into a Position """
|
|
||||||
board, color, castling, enpas, _, _ = fen.split()
|
board, color, castling, enpas, _, _ = fen.split()
|
||||||
board = re.sub(r'\d', (lambda m: '.'*int(m.group(0))), board)
|
board = re.sub(r'\d', (lambda m: '.'*int(m.group(0))), board)
|
||||||
board = list(21*' ' + ' '.join(board.split('/')) + 21*' ')
|
board = list(21*' ' + ' '.join(board.split('/')) + 21*' ')
|
||||||
|
@ -90,7 +111,7 @@ def parseFEN(fen):
|
||||||
|
|
||||||
def renderFEN(pos, half_move_clock=0, full_move_clock=1):
|
def renderFEN(pos, half_move_clock=0, full_move_clock=1):
|
||||||
color = 'wb'[get_color(pos)]
|
color = 'wb'[get_color(pos)]
|
||||||
if get_color(pos) == 1:
|
if color == 'b':
|
||||||
pos = pos.rotate()
|
pos = pos.rotate()
|
||||||
board = '/'.join(pos.board.split())
|
board = '/'.join(pos.board.split())
|
||||||
board = re.sub(r'\.+', (lambda m: str(len(m.group(0)))), board)
|
board = re.sub(r'\.+', (lambda m: str(len(m.group(0)))), board)
|
||||||
|
|
|
@ -80,7 +80,6 @@ class Draw:
|
||||||
|
|
||||||
def draw_board(self, board: str):
|
def draw_board(self, board: str):
|
||||||
ic(board)
|
ic(board)
|
||||||
is_black = board.startswith('\n')
|
|
||||||
self._graphics.fill_rect(0, 0, self.BOARD_SIZE, self.BOARD_SIZE, 0)
|
self._graphics.fill_rect(0, 0, self.BOARD_SIZE, self.BOARD_SIZE, 0)
|
||||||
nb = "".join(board.split())
|
nb = "".join(board.split())
|
||||||
c = True
|
c = True
|
||||||
|
@ -93,7 +92,7 @@ class Draw:
|
||||||
p = nb[(row * 8) + col]
|
p = nb[(row * 8) + col]
|
||||||
if p.lower() in self.PIECES:
|
if p.lower() in self.PIECES:
|
||||||
self._draw_piece(
|
self._draw_piece(
|
||||||
self.PIECES[p.lower()], p.isupper() if not is_black else p.islower(), col, row, c)
|
self.PIECES[p.lower()], p.isupper(), col, row, c)
|
||||||
c = not c
|
c = not c
|
||||||
c = not c
|
c = not c
|
||||||
self._graphics.show()
|
self._graphics.show()
|
||||||
|
@ -106,6 +105,21 @@ class Draw:
|
||||||
self._graphics.text(marker + self.MENU[i], 12, i + 2, 1)
|
self._graphics.text(marker + self.MENU[i], 12, i + 2, 1)
|
||||||
self._graphics.show()
|
self._graphics.show()
|
||||||
|
|
||||||
def draw_state(self):
|
def draw_thinking(self):
|
||||||
self._clear_info()
|
self._clear_info()
|
||||||
|
self._graphics.text("Shh, I'm", 12, 0, 1)
|
||||||
|
self._graphics.text("thinking!", 12, 1, 1)
|
||||||
|
self._graphics.show()
|
||||||
|
|
||||||
|
def draw_checkmate(self, move: str, player_won: bool):
|
||||||
|
self._clear_info()
|
||||||
|
self._graphics.text(move, 12, 0, 1)
|
||||||
|
self._graphics.text("Checkmate", 12, 1, 1)
|
||||||
|
self._graphics.text(
|
||||||
|
"you win!" if player_won else "you lose!", 12, 2, 1)
|
||||||
|
self._graphics.show()
|
||||||
|
|
||||||
|
def draw_rowsel(self, move: str):
|
||||||
|
self._clear_info()
|
||||||
|
self._graphics.text(move, 12, 0, 1)
|
||||||
self._graphics.show()
|
self._graphics.show()
|
||||||
|
|
|
@ -378,10 +378,6 @@ class Searcher:
|
||||||
# User interface
|
# User interface
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
# Python 2 compatability
|
|
||||||
if sys.version_info[0] == 2:
|
|
||||||
input = raw_input
|
|
||||||
|
|
||||||
|
|
||||||
def parse(c):
|
def parse(c):
|
||||||
fil, rank = ord(c[0]) - ord('a'), int(c[1]) - 1
|
fil, rank = ord(c[0]) - ord('a'), int(c[1]) - 1
|
||||||
|
@ -393,15 +389,6 @@ def render(i):
|
||||||
return chr(fil + ord('a')) + str(-rank + 1)
|
return chr(fil + ord('a')) + str(-rank + 1)
|
||||||
|
|
||||||
|
|
||||||
def print_pos(pos):
|
|
||||||
print()
|
|
||||||
uni_pieces = {'R':'♜', 'N':'♞', 'B':'♝', 'Q':'♛', 'K':'♚', 'P':'♟',
|
|
||||||
'r':'♖', 'n':'♘', 'b':'♗', 'q':'♕', 'k':'♔', 'p':'♙', '.':'·'}
|
|
||||||
for i, row in enumerate(pos.board.split()):
|
|
||||||
print(' ', 8-i, ' '.join(uni_pieces.get(p, p) for p in row))
|
|
||||||
print(' a b c d e f g h \n\n')
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
hist = [Position(initial, 0, (True,True), (True,True), 0, 0)]
|
hist = [Position(initial, 0, (True,True), (True,True), 0, 0)]
|
||||||
searcher = Searcher()
|
searcher = Searcher()
|
||||||
|
|
Reference in New Issue