You can't take the king :)
This commit is contained in:
commit
022cb43c92
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
__pycache__/
|
||||||
|
*.pyc
|
166
chess.py
Normal file
166
chess.py
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
#!/bin/python
|
||||||
|
|
||||||
|
import random
|
||||||
|
from collections import namedtuple
|
||||||
|
from vector import vec2, vec2_from_text
|
||||||
|
|
||||||
|
Piece = namedtuple('Piece', 'side rank')
|
||||||
|
|
||||||
|
ranks = 'RNBQKBNR'
|
||||||
|
|
||||||
|
def next_turn(turn):
|
||||||
|
return 'B' if turn == 'W' else 'W'
|
||||||
|
|
||||||
|
def create_board():
|
||||||
|
whites = {}
|
||||||
|
whites.update({vec2(c, 0): rank for (c, rank) in zip(range(8), ranks)})
|
||||||
|
whites.update({vec2(c, 1): 'P' for c in range(8)})
|
||||||
|
|
||||||
|
blacks = {}
|
||||||
|
blacks.update({vec2(c, 7): rank for (c, rank) in zip(range(8), ranks)})
|
||||||
|
blacks.update({vec2(c, 6): 'P' for c in range(8)})
|
||||||
|
|
||||||
|
return whites, blacks
|
||||||
|
|
||||||
|
def print_board(whites, blacks):
|
||||||
|
for y in range(7, -1, -1):
|
||||||
|
print(str(y + 1) + ' ', end='')
|
||||||
|
for x in range(8):
|
||||||
|
pos = vec2(x, y)
|
||||||
|
if pos in whites:
|
||||||
|
print('+' + whites[pos] + '+ ', end='')
|
||||||
|
elif pos in blacks:
|
||||||
|
print('-' + blacks[pos] + '- ', end='')
|
||||||
|
else:
|
||||||
|
print(' ', end='')
|
||||||
|
print()
|
||||||
|
print(' ' + ' '.join('ABCDEFGH'))
|
||||||
|
|
||||||
|
def get_human_move(turn):
|
||||||
|
s = input(turn + ' to move: ')
|
||||||
|
return tuple(map(vec2_from_text, s.split()))
|
||||||
|
|
||||||
|
def get_computer_move(turn, whites, blacks):
|
||||||
|
return random.choice(get_valid_moves(turn, whites, blacks))
|
||||||
|
|
||||||
|
def get_valid_dsts(src, whites, blacks):
|
||||||
|
# todo: castling
|
||||||
|
# todo: en passant
|
||||||
|
is_white_turn = src in whites
|
||||||
|
self_pieces, oppo_pieces = (whites, blacks) if is_white_turn else (blacks, whites)
|
||||||
|
|
||||||
|
piece = self_pieces[src]
|
||||||
|
valid_dsts = set()
|
||||||
|
|
||||||
|
straight_dirs = set([vec2(1, 0), vec2(-1, 0), vec2(0, 1), vec2(0, -1)])
|
||||||
|
diagonal_dirs = set([vec2(1, 1), vec2(-1, 1), vec2(1, -1), vec2(-1, -1)])
|
||||||
|
def add_dirs(dirs, *, single=False):
|
||||||
|
for dir in dirs:
|
||||||
|
delta = dir
|
||||||
|
while (src + delta).is_valid():
|
||||||
|
dst = src + delta
|
||||||
|
if dst in self_pieces:
|
||||||
|
break
|
||||||
|
valid_dsts.add(dst)
|
||||||
|
if dst in oppo_pieces:
|
||||||
|
break
|
||||||
|
if single:
|
||||||
|
break
|
||||||
|
delta += dir
|
||||||
|
|
||||||
|
if piece == 'P': # Pawn
|
||||||
|
dy = 1 if is_white_turn else -1
|
||||||
|
sy = 1 if is_white_turn else 6
|
||||||
|
dst_fw1 = src + vec2(0, dy)
|
||||||
|
dst_fw2 = src + vec2(0, dy * 2)
|
||||||
|
dst_tkl = src + vec2(-1, dy)
|
||||||
|
dst_tkr = src + vec2(1, dy)
|
||||||
|
if dst_fw1.is_valid() and dst_fw1 not in self_pieces and dst_fw1 not in oppo_pieces:
|
||||||
|
valid_dsts.add(dst_fw1)
|
||||||
|
if src.y == sy and dst_fw2 not in self_pieces and dst_fw2 not in oppo_pieces:
|
||||||
|
valid_dsts.add(dst_fw2)
|
||||||
|
if dst_tkl in oppo_pieces:
|
||||||
|
valid_dsts.add(dst_tkl)
|
||||||
|
if dst_tkr in oppo_pieces:
|
||||||
|
valid_dsts.add(dst_tkr)
|
||||||
|
elif piece == 'N': # Knight
|
||||||
|
knight_dirs = set([vec2(1, 2), vec2(2, 1), vec2(2, -1), vec2(1, -2), vec2(-1, -2), vec2(-2, -1), vec2(-2, 1), vec2(-1, 2)])
|
||||||
|
add_dirs(knight_dirs, single=True)
|
||||||
|
elif piece == 'R': # Rook
|
||||||
|
add_dirs(straight_dirs)
|
||||||
|
elif piece == 'B': # Bishop
|
||||||
|
add_dirs(diagonal_dirs)
|
||||||
|
elif piece == 'Q': # Queen
|
||||||
|
add_dirs(straight_dirs | diagonal_dirs)
|
||||||
|
elif piece == 'K': # King
|
||||||
|
add_dirs(straight_dirs | diagonal_dirs, single=True)
|
||||||
|
|
||||||
|
return valid_dsts
|
||||||
|
|
||||||
|
def get_valid_moves(turn, whites, blacks):
|
||||||
|
self_pieces = whites if turn == 'W' else blacks
|
||||||
|
return [(src, dst) for src in self_pieces for dst in get_valid_dsts(src, whites, blacks)]
|
||||||
|
|
||||||
|
def next_board(src, dst, whites, blacks):
|
||||||
|
self_pieces, oppo_pieces = (whites, blacks) if src in whites else (blacks, whites)
|
||||||
|
self_pieces[dst] = self_pieces[src] # Move src -> dst
|
||||||
|
del self_pieces[src] # Remove src
|
||||||
|
if dst in oppo_pieces: # Remove dst if it was an opponent
|
||||||
|
del oppo_pieces[dst]
|
||||||
|
return whites, blacks
|
||||||
|
|
||||||
|
# Valid moves filtered such that the opponent cannot take the current player's king
|
||||||
|
def get_legal_moves(turn, whites, blacks):
|
||||||
|
self_pieces, oppo_pieces = (whites, blacks) if turn == 'W' else (blacks, whites)
|
||||||
|
valid_moves = get_valid_moves(turn, whites, blacks)
|
||||||
|
legal_moves = []
|
||||||
|
for src, dst in valid_moves:
|
||||||
|
n_whites, n_blacks = next_board(src, dst, whites.copy(), blacks.copy())
|
||||||
|
n_turn = next_turn(turn)
|
||||||
|
n_self_pieces, n_oppo_pieces = (n_whites, n_blacks) if n_turn == 'W' else (n_blacks, n_whites)
|
||||||
|
n_valid_moves = get_valid_moves(n_turn, whites, blacks)
|
||||||
|
legal = True
|
||||||
|
for n_src, n_dst in n_valid_moves:
|
||||||
|
if n_dst in n_oppo_pieces and n_oppo_pieces[n_dst] == 'K':
|
||||||
|
legal = False
|
||||||
|
break
|
||||||
|
if legal:
|
||||||
|
legal_moves.append((src, dst))
|
||||||
|
return legal_moves
|
||||||
|
|
||||||
|
def is_in_check(turn, whites, blacks):
|
||||||
|
self_pieces, oppo_pieces = (whites, blacks) if turn == 'W' else (blacks, whites)
|
||||||
|
n_turn = next_turn(turn)
|
||||||
|
threat_moves = get_valid_moves(n_turn, whites, blacks)
|
||||||
|
for src, dst in threat_moves:
|
||||||
|
if dst in self_pieces and self_pieces[dst] == 'K':
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
turn = 'W'
|
||||||
|
whites, blacks = create_board()
|
||||||
|
while True:
|
||||||
|
print(turn, 'to move')
|
||||||
|
print_board(whites, blacks)
|
||||||
|
legal_moves = get_legal_moves(turn, whites, blacks)
|
||||||
|
print(len(legal_moves), 'valid moves')
|
||||||
|
for src, dst in legal_moves:
|
||||||
|
print(src, '->', dst)
|
||||||
|
if len(legal_moves) == 0:
|
||||||
|
print('game is over')
|
||||||
|
break
|
||||||
|
# if turn == 'W':
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
src, dst = get_human_move(turn)
|
||||||
|
if not (src, dst) in legal_moves:
|
||||||
|
print('invalid move')
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
except ValueError:
|
||||||
|
print('invalid input')
|
||||||
|
# else:
|
||||||
|
# src, dst = get_computer_move(turn, whites, blacks)
|
||||||
|
|
||||||
|
whites, blacks = next_board(src, dst, whites, blacks)
|
||||||
|
turn = next_turn(turn)
|
45
vector.py
Normal file
45
vector.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
rows = '12345678'
|
||||||
|
cols = 'ABCDEFGH'
|
||||||
|
|
||||||
|
#class vec2:
|
||||||
|
# def __init__(self, x, y):
|
||||||
|
# self.x = int(x)
|
||||||
|
# self.y = int(y)
|
||||||
|
# def __add__(self, other):
|
||||||
|
# return vec2(self.x + other.x, self.y + other.y)
|
||||||
|
# def __sub__(self, other):
|
||||||
|
# return vec2(self.x - other.x, self.y - other.y)
|
||||||
|
# def __mul__(self, scalar):
|
||||||
|
# return vec2(self.x * scalar, self.y * scalar)
|
||||||
|
# def __repr__(self):
|
||||||
|
# return 'vec2({},{})'.format(self.x, self.y)
|
||||||
|
# def __eq__(self, other):
|
||||||
|
# return self.x == other.x and self.y == other.y
|
||||||
|
|
||||||
|
class vec2:
|
||||||
|
def __init__(self, x, y):
|
||||||
|
x, y = int(x), int(y)
|
||||||
|
# if not 0 <= x < 8:
|
||||||
|
# raise Exception('invalid chessvec x: {}'.format(repr(x)))
|
||||||
|
# if not 0 <= y < 8:
|
||||||
|
# raise Exception('invalid chessvec y: {}'.format(repr(y)))
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
def __add__(self, other): # Add vec2
|
||||||
|
return vec2(self.x + other.x, self.y + other.y)
|
||||||
|
def __sub__(self, other): # Subtract vec2
|
||||||
|
return vec2(self.x - other.x, self.y - other.y)
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.x == other.x and self.y == other.y
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(self.x) + hash(self.y)
|
||||||
|
def __repr__(self):
|
||||||
|
return 'vec2({},{})'.format(self.x, self.y)
|
||||||
|
def __str__(self):
|
||||||
|
return cols[self.x] + rows[self.y] if self.is_valid() else repr(self)
|
||||||
|
def is_valid(self):
|
||||||
|
return 0 <= self.x < 8 and 0 <= self.y < 8
|
||||||
|
|
||||||
|
def vec2_from_text(s):
|
||||||
|
return vec2(cols.index(s[0]), rows.index(s[1]))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user