Continued implementation of functions needed for network play

This commit is contained in:
Anna Rose 2012-04-15 20:57:23 -04:00
parent f4680cc631
commit c7947d9790
3 changed files with 96 additions and 26 deletions

View File

@ -43,11 +43,38 @@ class Goban:
self.hover = rpos 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): def clear_hover(self):
self.hover = None 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: if self.to_move == Goban.EMPTY:
return return
@ -56,46 +83,55 @@ class Goban:
if not self._valid_move(rpos): if not self._valid_move(rpos):
return return
self.board[rpos] = self.to_move self.board[rpos] = color
self._capture(rpos) self._capture(rpos)
self.last_move = rpos self.last_move = rpos
self.passed_last = False self.passed_last = False
self.to_move = self._other_color(self.to_move) self.to_move = self._other_color(color)
self.clear_hover() self.clear_hover()
# fixme: need to handle post-game stuff here... scoring code # 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: if self.passed_last:
self.to_move = Goban.EMPTY self.to_move = Goban.EMPTY
else: else:
self.to_move = self._other_color(self.to_move) self.to_move = self._other_color(color)
self.passed_last = True self.passed_last = True
self.last_move = None self.last_move = None
self.ko = 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.passed_last = False
self.last_move = None self.last_move = None
self.ko = None self.ko = None
self.winner = self._other_color(self.to_move) self.winner = self._other_color(color)
self.to_move = Goban.EMPTY 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 """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 color is None:
color = self.to_move
# If we get here, we've definitely played a move, # If we get here, we've definitely played a move,
# clearing any existing ko point # clearing any existing ko point
self.ko = None self.ko = None
# Who are we capturing # Who are we capturing
who = self._other_color(self.to_move) who = self._other_color(color)
captures = 0 captures = 0
@ -106,13 +142,13 @@ class Goban:
if not self._num_liberties(p, who): if not self._num_liberties(p, who):
captures += self._delete_group(p) captures += self._delete_group(p)
if self.to_move == Goban.BLACK: if color == Goban.BLACK:
self.black_captures += captures self.black_captures += captures
elif self.to_move == Goban.WHITE: elif color == Goban.WHITE:
self.white_captures += captures self.white_captures += captures
# Check for ko # 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 # find the empty point
for p in self._neighbors(pos): for p in self._neighbors(pos):
if self.board[p] == Goban.EMPTY: 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): if not self._on_board(pos):
return False return False
if color is None:
color = self.to_move
# Can't play atop another stone or on the ko point # Can't play atop another stone or on the ko point
if self.board[pos] != Goban.EMPTY or pos == self.ko: 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] = color
liberties = self._num_liberties(pos, self.to_move) liberties = self._num_liberties(pos, color)
opponent = self._other_color(self.to_move) opponent = self._other_color(color)
kills_group = False kills_group = False
for d in self._neighbors(pos): for d in self._neighbors(pos):

View File

@ -26,11 +26,14 @@ class NetworkThread(threading.Thread):
self.socket = GTPSocket(socket) self.socket = GTPSocket(socket)
self.send_lock = threading.Lock() 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): 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): def do_quit(self, gtp):
@ -38,19 +41,31 @@ class NetworkThread(threading.Thread):
def do_boardsize(self, gtp): 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): def do_clear_board(self, gtp):
pass with self.goban_lock:
self.goban.reset()
def do_komi(self, gtp): def do_komi(self, gtp):
pass with self.goban_lock:
self.goban.komi = float(gtp.arguments[0])
def do_play(self, gtp): 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): def do_genmove(self, gtp):

View File

@ -6,7 +6,7 @@ import pygame
from pygame.locals import * from pygame.locals import *
import sgc import sgc
from sgc.locals import * from sgc.locals import *
import socket
class GUI: class GUI:
@ -63,9 +63,12 @@ class GUI:
self.quit_btn.activate = sys.exit self.quit_btn.activate = sys.exit
self.quit_btn.add() 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): def do_event(self):
@ -141,7 +144,20 @@ class GUI:
# fixme: this uses localhost as a stub # fixme: this uses localhost as a stub
def wait_for_game(self): 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): def do_hover(self, event):