首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为人工智能代理连接4游戏

为人工智能代理连接4游戏
EN

Code Review用户
提问于 2014-07-04 01:13:30
回答 2查看 3.9K关注 0票数 4

此连接4游戏将用于实现游戏-玩AI.提供了样品播放器。一个接收用户输入,另一个随机播放。现在,它被设置为一个人类玩家与一个随机的游戏代理,但在未来我计划尝试的算法,如Minimax,并让人工智能代理人发挥自己。

一些更多的功能(比如在游戏结束时通知玩家,而不仅仅是打印到stdout)需要为以后的工作添加一些功能,但我只是把它作为一个工作基础来展示。我并不是在寻找功能建议,因为这些建议稍后才会出现。我将添加文档字符串和注释,但就目前而言,应该是直接的。

我正在寻找关于以下方面的技巧:程序正确性、代码结构和最佳实践(无论是否针对Python )。

(Python 3.2.3)

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

回答 2

Code Review用户

发布于 2014-07-04 03:30:25

我建议使用稍微长一些的名称(rind应该是row_ind等),添加注释(当您编写代码时,而不是后面),并避免使用违反直觉的变量名称,比如four。当您正在编写诸如four == 2之类的语句时,会感到非常困惑。

另外,我会把

代码语言:javascript
复制
self.last_move == () 

使用

代码语言:javascript
复制
not self.last_move

为了防止您的代码切换到使用列表或其他全部内容。

此外,为了简化您的结构,我建议将较长的函数拆分为其他较小的函数,以使您的代码更易于理解和重用。

另外,不要用看似随机数的元组初始化播放器,而是在代码中添加一些常量,以进一步提高可读性。

票数 5
EN

Code Review用户

发布于 2014-07-05 00:10:17

  • 拥有self.player1self.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)方法来反复提示玩家移动,直到提交有效的移动。这也意味着单独的移动验证和移动执行方法。
票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

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

复制
相关文章

相似问题

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