Python &引用;“乘车票”;灰色路线的棋盘博弈逻辑

Python &引用;“乘车票”;灰色路线的棋盘博弈逻辑,python,algorithm,graph,Python,Algorithm,Graph,我喜欢玩,所以我决定在Python中实现部分游戏逻辑,作为一个辅助编程项目。游戏板本质上是一个加权多重图,因此用它复制游戏的基本结构是轻而易举的 我遇到的一个问题是,考虑到玩家拥有的火车卡的库存,分析是否有可能通过棋盘的特定路径。我认为这更像是一个数学问题,而不是一个编程问题本身,我可能可以拼凑出一个蛮力方法来解决问题,但我认为必须有一个更有效的方法 对于那些不了解游戏的人:在任何给定的时间,每个玩家都有许多8种颜色的火车卡,加上一个特殊的“火车头”类别作为通配符。这些颜色对应于游戏板()上火车

我喜欢玩,所以我决定在Python中实现部分游戏逻辑,作为一个辅助编程项目。游戏板本质上是一个加权多重图,因此用它复制游戏的基本结构是轻而易举的

我遇到的一个问题是,考虑到玩家拥有的火车卡的库存,分析是否有可能通过棋盘的特定路径。我认为这更像是一个数学问题,而不是一个编程问题本身,我可能可以拼凑出一个蛮力方法来解决问题,但我认为必须有一个更有效的方法

对于那些不了解游戏的人:在任何给定的时间,每个玩家都有许多8种颜色的火车卡,加上一个特殊的“火车头”类别作为通配符。这些颜色对应于游戏板()上火车线的颜色,但灰色线除外,在灰色线中可以使用任何颜色,只要该段中的所有汽车都是相同的颜色。(有一些涉及隧道和渡轮的边缘案例,但我们暂且不谈。)

有了现在的代码,我可以找到两个给定城市之间的所有路径,并返回需要多少种颜色的火车卡才能走这条特定的路径,除非路径包含灰色部分。我先做非灰色部分,因为它们更简单——要么路径中的每个红/绿/蓝部分都有足够的红/绿/蓝卡,要么没有。对于灰色,因为您可以为每个片段选择任何颜色,所以它会更加复杂

对于只有一个灰色段的路径,仍然很容易——要么你有足够的任何一种颜色的卡片来填充它,要么你没有。但是,对于多个灰色段,可能会遇到这样的情况:为第一段选择的颜色使完成第二段或第三段变得不可能

举个例子,假设一个玩家的卡片库存是4个红色,2个绿色,3个蓝色,我们试图弄清楚他是否能从巴黎到维也纳。看看黑板,很容易看出,这张卡片组合的唯一可能路线是去巴黎--(3灰色)->苏黎世--(2绿色)->威尼斯--(2灰色)->扎格勒--(2灰色)->维也纳。我的算法是从绿色部分开始计算,然后在那里分配两张绿卡。然后需要决定如何使用剩余的4张红色和3张蓝色卡片来覆盖长度为3、2和2的灰色部分

当然,答案是在巴黎和苏黎世之间使用3张蓝牌,在威尼斯到扎格勒和扎格勒到维也纳之间分别使用2张红牌。但是如何编写一个通用算法来解决涉及更多颜色和更多片段的不太明显的情况下的这个问题呢

我现在的代码如下所示:

def can_afford(path, cards):
    grays = list()
    for segment in path:
        if segment.color == 'Gray':
            grays.append(segment)
        else:
            if cards.get(segment.color, 0) >= segment.weight:
                cards[segment.color] -= segment.weight
            else:
                return False
    for gray in grays:
        # Halp!
        pass
    return True
(“重量”是列车车厢中区段的长度。)


我觉得有一个非常琐碎的解决方案潜藏在这里,我只是不能把我的手指。有什么想法吗?

正如丹尼尔·布鲁克纳(Daniel Brückner)所说,找到一种方法将卡片的颜色分配给灰色部分的问题对应于,彩色卡片集对应于箱子,灰色部分对应于要打包的对象

现在,箱子包装问题是,但在这种情况下这不是灾难,因为这个问题可以通过使用解决(也就是说,时间是箱子大小的多项式),这对于您的应用来说应该足够好了,因为箱子的大小受游戏中的牌数限制。下面是装箱的一个示例实现,使用将其存储:

从functools导入lru\U缓存

@lru_cache(maxsize=None)
def packing(bins, objects):
    """Return a packing of objects into bins, or None if impossible. Both
    arguments are tuples of numbers, and the packing is returned in
    the form of a list giving the bin number for each object.

    >>> packing((4,5,6), (6,5,4))
    [2, 1, 0]
    >>> packing((4,5,6), (1,1,2,4,5))
    [0, 0, 0, 1, 2]

    """
    if not objects:
        return []
    o = objects[0]
    rest = objects[1:]
    for i, b in enumerate(bins):
        if o <= b:
            p = packing(bins[:i] + (b - o,) + bins[i+1:], rest)
            if p is not None:
                return [i] + p
    return None

请注意,如果您制作了
卡片
a,那么您可以只编写
卡片[c]
,而不是
卡片。获取(c,0)
此问题与诸如、和其他类似问题有一些相似之处。上述问题和许多相关问题都是NP完全问题,因此可能没有(已知)有效的算法解决这个问题,但我目前无法证明这一点——这只是一种直觉。我会仔细考虑一下,然后更新这个答案。

另一种方法是建立一个搜索树,如下所示:

  • 每个节点都标有一个城市名称、一组卡片和若干列火车。这与特定路线的起始城市以及可用的卡和火车票相对应

  • 节点的每个子节点对应于您可以从父节点到达的城市,以及完成从父节点到节点的路线后留在您手中的卡片和火车票

例如,树的根可以对应蒙特利尔4个蓝色、1个白色和1个通配符,以及45个火车部件。根的子元素是:

  • 多伦多(1蓝,1白,1野),42#使用3张蓝卡
  • 多伦多(2个蓝色,1个白色),42#使用2个蓝色和一个通配符
  • 纽约(1张蓝卡、1张白卡、1张野卡),42#使用3张蓝卡
  • 纽约(2个蓝色,1个白色),43#使用2个蓝色和一个通配符
  • 波士顿(3个蓝色,1个白色),43#使用1个蓝色和一张通配符
  • 波士顿(2张蓝卡,1张白卡,1张野卡),43#使用2张蓝卡
  • 波士顿(4蓝色),43#使用1张白色和一张通配符

现在,您只需在此树中执行深度优先搜索,查看是否可以到达目的地城市。您添加到搜索树中的边受手中卡片的限制(即,您不能直接从蒙特利尔前往Sault St.Marie,因为您手中总共没有6张黑卡/通配符)和剩余的火车数量(如果您只剩下3张卡片,您就无法从卡尔加里前往西雅图).

可能会喜欢这样。你是故意忽略位置(通配符)吗?是的,现在我是因为我想得到灰色路线figu