-
Notifications
You must be signed in to change notification settings - Fork 0
/
notation.py
executable file
·142 lines (129 loc) · 4.59 KB
/
notation.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
from chess import Board
import re
import types
class ParseException(Exception):
pass
def format_move(move):
sr, sf, tr, tf = move[0:4]
return '%s%d-%s%d%s' % (chr(sf + ord('a') - 1), sr, chr(tf + ord('a') - 1), tr, '=%s' % move[4] if len(move) == 5 else '')
def read(f):
format = Algebra()
board = Board()
player = 'white'
for move in parse_pgn(f):
if type(move) == types.TupleType and move[0] == "done":
print "winner", move[1]
board = Board()
player = 'white'
continue
elif type(move) == types.TupleType and move[0] == 'metadata':
print move[1]
continue
parsed = format.interpret(move, board, player)
print '...' if player == 'black' else '', move, parsed
# legal_moves = [x for x in board.legal_moves(player)]
# if not parsed in legal_moves:
# raise Exception, "%s is not legal: not in %s" % (repr(parsed), repr(sorted([board.format_move(m) for m in legal_moves])))
board.apply_move(parsed)
if player == 'white':
player = 'black'
else:
player = 'white'
Winner = { '0-1': 'black', '1-0': 'white', '1/2-1/2': 'draw' }
def parse_pgn(f):
meta = {}
for line in f:
m = re.match('\[(\w+) "(.*)"\]', line)
if m:
meta[m.group(1)] = m.group(2)
elif line.strip():
moves_found = 0
for pseudomove in re.split('\d+\.', line):
if not pseudomove.strip():
continue
parts = pseudomove.strip().split(' ')
if len(parts) == 2:
yield parts[0]
yield parts[1]
elif len(parts) == 4 and parts[2] == '' and parts[3] in Winner:
yield parts[0]
yield parts[1]
yield "done", Winner[parts[3]]
elif len(parts) == 3 and parts[1] == '' and parts[2] in Winner:
yield parts[0]
yield "done", Winner[parts[2]]
else:
raise ParseException, "Can't parse pseudomove %s %s" % (pseudomove, repr(parts))
moves_found += 1
if moves_found == 0:
raise ParseException, "Can't read %s" % line
elif meta:
yield "metadata", meta
meta = {}
class Notation:
def interpret(self, move, board, player):
pass
class Basic(Notation):
def interpret(self, move, board, player):
m = re.match('\s*([a-h])([1-8])[x\-]?([a-h])([1-8])\s*')
if m:
return ord(m.group(1)) - ord('a') + 1, int(m.group(2)), ord(m.group(3)) - ord('a') + 1, int(m.group(4))
else:
raise ParseException, "Can't parse %s" % move
class Algebra(Notation):
def interpret(self, move, board, player):
"""
>>> b = Board()
>>> Algebra().interpret('b8=Q', b, 'white')
"""
m = re.match('(?P<move>O-O(-O)?)(?P<check>\+?\+?)', move)
if m:
if m.group('move') == 'O-O':
if player == 'white':
return (1, 5, 1, 7)
else:
return (8, 5, 8, 7)
elif m.group('move') == 'O-O-O':
if player == 'white':
return (1, 5, 1, 3)
else:
return (8, 5, 8, 3)
m = re.match('^(?P<piece>[KNBRQ]?)(?P<originrank>[1-8]?)(?P<originfile>[a-h]?)x?(?P<file>[a-h])(?P<rank>[1-8])(=(?P<promote>[BNRQ]))?(?P<check>\+?\+?)$', move)
if m:
check = m.group('check')
piece = board.get_piece(m.group('piece') or 'p')
src_file = ord(m.group('originfile')) - ord('a') + 1 if m.group('originfile') else None
src_rank = int(m.group('originrank'))if m.group('originrank') else None
dest_file = ord(m.group('file')) - ord('a') + 1
dest_rank = int(m.group('rank'))
promotion = m.group('promote')
for candidate in board.legal_moves(player):
if dest_rank == candidate[2] and dest_file == candidate[3] and piece == board.get_piece(board.get_square(candidate[0], candidate[1])) and (src_rank is None or src_rank == candidate[0]) and (src_file is None or src_file == candidate[1]) and (len(candidate) == 4 or promotion == candidate[4]):
if check == '+':
m = board.apply_move(candidate)
causes_check = board.king_in_check(board.opposite_color(player))
board.undo_move(m)
if causes_check:
return candidate
else:
return candidate
print board.format()
raise ParseException, "Couldn't find match for %s %s=(%s %s%d-%s%d)%s among %s" % (player, move, piece, src_file or 'x', src_rank or 0, dest_file, dest_rank, check, repr(sorted([board.format_move(m) for m in board.legal_moves(player)])))
else:
raise ParseException, "Couldn't parse %s" % move
class Printer:
def show(self, board):
for rank in range(8, 0, -1):
print "%d %s" % (rank, board.board[(rank-1)*8:rank*8])
print " abcdefgh"
def test():
import doctest
doctest.testmod()
def main():
import sys
inf = sys.stdin
if len(sys.argv) > 1:
inf = file(sys.argv[1])
read(inf)
if __name__ == '__main__':
main()