というわけでgoban.py最新版

とりあえずこれで対局を進められる。勝敗判定はできません。。
次はいよいよこれをGAE上で動かす。

# -*- coding: utf-8 -*-
import sys
import codecs

class Untouchable(Exception): pass

class Goban(object):

    empty = 0
    black = 1
    white = 2
    invalid = 3
    around_moves = ((1, 0), (-1, 0), (0, 1), (0, -1))

    def __init__(self, size):
        self.size = size
        self.data = [ [ self.empty for i in range(size) ]
            for j in range(size) ]
    
    def render(self, output=sys.stdout):
        for i, line in enumerate(self.data):
            for j, point in enumerate(line):
                if point == self.empty:
                    output.write(self._empty_str(i, j))
                elif point == self.black:
                    output.write(u'●')
                else:
                    output.write(u'○')
            output.write('\n')
    
    @classmethod
    def get_opponent_color(cls, color):
        return cls.black if color is cls.white else cls.white

    def touch(self, x, y, color):
        if not self.touchable(x, y, color):
            raise Untouchable()
        self.data[y][x] = color
        gottens = set()
        checked = set()
        opponent = self.get_opponent_color(color)
        for move_x, move_y in self.around_moves:
            next_x = x + move_x
            next_y = y + move_y
            if self.get_state(next_x, next_y) is not opponent: continue
            if not self.check_alive(next_x, next_y, opponent, checked):
                self._get_stones(next_x, next_y, gottens)
        for gotten_x, gotten_y in gottens:
            self.data[gotten_y][gotten_x] = self.empty
        return len(gottens)

    def _get_stones(self, x, y, gottens):
        color = self.get_state(x, y)
        gottens.add((x, y))
        targets = []
        target = (x, y)
        while target is not None:
            x, y = target
            for move_x, move_y in self.around_moves:
                next_x = x + move_x
                next_y = y + move_y
                if self.get_state(next_x, next_y) is not color: continue
                if (next_x, next_y) not in gottens:
                    targets.append((next_x, next_y))
                    gottens.add((next_x, next_y))
            target = targets.pop() if targets else None

    def touchable(self, x, y, color):
        if self.get_state(x, y) is not self.empty:
            return False
        elif not self.check_alive(x, y, color):
            return False
        else:
            return True

    def get_state(self, x, y):
        if x < 0 or self.size <= x or y < 0 or self.size <= y:
            return self.invalid
        return self.data[y][x]

    def check_alive(self, x, y, color, checked=None):
        if checked is None: checked = set()
        if (x, y) in checked: return
        checked.add((x, y))
        targets = []
        target = (x, y)
        while target is not None:
            x, y = target
            for move_x, move_y in self.around_moves:
                next_x = x + move_x
                next_y = y + move_y
                state = self.get_state(next_x, next_y)
                if state is self.empty:
                    return True
                elif state is color:
                    if (next_x, next_y) not in checked:
                        targets.append((next_x, next_y))
                        checked.add((next_x, next_y))
            target = targets.pop() if targets else None
        return False

    def _empty_str(self, x, y):
        if x == 0:
            if y == 0:
                return u'┏'
            elif y == self.size - 1:
                return u'┓'
            else:
                return u'┯'
        elif x == self.size - 1:
            if y == 0:
                return u'┗'
            elif y == self.size - 1:
                return u'┛'
            else:
                return u'┷'
        else:
            if y == 0:
                return u'┠'
            elif y == self.size - 1:
                return u'┨'
            else:
                return u'┼'
        
def test():
    sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
    goban_size = 19
    goban = Goban(goban_size)
    goban.touch(3, 3, Goban.black)
    goban.touch(15, 15, Goban.white)
    gotten = goban.touch(3, 4, Goban.black)
    gotten = goban.touch(2, 3, Goban.black)
    gotten = goban.touch(2, 2, Goban.white)
    gotten = goban.touch(3, 2, Goban.white)
    gotten = goban.touch(1, 3, Goban.white)
    gotten = goban.touch(2, 4, Goban.white)
    gotten = goban.touch(4, 3, Goban.white)
    gotten = goban.touch(4, 4, Goban.white)
    goban.render()
    gotten = goban.touch(3, 5, Goban.white)
    goban.render(sys.stdout)
    print 'white got', gotten, 'stones.'

def main():
    sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
    goban_size = 19
    goban = Goban(goban_size)
    turn = Goban.black
    while True:
        goban.render(sys.stdout)
        try:
            input = raw_input()
        except EOFError:
            break
        x, y = [ int(d) for d in input.split(',') ]
        try:
            goban.touch(x, y, turn)
        except Untouchable, e:
            print u'着手できません'
        else:
            turn = Goban.get_opponent_color(turn)

if __name__ == '__main__':
    main()