othello.py
from __future__ import print_function
from sys import argv, path as syspath, stdout
from os import path
ROWS,COLS = 8,8
BSIZE = (ROWS, COLS)
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__(self, state_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__(self, row, col):
self.row = row
self.col = col
self.cid = 1 + ((row*COLS)+col)
self.color = ((col+1) % 2) if (row % 2) else (col % 2)
self.piece = None
def __call__(self):
return self.piece
def __str__(self):
return str(self.piece) if self.piece else ' '
def __repr__(self):
t = (self.cid, self.row, self.col, str(self))
s = '{BoardCell:{id:%d, row:%d,col:%d, state:"%s"}}'
return s % t
def place_piece(self, piece):
self.piece = piece
def toggle_piece(self):
self.piece.toggle()
class Othello (object):
hr = '+'+('---+' * COLS)
def __init__(self):
self.board = [[BoardCell(r,c) for 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__(self, row, col):
return self.board[row][col]
def __str__(self):
a = [self.hr]
for row in self.board:
t = [' %s ' % str(cell) for 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(self, callback):
for row in self.board:
for cell in row:
callback(cell)
def make_move(self, row, col):
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(self, row, col):
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] < ROWS) and (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' % (ix, str(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)' % (ix, len(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:])