Continued implementation of functions needed for network play
This commit is contained in:
parent
f4680cc631
commit
c7947d9790
71
lib/goban.py
71
lib/goban.py
|
@ -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):
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user