Implement ko checking
This commit is contained in:
parent
de81e9129f
commit
79d9fb0d9e
52
lib/goban.py
52
lib/goban.py
|
@ -45,8 +45,6 @@ class Goban:
|
||||||
self.hover = None
|
self.hover = None
|
||||||
|
|
||||||
|
|
||||||
# fixme - somewhere in this or its component functions we need to
|
|
||||||
# identify ko points :)
|
|
||||||
def play_move(self, pos):
|
def play_move(self, pos):
|
||||||
rpos = self._real_pos(pos)
|
rpos = self._real_pos(pos)
|
||||||
|
|
||||||
|
@ -66,18 +64,34 @@ class Goban:
|
||||||
"""Look for stones captured on the 4 sides of pos, remove them and increment
|
"""Look for stones captured on the 4 sides of pos, remove them and increment
|
||||||
capture counter. This pos must be a *real* position value, not an x,y tuple."""
|
capture counter. This pos must be a *real* position value, not an x,y tuple."""
|
||||||
|
|
||||||
|
# If we get here, we've definitely played a move,
|
||||||
|
# clearing any existing ko point
|
||||||
|
self.ko = None
|
||||||
|
|
||||||
# Who are we capturing
|
# Who are we capturing
|
||||||
who = self._other_color(self.to_move)
|
who = self._other_color(self.to_move)
|
||||||
|
|
||||||
|
captures = 0
|
||||||
|
|
||||||
for p in self._neighbors(pos):
|
for p in self._neighbors(pos):
|
||||||
if not self._on_board(p):
|
if not self._on_board(p):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not self._has_liberties(p, who):
|
if not self._num_liberties(p, who):
|
||||||
if self.to_move == Goban.BLACK:
|
captures += self._delete_group(p)
|
||||||
self.black_captures += self._delete_group(p)
|
|
||||||
elif self.to_move == Goban.WHITE:
|
if self.to_move == Goban.BLACK:
|
||||||
self.white_captures += self._delete_group(p)
|
self.black_captures += captures
|
||||||
|
elif self.to_move == Goban.WHITE:
|
||||||
|
self.white_captures += captures
|
||||||
|
|
||||||
|
# Check for ko
|
||||||
|
if captures == 1 and self._num_liberties(pos, self.to_move):
|
||||||
|
# find the empty point
|
||||||
|
for p in self._neighbors(pos):
|
||||||
|
if self.board[p] == Goban.EMPTY:
|
||||||
|
self.ko = p
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,14 +99,14 @@ class Goban:
|
||||||
if not self._on_board(pos):
|
if not self._on_board(pos):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Can't play atop another stone
|
# Can't play atop another stone or on the ko point
|
||||||
if self.board[pos] != Goban.EMPTY:
|
if self.board[pos] != Goban.EMPTY or pos == self.ko:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Temporarily place the stone
|
# Temporarily place the stone
|
||||||
self.board[pos] = self.to_move
|
self.board[pos] = self.to_move
|
||||||
|
|
||||||
liberties = self._has_liberties(pos, self.to_move)
|
liberties = self._num_liberties(pos, self.to_move)
|
||||||
opponent = self._other_color(self.to_move)
|
opponent = self._other_color(self.to_move)
|
||||||
|
|
||||||
kills_group = False
|
kills_group = False
|
||||||
|
@ -100,7 +114,7 @@ class Goban:
|
||||||
if not self._on_board(d):
|
if not self._on_board(d):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if self._has_liberties(d, opponent) == 0:
|
if self._num_liberties(d, opponent) == 0:
|
||||||
kills_group = True
|
kills_group = True
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@ -112,19 +126,18 @@ class Goban:
|
||||||
|
|
||||||
|
|
||||||
# Recursively find whether there are liberties for the group
|
# Recursively find whether there are liberties for the group
|
||||||
# at pos. Positive numbers are not necessarily accurate -
|
# at pos.
|
||||||
# treat this as a boolean
|
def _num_liberties(self, pos, who):
|
||||||
def _has_liberties(self, pos, who):
|
|
||||||
if not self._on_board(pos) or self.board[pos] != who:
|
if not self._on_board(pos) or self.board[pos] != who:
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
bs = self.board_size * self.board_size
|
bs = self.board_size * self.board_size
|
||||||
checked = [False] * bs
|
checked = [False] * bs
|
||||||
|
|
||||||
return self._has_liberties_r(pos, who, checked)
|
return self._num_liberties_r(pos, who, checked)
|
||||||
|
|
||||||
|
|
||||||
def _has_liberties_r(self, pos, who, checked=None):
|
def _num_liberties_r(self, pos, who, checked=None):
|
||||||
if checked[pos]:
|
if checked[pos]:
|
||||||
return 0
|
return 0
|
||||||
else:
|
else:
|
||||||
|
@ -139,7 +152,7 @@ class Goban:
|
||||||
else:
|
else:
|
||||||
liberties = 0
|
liberties = 0
|
||||||
for d in self._neighbors(pos):
|
for d in self._neighbors(pos):
|
||||||
liberties += self._has_liberties_r(d, who, checked)
|
liberties += self._num_liberties_r(d, who, checked)
|
||||||
|
|
||||||
return liberties
|
return liberties
|
||||||
|
|
||||||
|
@ -147,8 +160,6 @@ class Goban:
|
||||||
|
|
||||||
# We don't need to worry about crossing ourselves with the
|
# We don't need to worry about crossing ourselves with the
|
||||||
# recursion here, because we've already deleted the stone.
|
# recursion here, because we've already deleted the stone.
|
||||||
# It would be more efficient to avoid going backwards,
|
|
||||||
# but a lot more complicated (see _has_liberties)
|
|
||||||
def _delete_group(self, pos):
|
def _delete_group(self, pos):
|
||||||
if not self._on_board(pos):
|
if not self._on_board(pos):
|
||||||
return
|
return
|
||||||
|
@ -205,6 +216,9 @@ class Goban:
|
||||||
if pos == self.last_move:
|
if pos == self.last_move:
|
||||||
code = code + 'T'
|
code = code + 'T'
|
||||||
|
|
||||||
|
if pos == self.ko:
|
||||||
|
code = code + 'C'
|
||||||
|
|
||||||
s = img_res[code]
|
s = img_res[code]
|
||||||
s = pygame.transform.scale(s, (inc, inc))
|
s = pygame.transform.scale(s, (inc, inc))
|
||||||
ret.blit(s, ((pos % self.board_size) *inc, (pos / self.board_size) *inc))
|
ret.blit(s, ((pos % self.board_size) *inc, (pos / self.board_size) *inc))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user