From c7947d9790e09f0f83b835166f92df13895cd6f0 Mon Sep 17 00:00:00 2001 From: Anna Wiggins Date: Sun, 15 Apr 2012 20:57:23 -0400 Subject: [PATCH] Continued implementation of functions needed for network play --- lib/goban.py | 71 ++++++++++++++++++++++++++++++++++---------- lib/networkthread.py | 27 +++++++++++++---- lib/pygogui.py | 24 ++++++++++++--- 3 files changed, 96 insertions(+), 26 deletions(-) diff --git a/lib/goban.py b/lib/goban.py index 9b2761d..dc273cc 100644 --- a/lib/goban.py +++ b/lib/goban.py @@ -43,11 +43,38 @@ class Goban: self.hover = rpos + def reset(self): + """Reset the board to a pre-game state""" + # Clear the board by setting it to the same size it currently is at + self.set_board_size(self.board_size) + self.to_move = Goban.BLACK + self.black_captures = 0 + self.white_captures = 0 + self.last_move = None + self.passed_last = False + self.ko = None + self.hover = None + self.elapsed_time = 0 + self.winner = Goban.EMPTY + + + def set_board_size(self, new_size): + """Set the board to a new size. This will also + reset the board to a blank state, but will *not* reset captures, etc + (call reset() first if you want that)""" + self.board_size = new_size + num_points = board_size * board_size + self.board = [Goban.EMPTY] * num_points + + def clear_hover(self): self.hover = None - def play_move(self, pos): + def play_move(self, pos, color=None): + if color is None: + color = self.to_move + if self.to_move == Goban.EMPTY: return @@ -56,46 +83,55 @@ class Goban: if not self._valid_move(rpos): return - self.board[rpos] = self.to_move + self.board[rpos] = color self._capture(rpos) self.last_move = rpos self.passed_last = False - self.to_move = self._other_color(self.to_move) + self.to_move = self._other_color(color) self.clear_hover() # fixme: need to handle post-game stuff here... scoring code - def pass_move(self): + def pass_move(self, color=None): + if color is None: + color = self.to_move + if self.passed_last: self.to_move = Goban.EMPTY else: - self.to_move = self._other_color(self.to_move) + self.to_move = self._other_color(color) self.passed_last = True self.last_move = None self.ko = None - def resign(self): + def resign(self, color=None): + if color is None: + color = self.to_move + self.passed_last = False self.last_move = None self.ko = None - self.winner = self._other_color(self.to_move) + self.winner = self._other_color(color) self.to_move = Goban.EMPTY - def _capture(self, pos): + def _capture(self, pos, color=None): """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.""" + if color is None: + color = self.to_move + # If we get here, we've definitely played a move, # clearing any existing ko point self.ko = None # Who are we capturing - who = self._other_color(self.to_move) + who = self._other_color(color) captures = 0 @@ -106,13 +142,13 @@ class Goban: if not self._num_liberties(p, who): captures += self._delete_group(p) - if self.to_move == Goban.BLACK: + if color == Goban.BLACK: self.black_captures += captures - elif self.to_move == Goban.WHITE: + elif color == Goban.WHITE: self.white_captures += captures # Check for ko - if captures == 1 and self._num_liberties(pos, self.to_move): + if captures == 1 and self._num_liberties(pos, color): # find the empty point for p in self._neighbors(pos): if self.board[p] == Goban.EMPTY: @@ -121,19 +157,22 @@ class Goban: - def _valid_move(self, pos): + def _valid_move(self, pos, color=None): if not self._on_board(pos): return False + if color is None: + color = self.to_move + # Can't play atop another stone or on the ko point if self.board[pos] != Goban.EMPTY or pos == self.ko: return False # Temporarily place the stone - self.board[pos] = self.to_move + self.board[pos] = color - liberties = self._num_liberties(pos, self.to_move) - opponent = self._other_color(self.to_move) + liberties = self._num_liberties(pos, color) + opponent = self._other_color(color) kills_group = False for d in self._neighbors(pos): diff --git a/lib/networkthread.py b/lib/networkthread.py index 44e4e5b..a868dd3 100644 --- a/lib/networkthread.py +++ b/lib/networkthread.py @@ -26,11 +26,14 @@ class NetworkThread(threading.Thread): self.socket = GTPSocket(socket) self.send_lock = threading.Lock() - GTPSocket.known_cmds = GTPSocket.known_cmds & set(dispatcher.keys()) + GTPSocket.known_cmds = GTPSocket.known_cmds & set(NetworkThread.dispatcher.keys()) def run(self): - pass + while True: + gtp = self.socket.get() + if gtp is not None: + NetworkThread.dispatcher[gtp.command](gtp) def do_quit(self, gtp): @@ -38,19 +41,31 @@ class NetworkThread(threading.Thread): def do_boardsize(self, gtp): - pass + with self.goban_lock: + self.goban.set_board_size(int(gtp.arguments[0])) def do_clear_board(self, gtp): - pass + with self.goban_lock: + self.goban.reset() def do_komi(self, gtp): - pass + with self.goban_lock: + self.goban.komi = float(gtp.arguments[0]) def do_play(self, gtp): - pass + if gtp.arguments[0] == 'black': + color = goban.Goban.BLACK + elif gtp.arguments[0] == 'white': + color = goban.Goban.WHITE + + row = int(gtp.arguments[1][1:]) + col = ord(gtp.arguments[1][0]) - 96 + + with self.goban_lock: + self.goban.play_move((row,col), color) def do_genmove(self, gtp): diff --git a/lib/pygogui.py b/lib/pygogui.py index de3a2cd..a0900ff 100644 --- a/lib/pygogui.py +++ b/lib/pygogui.py @@ -6,7 +6,7 @@ import pygame from pygame.locals import * import sgc from sgc.locals import * - +import socket class GUI: @@ -63,9 +63,12 @@ class GUI: self.quit_btn.activate = sys.exit self.quit_btn.add() -# self.waiting + self.wait_dialog = sgc.widgets.Dialog(title="Please wait...", widget=sgc.widgets.Label(text='Waiting for a connection')) + self.wait_dialog.rect.center = self.screen.rect.center - # pygame.time.set_timer(USEREVENT, 1000) + # Generate a spurious event once a second, just to + # force an update + pygame.time.set_timer(USEREVENT, 1000) def do_event(self): @@ -141,7 +144,20 @@ class GUI: # fixme: this uses localhost as a stub def wait_for_game(self): - pass + self.wait_dialog.add() + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.bind(("127.0.0.1", 6859)) + sock.listen(1) + conn, addr = sock.accept() + sock.close() + + self.socket = gtpsocket.GTPSocket(conn) + self.net_thread = networkthread.NetworkThread(self.goban, conn) + self.net_thread.start() + self.network_mode = True + + self.wait_dialog.remove() def do_hover(self, event):