I redid a Python Reversi move preview routine that is online. I could use comments about using Python better and/or better OOP design since the original did not use classes. There are three main classes:
Board
for the Reversi boardLocation
to hold an x,y coordinate (0-7,0-7)Move
to store a location to put a disc on a board and how many discs would be affected by that move
I separated out Move
because I would like to keep a sequence of Move
s in memory to play forward or reverse. Board
knows about where the discs are in two bitfields, one for each player, and knows how to turn over discs and return if a disc is at a location.
import unittest
import copy
from bitarray import bitarray
INITIAL_BOARD = """
|_|_|_|_|_|_|_|_|
|_|_|_|_|_|_|_|_|
|_|_|_|_|_|_|_|_|
|_|_|_|B|W|_|_|_|
|_|_|_|W|B|_|_|_|
|_|_|_|_|_|_|_|_|
|_|_|_|_|_|_|_|_|
|_|_|_|_|_|_|_|_|
"""
def other_player(playerId):
return 'B' if playerId == 'W' else 'W'
class Location:
def __init__(self,x=0,y=0):
self.valid = True
self.x = x
self.y = y
self.offset = self.convertToOffset(self.x,self.y)
def convertToOffset(self,x,y):
if self.valid:
self.valid = (x >= 0 and x <= 7 and y >= 0 and y <= 7)
return x + y * 8
def translate(self,dx,dy):
self.x += dx
self.y += dy
self.offset = self.convertToOffset(self.x,self.y)
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.__dict__ == other.__dict__
else:
return False
def __ne__(self, other):
return not self.__eq__(other)
class Board:
def __init__(self, board=INITIAL_BOARD):
self.discs = self.parse_board(board)
def make_bitstring(self,board,color_current):
other_color = other_player(color_current)
def parse_to_bit(square):
if square == color_current:
return '1'
elif square == '_' or square == other_color:
return '0'
return ''
return bitarray(''.join(map(parse_to_bit,board)))
def parse_board(self,board):
return (self.make_bitstring(board,'B'),
self.make_bitstring(board,'W'))
def show(self):
print self.discs
def at(self, location, player):
return location.valid and self.discs[int(player=='W')][location.offset]
def empty(self, location):
return not location.valid or (not self.at (location,'B') and not self.at (location,'W'))
def turnoverDisc(self, location):
offset = location.offset
self.discs[0][offset], self.discs[1][offset] = self.discs[1][offset], self.discs[0][offset]
def placeDisc(self, location, player):
self.discs[int(player=='W')][location.offset] = 1
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.__dict__ == other.__dict__
else:
return False
def __ne__(self, other):
return not self.__eq__(other)
class Move:
def __init__(self, board, location, color_player):
self.location = location
self.player = color_player
self.board = board
self.discDelta = self.makeDiscDelta()
def makeDiscDelta(self):
result = []
other = other_player(self.player)
if not self.board.empty(self.location):
return result
for dir in [(1,0),(1,-1),(0,-1),(-1,-1),(-1,0),(-1,1),(0,1),(1,1)]:
next_location = copy.copy(self.location)
next_location.translate(dir[0],dir[1])
dirDelta = []
while self.board.at(next_location,other):
dirDelta.append(copy.copy(next_location))
next_location.translate(dir[0],dir[1])
if self.board.at(next_location,self.player):
result.extend(dirDelta)
return result
def makeBoard(self):
result = copy.deepcopy(self.board)
for location in self.discDelta:
result.turnoverDisc(location)
result.placeDisc(self.location,self.player)
return result
class ReversiTest(unittest.TestCase):
def testMovePreviewWhite(self):
board = Board()
location = Location(4,5)
move = Move(board,location,'W')
self.assertEquals([Location(4,4)], move.discDelta)
def testMovePreviewBlack(self):
board = Board()
location = Location(3,2)
move = Move(board,location,'W')
self.assertEquals([Location(3,3)], move.discDelta)
def testMove(self):
board = Board()
expected_board = """
|_|_|_|_|_|_|_|_|
|_|_|_|_|_|_|_|_|
|_|_|_|_|_|_|_|_|
|_|_|_|B|W|_|_|_|
|_|_|_|W|W|_|_|_|
|_|_|_|_|W|_|_|_|
|_|_|_|_|_|_|_|_|
|_|_|_|_|_|_|_|_|
"""
expected = Board(expected_board)
location = Location(4,5)
move = Move(board,location,'W')
result = move.makeBoard()
self.assertEquals(expected, result)
self.assertEquals(board, Board())
self.assertEquals(location, Location(4,5))
expected_board
for example, you would have a method called, saydrawBoard(data)
. \$\endgroup\$