我正在编写一个播放Tic Tac Toe的程序,并有ComputerPlayer
的各种版本,例如RandomPlayer
和THandPlayer
:
class RandomPlayer(ComputerPlayer):
def __init__(self, mark):
super(RandomPlayer, self).__init__(mark=mark)
def get_move(self, board):
moves = board.available_moves()
if moves: # If "moves" is not an empty list (as it would be if cat's game were reached)
return moves[np.random.choice(len(moves))] # Apply random select to the index, as otherwise it will be seen as a 2D array
class THandPlayer(ComputerPlayer):
def __init__(self, mark):
super(THandPlayer, self).__init__(mark=mark)
def get_move(self, board):
moves = board.available_moves()
if moves: # If "moves" is not an empty list (as it would be if cat's game were reached)
for move in moves:
if board.get_next_board(move, self.mark).winner() == self.mark: # Make winning move (if possible)
return move
elif board.get_next_board(move, self.opponent_mark).winner() == self.opponent_mark: # Block opponent's winning move
return move
else:
# return moves[np.random.choice(len(moves))] # This is a repetition of the code in RandomPlayer and is not DRY
randomplayer = RandomPlayer(mark=self.mark)
return randomplayer.get_move(board)
# return RandomPlayer.get_move(board) # This returns an error as "get_move" is an instance method
如果不能进行获胜动作或对手的获胜动作被阻挡,THandPlayer
也会随机选择动作。现在我通过创建RandomPlayer
的实例并在其上调用get_move
来实现此目的。但是,如果get_move
可以被解释为可以将其解释为类方法和实例方法,则可以使其更简洁。这可能吗?
修改
为简化问题,假设我们有两个类RandomPlayer
和OtherPlayer
,两个类都有一个实例方法get_move
:
import numpy as np
class RandomPlayer:
def get_move(self, arr):
return np.random.choice(arr)
class OtherPlayer:
def get_move(self, arr):
if max(arr) > 5:
return max(arr)
else:
randomplayer=RandomPlayer()
return randomplayer.get_move(arr)
arr = np.arange(4)
otherplayer = OtherPlayer()
print otherplayer.get_move(arr)
是否可以在RandomPlayer
中使用get_move
的{{1}}方法,而无需创建OtherPlayer
的实例?
答案 0 :(得分:2)
听起来您正在寻找staticmethod
,它既不能访问cls
也不能访问self
,但可以通过以下方式访问:
>>> class Foo:
... @staticmethod
... def bar():
... print('baz')
...
>>> Foo.bar()
baz
>>> Foo().bar()
baz
答案 1 :(得分:1)
随机移动是一种特定类型的移动;放一个在ComputerPlayer
中生成一个的方法;然后,RandomPlayer
和THandPlayer
都可以根据需要调用它。
class ComputerPlayer(...):
@staticmethod
def choose_random_move(moves):
if moves:
return moves[np.random.choice(len(moves))]
class RandomPlayer(ComputerPlayer):
def get_move(self, board):
moves = board.available_moves()
if moves:
return self.choose_random_move(moves)
class THandPlayer(ComputerPlayer):
def get_move(self, board):
moves = board.available_moves()
for move in moves:
for mark in [self.mark, self.opponent_mark]:
if board.get_next_board(move, mark).winner() == mark:
return move
else:
return self.choose_random_move(moves)
一些额外的说明:
如果您的__init__
方法除了调用super
之外没有执行任何操作并传递完全相同的参数,请不要实现它;只需直接调用继承的方法。
可以重构对获胜者的两次检查。
choose_random_move
不一定需要是静态方法;您可以将其保留为具有默认实现的实例方法,该实现在选择移动时忽略任何特定于播放器的信息。如果他们愿意,派生类可以覆盖该方法。
答案 2 :(得分:1)
(这是我的另一个答案的替代方案,使用不同的抽象。)
随机移动不是与玩家相关的东西,而是与棋盘相关的东西;它就像board.available_moves
,但返回一个动作而不是所有动作。
class Board(...):
# Given how often this is called by or before
# random_move(), it would be smart to implement
# some kind of caching so that the available
# moves don't have to be recalcuated for the same board
# state every time it is called.
def available_moves(self):
...
def random_move(self):
moves = self.available_moves()
if moves:
return moves[np.random.choice(len(moves))]
class RandomPlayer(ComputerPlayer):
def get_move(self, board):
return board.random_move()
class THandPlayer(ComputerPlayer):
def get_move(self, board):
moves = board.available_moves()
if moves:
for move in moves:
if board.get_next_board(move, self.mark).winner() == self.mark:
return move
elif board.get_next_board(move, self.opponent_mark).winner() == self.opponent_mark:
return move
else:
return board.random_move()
答案 3 :(得分:0)
为了完整起见,这是我对deceze建议的解决方案的实现,其中我还遵循chepner的建议来重构两个布尔语句:
class RandomPlayer(ComputerPlayer):
def __init__(self, mark):
super(RandomPlayer, self).__init__(mark=mark)
@staticmethod
def get_move(board):
moves = board.available_moves()
if moves: # If "moves" is not an empty list (as it would be if cat's game were reached)
return moves[np.random.choice(len(moves))] # Apply random selection to the index, as otherwise it will be seen as a 2D array
class THandPlayer(ComputerPlayer):
def __init__(self, mark):
super(THandPlayer, self).__init__(mark=mark)
def get_move(self, board):
moves = board.available_moves()
if moves:
for move in moves:
if THandPlayer.next_move_winner(board, move, self.mark):
return move
elif THandPlayer.next_move_winner(board, move, self.opponent_mark):
return move
else:
return RandomPlayer.get_move(board)
@staticmethod
def next_move_winner(board, move, mark):
return board.get_next_board(move, mark).winner() == mark
静态方法既可用于默认随机播放器,也可用于重构布尔语句。