-
Notifications
You must be signed in to change notification settings - Fork 6
/
positions.py
149 lines (124 loc) · 4.55 KB
/
positions.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
148
149
from collections import namedtuple
import chess
from exceptions import IllegalMoveError
from vision import SquareType
def print_position(position):
for x in range(8):
for y in range(8):
print(position[x][y], sep="", end="")
print()
# Extracts position from a chess.Board.
def get_position(board):
mapping = {
'P': 1, # White Pawn
'p': -1, # Black Pawn
'N': 2, # White Knight
'n': -2, # Black Knight
'B': 3, # White Bishop
'b': -3, # Black Bishop
'R': 4, # White Rook
'r': -4, # Black Rook
'Q': 5, # White Queen
'q': -5, # Black Queen
'K': 6, # White King
'k': -6 # Black King
}
def convert_to_int(board):
epd_string = board.epd()
list_int = []
for i in epd_string:
if i == " ":
return list_int
elif i != "/":
if i in mapping:
list_int.append(mapping[i])
else:
for counter in range(0, int(i)):
list_int.append(0)
def type_of(x):
if x > 0:
return SquareType.white
if x < 0:
return SquareType.black
else:
return SquareType.empty
lst = convert_to_int(board)
return [[type_of(lst[i * 8 + j]) for j in range(8)] for i in range(8)]
# Returns a chess.Move object by analysing change of positions.
# [board] should be the board of the [new_position]
def get_move_from_diff(board, old_position, new_position):
# A SquarePair denotes the starting and ending point of a move.
Square = namedtuple("Square", ["x", "y"])
SquarePair = namedtuple("SquarePair", ["start", "end"])
# Convert a move(point pair) to algebraic notation.
def pair_to_algebraic(pair):
def square_to_string(square):
mapping = "abcdefgh"
return mapping[square.y] + str(8 - square.x)
return square_to_string(pair.start) + square_to_string(pair.end)
# Returns a move(point pair) by analysing differences between two positions.
def diff_position(old_position, new_position):
diff = [
Square(x, y)
for x in range(8)
for y in range(8)
if old_position[x][y] != new_position[x][y]
]
# Number of differences between boards:
# Castling has 4.
# Capture en passant has 3.
# Any other move, promotion, or normal capture has 2.
if len(diff) == 4:
# Castling
king_points = [p for p in diff if p.y == 4]
rook_points = [p for p in diff if p.y == 0 or p.y == 7]
if len(king_points) != 1 or len(rook_points) != 1:
raise IllegalMoveError
p = king_points[0]
q = rook_points[0]
if q.y == 0:
# Castle long
return SquarePair(p, Square(p.x, 2))
elif q.y == 7:
# Castle short
return SquarePair(p, Square(p.x, 6))
else:
raise Exception("")
elif len(diff) == 3:
# Capture en passant
pawn_points = [
p for p in diff if new_position[p.x][p.y] != SquareType.empty
]
if len(pawn_points) != 1:
raise IllegalMoveError
p = pawn_points[0]
start_points = [
q
for q in diff
if q != p and old_position[q.x][q.y] == new_position[p.x][p.y]
]
if len(start_points) != 1:
raise IllegalMoveError
return SquarePair(start_points[0], p)
elif len(diff) == 2:
# Normal move, capture, or promotion
start_points = [
p for p in diff if new_position[p.x][p.y] == SquareType.empty
]
if len(start_points) != 1:
raise IllegalMoveError
start = start_points[0]
end_points = [p for p in diff if p != start]
if len(end_points) != 1:
raise IllegalMoveError
end = end_points[0]
return SquarePair(start, end)
else:
raise IllegalMoveError
square_pair = diff_position(old_position, new_position)
assert square_pair is not None
s = pair_to_algebraic(square_pair)
# Todo: deal with promotion.
# Algerbraic notation requires that promotion is identified like "a7a8q".
# Currently it is not supported.
return chess.Move.from_uci(s)