此连接4游戏将用于实现游戏-玩AI.提供了样品播放器。一个接收用户输入,另一个随机播放。现在,它被设置为一个人类玩家与一个随机的游戏代理,但在未来我计划尝试的算法,如Minimax,并让人工智能代理人发挥自己。
一些更多的功能(比如在游戏结束时通知玩家,而不仅仅是打印到stdout)需要为以后的工作添加一些功能,但我只是把它作为一个工作基础来展示。我并不是在寻找功能建议,因为这些建议稍后才会出现。我将添加文档字符串和注释,但就目前而言,应该是直接的。
我正在寻找关于以下方面的技巧:程序正确性、代码结构和最佳实践(无论是否针对Python )。
(Python 3.2.3)
#!/usr/bin/env python
import numpy as np
from copy import copy
from abc import ABCMeta, abstractmethod
class Connect4Game():
def __init__(self, player1, player2):
self.player1 = player1
self.player2 = player2
self.player_names = {player1 : "Player1", player2 : "Player2"}
self.board = np.zeros((6, 7), dtype=np.int8)
self.turn = player1
self.last_move = ()
self.winner = None
def gameover(self):
if self.last_move == ():
return False
rind, cind = self.last_move
row = self.board[rind, :]
col = self.board[:, cind]
diag1 = np.diagonal(self.board, cind - rind)
diag2 = np.diagonal(np.fliplr(self.board), -(cind + rind - 6))
for line in [row, col, diag1, diag2]:
if line.shape[0] < 4:
continue
for four in [line[i:i+4] for i in range(len(line)-3)]:
if sum(four == 1) == 4:
self.winner = self.player1
return True
elif sum(four == 2) == 4:
self.winner = self.player2
return True
if sum(self.board[0] == 0) == 0:
return True
return False
def move(self, cind):
free_index = sum(self.board[:, cind] == 0) - 1
if free_index == -1:
return False
if self.turn is self.player1:
self.board[free_index, cind] = 1
self.turn = self.player2
else:
self.board[free_index, cind] = 2
self.turn = self.player1
self.last_move = (free_index, cind)
return True
def play(self):
while not self.gameover():
print(self.board)
print(self.player_names[self.turn]+"'s turn.")
self.move(self.turn.get_move(copy(self.board)))
print(self.board)
if self.winner is self.player1:
print("Winner: player1")
elif self.winner is self.player2:
print("Winner: player2")
else:
print("Tie")
class BasePlayer(metaclass=ABCMeta):
@abstractmethod
def __init__(self, empty, me, opponent):
pass
@abstractmethod
def get_move(self, board):
pass
class HumanPlayer(BasePlayer):
def __init__(self, empty, me, opponent):
pass
def get_move(self, board):
col = input("Your move (0-6): ")
return int(col)
class RandomPlayer(BasePlayer):
def __init__(self, empty, me, opponent):
pass
def get_move(self, board):
free_columns = np.where(board[0] == 0)[0]
return np.random.choice(free_columns)
def main():
player1 = HumanPlayer(0, 1, 2)
player2 = RandomPlayer(0, 2, 1)
game = Connect4Game(player1, player2)
game.play()
if __name__ == "__main__":
main()发布于 2014-07-04 03:30:25
我建议使用稍微长一些的名称(rind应该是row_ind等),添加注释(当您编写代码时,而不是后面),并避免使用违反直觉的变量名称,比如four。当您正在编写诸如four == 2之类的语句时,会感到非常困惑。
另外,我会把
self.last_move == () 使用
not self.last_move为了防止您的代码切换到使用列表或其他全部内容。
此外,为了简化您的结构,我建议将较长的函数拆分为其他较小的函数,以使您的代码更易于理解和重用。
另外,不要用看似随机数的元组初始化播放器,而是在代码中添加一些常量,以进一步提高可读性。
发布于 2014-07-05 00:10:17
self.player1和self.player2是问题的早期迹象。程序员不能数到二,我们只知道“零”、“一”和“多”。出现不止一次的任何东西都应该打包到一个容器中(考虑将相同的代码适用于两个以上的玩家)。一张单子就行了。if/else' clause inmoveseems unnecessary: Having a player list it is just self.board[free\_index, cind] = self.turn.me self.turn = self.player[self.player.next] with noifs whatsoever (in your casenextmeansopponent`).再说一遍,多人游戏和两人游戏没有多大区别。game.get_move(player)方法来反复提示玩家移动,直到提交有效的移动。这也意味着单独的移动验证和移动执行方法。https://codereview.stackexchange.com/questions/56061
复制相似问题