othello.py

from __future__ import print_function
from sys import argvpath as syspathstdout
from os import path

ROWS,COLS = 8,8
BSIZE = (ROWSCOLS)
Vecs = [(-1,0),(-1,+1),(0,+1),(+1,+1),(+1,0),(+1,-1),(0,-1),(-1,-1)]


class BoardCellState (object):
    states = ['W''B']

    def __init__(selfstate_index):
        self.state = state_index
        self.aspect = self.states[self.state]

    def __call__(self):
        return self.state

    def __str__(self):
        return self.aspect

    def toggle(self):
        self.state += 1
        if len(self.states) <= self.state:
            self.state = 0
        self.aspect = self.states[self.state]

class BoardCell (object):
    def __init__(selfrowcol):
        self.row = row
        self.col = col
        self.cid = 1 + ((row*COLS)+col)
        self.color = ((col+1) % 2if (row % 2else (col % 2)
        self.piece = None

    def __call__(self):
        return self.piece

    def __str__(self):
        return str(self.pieceif self.piece else ' '

    def __repr__(self):
        t = (self.cidself.rowself.colstr(self))
        s = '{BoardCell:{id:%d, row:%d,col:%d, state:"%s"}}'
        return s % t

    def place_piece(selfpiece):
        self.piece = piece

    def toggle_piece(self):
        self.piece.toggle()

class Othello (object):
    hr = '+'+('---+' * COLS)

    def __init__(self):
        self.board = [[BoardCell(r,cfor c in range(COLS)] for r in range(ROWS)]
        self(3,3).place_piece(BoardCellState(0))
        self(3,4).place_piece(BoardCellState(1))
        self(4,3).place_piece(BoardCellState(1))
        self(4,4).place_piece(BoardCellState(0))
        self.turn = BoardCellState(0)
        self.verbose = False

    def __call__(selfrowcol):
        return self.board[row][col]

    def __str__(self):
        a = [self.hr]
        for row in self.board:
            t = [' %s ' % str(cellfor cell in row]
            s = '|'.join(t)
            a.append('|%s|' % s)
            a.append(self.hr)
        s = 'Othello:\n%s\n\n' % '\n'.join(a)
        return s

    def traveler(selfcallback):
        for row in self.board:
            for cell in row:
                callback(cell)

    def make_move(selfrowcol):
        self.get_rays(row,col)
        self.test_rays()
        if len(self.caps):
            self(row,col).place_piece(BoardCellState(self.turn()))
            for r in self.caps:
                for c in r:
                    c().toggle()
            self.turn.toggle()
        return 0 < len(self.caps)

    def get_rays(selfrowcol):
        self.rays = []
        for v in Vecs:
            d = [(row+(v[0]*ix), col+(v[1]*ix)) for ix in range(1,max(BSIZE))]
            d = [t for t in d if (0 <= min(t)) and (t[0] < ROWSand (t[1] < COLS)]
            d = [self(t[0],t[1]) for t in d]
            self.rays.append(d)
        return self.rays

    def test_rays(self):
        self.caps = []
        for ray in self.rays:
            if len(ray) == 0: continue
            if not ray[0](): continue
            p = ray[0]()
            if p() == self.turn(): continue
            a = []
            for cell in ray:
                if not cell(): a = []; break
                if cell()() == self.turn(): break
                a.append(cell)
            if len(a): self.caps.append(a)
        return self.caps

    def print_rays(self):
        print('Rays for new move:')
        for ix,ray in enumerate(self.rays):
            print('Ray[%d] %s' % (ixstr(Vecs[ix])))
            for cell in ray:
                print(repr(cell))
        print()

    def print_caps(self):
        print('Rays with captures:')
        for ix,ray in enumerate(self.caps):
            print('Cap[%d] (captures: %d)' % (ixlen(ray)))
            for cell in ray:
                print(repr(cell))
        print()


def main(*args):
    b = Othello()
    b.make_move(4,2)
    b.make_move(5,2)
    print(b)
    return b

if __name__ == '__main__':
    obj = main(*argv[1:])