首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Reversi移动类

Reversi移动类
EN

Code Review用户
提问于 2012-08-11 22:47:09
回答 1查看 2.9K关注 0票数 1

我重做了一个在线的移动预览例程。我可以使用关于使用Python更好和/或更好的OOP设计的注释,因为最初的版本不使用类。主要有三个班:

  1. Reversi董事会的Board
  2. Location保持x,y坐标(0-7,0-7)
  3. Move用于存储一个位置,以便将光盘放在板上,以及该移动会影响多少光盘。

我把Move分开了,因为我想把Moves的序列保存在记忆中,以发挥前进或逆转。Board知道光盘在两个位字段中的位置,每个播放机一个,并且知道如何在磁盘位于某个位置时翻转光盘并返回。

代码语言:javascript
复制
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))
EN

回答 1

Code Review用户

回答已采纳

发布于 2012-08-12 15:13:25

代码语言:javascript
复制
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):

代码语言:javascript
复制
        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

代码语言:javascript
复制
        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.xself.y呢?将self.valid变成属性,将convert_to_offset变成静态方法。

代码语言:javascript
复制
        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

return NotImplemented而不是False --那样的话,Python将尝试(相当于) other.__eq__(self),并且只在它也是NotImplemented的情况下给出FalseFalse的意思是“我知道这两者并不相等”;NotImplemented的意思是“我不知道如何比较它们”。

代码语言:javascript
复制
    def __ne__(self, other):
        return not self.__eq__(other)

首先,这应该是not self == other,因为上面的比较序列相同。但是更重要的是,这是self != other的默认行为,所以您也可以忽略它。

代码语言:javascript
复制
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 ''

考虑将这个函数移到模块级别,并将颜色传递到它中(或者,如果您真的喜欢它,可以为正方形使用一个类,并将它作为一个方法;但这可能并不太值得)。

代码语言:javascript
复制
        return bitarray(''.join(map(parse_to_bit,board)))

考虑使用生成器表达式,特别是在Py2中,map构建了一个列表(至少在那里使用itertools.imap )--但我非常肯定,并不是只有我才能找到更直接、更易于阅读的return bitarray(''.join(parse_to_bit(square) for square in board))

代码语言:javascript
复制
    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的一个子类--您甚至可以添加和乘以它们)。

代码语言:javascript
复制
    def empty(self, location):
        return not location.valid or (not self.at (location,'B') and not self.at (location,'W'))

在参数之间放置空格(命令之后),不要在函数名(self.at)和开始括号之间放置空格。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/14568

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档