我重做了一个在线的移动预览例程。我可以使用关于使用Python更好和/或更好的OOP设计的注释,因为最初的版本不使用类。主要有三个班:
BoardLocation保持x,y坐标(0-7,0-7)Move用于存储一个位置,以便将光盘放在板上,以及该移动会影响多少光盘。我把Move分开了,因为我想把Moves的序列保存在记忆中,以发挥前进或逆转。Board知道光盘在两个位字段中的位置,每个播放机一个,并且知道如何在磁盘位于某个位置时翻转光盘并返回。
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))发布于 2012-08-12 15:13:25
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):将空格放在逗号后面: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):按照此代码的其余部分(和PEP 8),将其命名为convert_to_offset。
if self.valid:
self.valid = (x >= 0 and x <= 7 and y >= 0 and y <= 7)使用Python的操作符链接:0 <= x <= 7 and 0 <= y <= 7,可以稍微简化一些。但是,为什么这种方法会改变self.valid,而不改变self.x或self.y呢?将self.valid变成属性,将convert_to_offset变成静态方法。
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 Falsereturn NotImplemented而不是False --那样的话,Python将尝试(相当于) other.__eq__(self),并且只在它也是NotImplemented的情况下给出False。False的意思是“我知道这两者并不相等”;NotImplemented的意思是“我不知道如何比较它们”。
def __ne__(self, other):
return not self.__eq__(other)首先,这应该是not self == other,因为上面的比较序列相同。但是更重要的是,这是self != 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)))考虑使用生成器表达式,特别是在Py2中,map构建了一个列表(至少在那里使用itertools.imap )--但我非常肯定,并不是只有我才能找到更直接、更易于阅读的return bitarray(''.join(parse_to_bit(square) for square in 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]考虑在==周围放置空格;但更重要的是,这里不需要调用int -- bools可以很好地工作,因为序列索引(实际上,bool是int的一个子类--您甚至可以添加和乘以它们)。
def empty(self, location):
return not location.valid or (not self.at (location,'B') and not self.at (location,'W'))在参数之间放置空格(命令之后),不要在函数名(self.at)和开始括号之间放置空格。
https://codereview.stackexchange.com/questions/14568
复制相似问题