我发布了这个问题over at CodeReview,但我意识到这不是一个Haskell问题,因为它是一个算法问题。
可以找到Haskell代码on my github repo,但我认为代码并不像一般概念那么重要。
基本上,该计划计算出卡拉哈(瑞典变体)游戏中最佳的第一组动作。只考虑第一个“转弯”,所以我们假设你开始并且没有计算从对手开始移动的任何东西。
Kalaha board http://www.graf-web.at/mwm/kalaha.jpg
董事会从空店开始,每个锅中都有相同数量的弹珠。
你开始轮到你选择一个非空的锅,从锅中取出所有的大理石,然后在通过锅时丢下一块大理石在板上移动。如果你的最后一块大理石落在商店里,你会再转一圈。如果你降落在一个非空的非商店锅里,你就拿起那个锅的所有内容然后继续。最后,如果你降落在一个空锅中,转弯将被传递给对手。
到目前为止,我已经通过挑选所有可能的路径来解决这个问题,然后根据商店中大理石的数量对它们进行排序。一条路径意味着从你的一个花盆开始,做所有必要的拾取和移动,看看你是在土地上还是在空锅里。如果你在商店里着陆,你可以继续,现在有很多新的分支,就像你身边有非空罐一样。
问题在于,如果你从花盆中的五个大理石开始,它已经是相当多的路径。跳到六,ghci内存不足。
我无法弄清楚如何降低成本的原因是因为我认为在计算过程中每条路径都是必需的。虽然我在生成的数千(或数百万)中只需要最多三条路径(最好的路径),但其余路径需要通过检查它们是否真的比以前更好。
如果一个更长(通常更好)那么这是好的,但成本高。如果它比任何先前的路径短,那么程序仍然必须计算该路径才能找到它。
有没有办法解决这个问题,还是计算定义所需的所有路径?
答案 0 :(得分:2)
按顺序按顺序尝试,将你的动作序列记录为数字1到6的序列(代表你从中选取弹珠的底池),每次重播整个从一开始的序列。保持并更新三个获胜者,以及最后一系列动作,以便您知道接下来要尝试什么。如果没有下一步合法行动,请回过头来。
它可能会非常缓慢,但会使用很少的内存。你不存储结果位置,只选择从中拾取的数量,并且每次从起始位置重新重放序列,改变最后一步(而不是2,下一次尝试3,4等;如果没有更多合法的动作,回溯一级)。或者也许只是针对最后一系列动作存储位置,以便更容易回溯。
这是速度交易的典型空间。
答案 1 :(得分:2)
你可以尝试使用这个并行版本的map进行并行化:
parMap :: (a -> b) -> [a] -> Eval [b]
parMap f xs = map f xs `using` parList rseq
然后,您将为分支中的每个选择启动一个新线程。
如果你使用parMap pathFunction kalahaPots
作为你的递归,它会激发很多线程,但它可能会更快,你可以把它打碎,但我不是那么好的并行haskeller。