diff --git a/GTP/engine.py b/GTP/engine.py index 350d3a5..b55a8d5 100644 --- a/GTP/engine.py +++ b/GTP/engine.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # vim:fenc=utf-8 # $File: engine.py -# $Date: Fri Nov 17 13:5624 2017 +0800 +# $Date: Tue Nov 28 00:0616 2017 +0800 # $Author: renyong15 © # @@ -40,7 +40,7 @@ class GTPEngine(): return "resign" else: x, y = vertex - return "{}{}".format("ABCDEFGHJKLMNOPQRSTYVWYZ"[x - 1], y) + return "{}{}".format("ABCDEFGHIJKLMNOPQRSTYVWYZ"[x - 1], y) def _vertex_string2point(self, s): if s is None: @@ -48,7 +48,7 @@ class GTPEngine(): elif s.lower() == "pass": return utils.PASS elif len(s) > 1: - x = "abcdefghjklmnopqrstuvwxyz".find(s[0].lower()) + 1 + x = "abcdefghijklmnopqrstuvwxyz".find(s[0].lower()) + 1 if x == 0: return False if s[1:].isdigit(): @@ -93,13 +93,13 @@ class GTPEngine(): def _parse_cmd(self, message): try: - m = message.strip().split(" ", 1) + m = (message.strip().split(" ", 1) + [None])[:2] if m[0].isdigit(): id_ = int(m[0]) cmd, args = (m[1].split(" ", 1) + [None])[:2] else: id_ = None - cmd, args = (m[0].split(" ", 1) + [None])[:2] + cmd, args = (m[0], m[1]) except: return "invaild command" return id_, cmd, args diff --git a/GTP/game.py b/GTP/game.py index 3034a94..7f1b4c6 100644 --- a/GTP/game.py +++ b/GTP/game.py @@ -1,11 +1,139 @@ # -*- coding: utf-8 -*- # vim:fenc=utf-8 # $File: game.py -# $Date: Fri Nov 17 15:0745 2017 +0800 +# $Date: Tue Nov 28 14:4726 2017 +0800 # $Author: renyong15 © # import utils +import copy + + +''' +(1, 1) is considered as the upper left corner of the board, +(size, 1) is the lower left +''' + +DELTA = [[1,0], [-1,0], [0, -1], [0, 1]] + +class Executor: + def __init__(self, **kwargs): + self.game = kwargs['game'] + + + def _bfs(self, vertex, color, block, status, alive_break): + block.append(vertex) + status[self.game._flatten(vertex)] = True + nei = self._neighbor(vertex) + for n in nei: + if not status[self.game._flatten(n)]: + if self.game.board[self.game._flatten(n)] == color: + self._bfs(n, color, block, status, alive_break) + + def _find_block(self, vertex, alive_break = False): + block = [] + status = [False] * (self.game.size * self.game.size) + color = self.game.board[self.game._flatten(vertex)] + self._bfs(vertex, color, block, status, alive_break) + + for b in block: + for n in self._neighbor(b): + if self.game.board[self.game._flatten(n)] == utils.EMPTY: + return False,block + return True,block + + + def _is_qi(self, color, vertex): + nei = self._neighbor(vertex) + for n in nei: + if self.game.board[self.game._flatten(n)] == utils.EMPTY: + return True + + self.game.board[self.game._flatten(vertex)] = color + for n in nei: + if self.game.board[self.game._flatten(n)] == utils.another_color(color): + can_kill,block = self._find_block(n) + if can_kill: + self.game.board[self.game._flatten(vertex)] = utils.EMPTY + return True + + ### can not suicide + can_kill,block = self._find_block(vertex) + if can_kill: + self.game.board[self.game._flatten(vertex)] = utils.EMPTY + return False + + self.game.board[self.game._flatten(vertex)] = utils.EMPTY + return True + + + def _check_global_isomorphous(self, color, vertex): + ##backup + _board = copy.copy(self.game.board) + self.game.board[self.game._flatten(vertex)] = color + self._process_board(color, vertex) + if self.game.board in self.game.history: + res = True + else: + res = False + + self.game.board = _board + return res + + + def _in_board(self, vertex): + x, y = vertex + if x < 1 or x > self.game.size: return False + if y < 1 or y > self.game.size: return False + return True + + + def _neighbor(self, vertex): + x,y = vertex + nei = [] + for d in DELTA: + _x = x + d[0] + _y = y + d[1] + if self._in_board((_x, _y)): + nei.append((_x, _y)) + return nei + + def _process_board(self, color, vertex): + nei = self._neighbor(vertex) + for n in nei: + if self.game.board[self.game._flatten(n)] == utils.another_color(color): + can_kill, block = self._find_block(n, alive_break = True) + if can_kill: + for b in block: + self.game.board[self.game._flatten(b)] = utils.EMPTY + + + def is_valid(self, color, vertex): + ### in board + if not self._in_board(vertex): + return False + + ### already have stone + if not self.game.board[self.game._flatten(vertex)] == utils.EMPTY: + return False + + ### check if it is qi + if not self._is_qi(color, vertex): + return False + + + if self._check_global_isomorphous(color, vertex): + return False + + return True + + def do_move(self, color, vertex): + if not self.is_valid(color, vertex): + return False + self.game.board[self.game._flatten(vertex)] = color + self._process_board(color,vertex) + self.game.history.append(copy.copy(self.game.board)) + return True class Game: @@ -14,10 +142,12 @@ class Game: self.komi = 6.5 self.board = [utils.EMPTY] * (self.size * self.size) self.strategy = None + self.executor = Executor(game = self) + self.history = [] def _flatten(self, vertex): x,y = vertex - return (x-1) * self.size + (y-1) + return (y - 1) * self.size + (x-1) def clear(self): @@ -30,21 +160,44 @@ class Game: def set_komi(self, k): self.komi = k + + def check_valid(self, vertex): + return True + def do_move(self, color, vertex): if vertex == utils.PASS: return True - - id_ = self._flatten(vertex) - if self.board[id_] == utils.EMPTY: - self.board[id_] = color - return True - else: - return False + res = self.executor.do_move(color, vertex) + return res + def gen_move(self, color): - move = self.strategy.gen_move(color) - return move - #return utils.PASS + #move = self.strategy.gen_move(color) + #return move + return utils.PASS + + + def status2symbol(self, s): + pool = { utils.WHITE:'#', utils.EMPTY:'.', utils.BLACK:'*', utils.FILL:'F', utils.UNKNOWN:'?'} + return pool[s] + + + def show_board(self): + row = [i for i in range(1, 20)] + col = ' abcdefghijklmnopqrstuvwxyz' + + for i in range(self.size): + print(row[i], end = ' ') + if row[i] < 10: + print(' ', end = '') + for j in range(self.size): + print(self.status2symbol(self.board[self._flatten((j+1,i+1))]), end=' ') + print('\n') + print(' ', end = '') + for j in range(self.size + 1): + print(col[j], end = ' ') + print('\n') + diff --git a/GTP/test.py b/GTP/test.py index 734e8e6..0b8d4df 100644 --- a/GTP/test.py +++ b/GTP/test.py @@ -1,12 +1,13 @@ # -*- coding: utf-8 -*- # vim:fenc=utf-8 # $File: test.py -# $Date: Fri Nov 17 13:5600 2017 +0800 +# $Date: Tue Nov 28 14:4717 2017 +0800 # $Author: renyong15 © # from game import Game from engine import GTPEngine +import utils @@ -34,7 +35,107 @@ print(res) res = e.run_cmd('7 play BLACK C3') print(res) +res = e.run_cmd('play BLACK C4') +res = e.run_cmd('play BLACK C5') +res = e.run_cmd('play BLACK C6') +res = e.run_cmd('play BLACK D3') +print(res) + res = e.run_cmd('8 genmove BLACK') print(res) +#g.show_board() +print(g.check_valid((10, 9))) +print(g.executor._neighbor((1,1))) +print(g.do_move(utils.WHITE, (4, 6))) +#g.show_board() + +res = e.run_cmd('play BLACK L10') +res = e.run_cmd('play BLACK L11') +res = e.run_cmd('play BLACK L12') +res = e.run_cmd('play BLACK L13') +res = e.run_cmd('play BLACK L14') +res = e.run_cmd('play BLACK m15') +res = e.run_cmd('play BLACK m9') +res = e.run_cmd('play BLACK C9') +res = e.run_cmd('play BLACK D9') +res = e.run_cmd('play BLACK E9') +res = e.run_cmd('play BLACK F9') +res = e.run_cmd('play BLACK G9') +res = e.run_cmd('play BLACK H9') +res = e.run_cmd('play BLACK I9') + +res = e.run_cmd('play BLACK N9') +res = e.run_cmd('play BLACK N15') +res = e.run_cmd('play BLACK O10') +res = e.run_cmd('play BLACK O11') +res = e.run_cmd('play BLACK O12') +res = e.run_cmd('play BLACK O13') +res = e.run_cmd('play BLACK O14') +res = e.run_cmd('play BLACK M12') + +res = e.run_cmd('play WHITE M10') +res = e.run_cmd('play WHITE M11') +res = e.run_cmd('play WHITE N10') +res = e.run_cmd('play WHITE N11') + +res = e.run_cmd('play WHITE M13') +res = e.run_cmd('play WHITE M14') +res = e.run_cmd('play WHITE N13') +res = e.run_cmd('play WHITE N14') +print(res) + +res = e.run_cmd('play BLACK N12') +print(res) +#g.show_board() + +res = e.run_cmd('play BLACK P16') +res = e.run_cmd('play BLACK P17') +res = e.run_cmd('play BLACK P18') +res = e.run_cmd('play BLACK P19') +res = e.run_cmd('play BLACK Q16') +res = e.run_cmd('play BLACK R16') +res = e.run_cmd('play BLACK S16') + +res = e.run_cmd('play WHITE S18') +res = e.run_cmd('play WHITE S17') +res = e.run_cmd('play WHITE Q19') +res = e.run_cmd('play WHITE Q18') +res = e.run_cmd('play WHITE Q17') +res = e.run_cmd('play WHITE R18') +res = e.run_cmd('play WHITE R17') +res = e.run_cmd('play BLACK S19') +print(res) +#g.show_board() + +res = e.run_cmd('play WHITE R19') +g.show_board() + +res = e.run_cmd('play BLACK S19') +print(res) +g.show_board() + +res = e.run_cmd('play BLACK S19') +print(res) + + +res = e.run_cmd('play BLACK E17') +res = e.run_cmd('play BLACK F16') +res = e.run_cmd('play BLACK F18') +res = e.run_cmd('play BLACK G17') +res = e.run_cmd('play WHITE G16') +res = e.run_cmd('play WHITE G18') +res = e.run_cmd('play WHITE H17') +g.show_board() + +res = e.run_cmd('play WHITE F17') +g.show_board() + +res = e.run_cmd('play BLACK G17') +print(res) +g.show_board() + +res = e.run_cmd('play BLACK G19') +res = e.run_cmd('play BLACK G17') +g.show_board() diff --git a/GTP/utils.py b/GTP/utils.py index dcf0160..b7ce00c 100644 --- a/GTP/utils.py +++ b/GTP/utils.py @@ -1,16 +1,22 @@ # -*- coding: utf-8 -*- # vim:fenc=utf-8 # $File: utils.py -# $Date: Fri Nov 17 10:2407 2017 +0800 +# $Date: Mon Nov 27 18:2755 2017 +0800 # $Author: renyong15 © # WHITE = -1 -BLACK = +1 EMPTY = 0 +BLACK = +1 +FILL = +2 +KO = +3 +UNKNOWN = +4 PASS = (0,0) RESIGN = "resign" +def another_color(color): + return color * -1 +