找到放置块的最佳策略的算法

时间:2017-11-26 20:42:57

标签: python algorithm python-3.x

此游戏的网格大小为8x8。在每轮开始时,玩家随机抽取3个街区,他必须放在网格上。放置一个块是值得的区域,并且完成一行或一列值80点,并且该行或列从板上清除。在像俄罗斯方块一样清除方块之后,块不会向下移动。

如果不能放置更多的块,则游戏结束。游戏的目的是最大化你的分数。

示例:

example

Example video

我希望创建一个程序,当提供用户可用的三个块时,将找到最佳的块放置策略。

目前,我有代码来创建网格和块列表。

class Piece():

    def __init__(self, shape):
        self.shape = shape


    def __str__(self):
        return self.render()


    def render(self):
        res = []

        for row in self.shape:
            res.append("".join(row)+"\n")

        return "".join(res)


pieces = [Piece([["x"]]),
          Piece([["x", "x"]]),
          Piece([["x", "x", "x"]]),
          Piece([["x", "x", "x", "x"]]),
          Piece([["x"],["x"]]),
          Piece([["x"], ["x"], ["x"]]),
          Piece([["x"], ["x"], ["x"], ["x"]]),
          Piece([["x", "x"], ["x", "x"]]),
          Piece([["x", "x"], ["x"]]),
          Piece([["x"], ["x", "x"]]),
          Piece([[" ", "x"], ["x", "x"]]),
          Piece([["x", "x"], [" ", "x"]]),
          Piece([["x", "x", "x"], ["x"], ["x"]]),
          Piece([["x", "x", "x"], [" ", " ", "x"], [" ", " ", "x"]]),
          Piece([[" ", " ", "x"], [" ", " ", "x"], ["x", "x", "x"]]),
          Piece([["x"], ["x"], ["x", "x", "x"]])
         ]

我在这里找到了用于创建网格的代码https://gist.github.com/Olical/2306105(不是我的)

我目前的方法只是一次搜索网格1个位置,以便找到放置它的地方,尽管这看起来效率不高。

我可以/应该使用哪种算法来找到它?

1 个答案:

答案 0 :(得分:1)

如果你想要一个非常简单的近似最佳策略,你可以使用贪婪策略尝试在当前轮次中尽可能多地清除行。

您还可以编写一个简单的评估函数,以支持诸如块的紧密堆积,留下未来块形状可能适合的孔等等。

然而,我怀疑这将远非最佳状态,因为你可能会清除一条线但是留下一个巨大的混乱,这将在未来几轮中难以清除。

如果你想找到三个区块的最佳位置,你必须解决整个game tree,因为区块位置不仅决定你当前回合的分数,还决定你将在未来几轮。

由于游戏树要完全解决,你必须找到一个很好的近似解决方案。出于多种原因,我认为这个问题适合Monte Carlo Tree Search,例如:

  • 游戏树很大,分支因子很高
  • 游戏有明确的前瞻性方向
  • 从更好的董事会职位开始,随机移动的得分往往会更好。
  • MCTS不要求为非终端位置编写评估函数

游戏树将有两种节点:播放器节点和机会节点。每个玩家节点代表棋盘上的一个棋子位置,每个机会节点代表你在该轮开始时随机抽取的三个棋盘,玩家无法控制。

此游戏的MCTS算法的伪代码将是:

def MCTS(root, board, n_sims):
    for 1...n_sims:
        b = board.copy()
        cur_node = root
        while cur_node.vists >= expand_threshold:
            if cur_node is expanded:
                if cur_node is chance node:
                    cur_node = sample child uniformly at random
                else:
                    cur_node = child that maximizes UCT score
                b.update(cur_node) # update the board position with the block placement or the new three block draw
            else if b.game_over():
                break
            else:
                expand(cur_node, b) # add all child nodes to tree
        score = b.roll_out() # play random moves to the end of the game and return final score
        cur_node.backprop(score) # propagate score and visit back up tree
    return most visited child of root

root = new Node(parent=null, total_score=0, visits=0)
board = new Board(current position)
best_move = MCTS(root, board, 10000)
print(best_move)

您需要在UCT分数中使用total_score/visits(而不是双人游戏的获胜/访问),并且您可以通过存储每个节点的总分和访问次数来将分数传播到树中。将当前模拟的分数添加到总分中,并增加访问次数。