use*_*714 28 algorithm graph-algorithm coronasdk
我需要一些建议.我正在开发一种类似于Flow Free的游戏,其中游戏板由网格和彩色点组成,用户必须将相同的彩色点连接在一起而不与其他线重叠,并且用尽所有板中的空闲空间.
我的问题是关于水平创造.我希望随机生成各级(并且至少应该能够自己解决,以便它可以给玩家提示)并且我在使用什么算法.有什么建议?
注意:图像显示了Flow Free的目标,它与我正在开发的目标相同.
谢谢你的帮助.:)
use*_*210 28
考虑使用一对更简单,更易于管理的算法来解决您的问题:一种算法可靠地创建简单的预解决板,另一种算法重新排列流量,使简单的板更复杂.
第一部分,构建一个简单的预解块板,如果你在x 网格n
上使用流,那么它是微不足道的(如果你想要的话):n
n
或者,您可以提供自己的手工制作的启动板以传递到第二部分.这个阶段的唯一目标是建立一个有效的板,即使它只是微不足道或预先确定,所以值得保持简单.
第二部分,重新排列流量,涉及在每个流上循环,看看哪个流可以与其相邻流一起生长和收缩:
f
.f
是最小长度(比如3个方格长),请跳到下一个迭代,因为我们f
现在无法收缩.f
另一个点的一个点的旁边g
(如果有多个g
可供选择,则随机选择一个)...
f
沿着它的流动将头部移动一个方块(即,朝向尾部移动一个方格).f
现在是一个方格更短,有一个空方格.(这个难题现在尚未解决.)g
到空出的空方格中f
.现在有一个空方块,其中g
的点移动了.g
.现在g
比这次迭代开始时长一平方.(这个难题也回归了.)f
的尾点.目前的方法是有限的(点将永远是邻居),但它很容易扩展:
f
,寻找与其他流交换空间的棘手方法......这里的整体解决方案可能不是你想要的理想解决方案,但现在你有两个简单的算法,你可以进一步充实,以发挥一个大的,无所不包的算法的作用.最后,我认为这种方法是可管理的,不是神秘的,易于调整,如果不是其他的话,这是一个好的起点.
更新:我根据上述步骤编写了一个概念验证.从下面的第一个5x5网格开始,该过程产生了随后的5个不同的板.有些是有趣的,有些则不是,但它们总是对一个已知的解决方案有效.
初始点
5随机结果(对不对齐的截图)
随机8x8为衡量标准.起点与上述相同的简单列方法相同.
创建这样一个级别最直接的方法是找到解决它的方法.这样,您基本上可以生成任何随机启动配置,并通过尝试解决它来确定它是否是有效级别.这将产生最多样化的水平.
即使你找到了一种以其他方式生成关卡的方法,你仍然希望应用这个求解算法来证明生成的关卡是好的;)
如果电路板的NxN单元大小,并且还有N种可用颜色,则强制枚举所有可能的配置(无论它们是否形成起始节点和结束节点之间的实际路径)将采用:
所以,
换句话说,一开始可能的组合数量相当高,但一旦开始使电路板变大,也会变得非常快.
显然,我们应尽量减少配置数量.一种方法是考虑每种颜色的起始和结束单元格之间的最小距离("dMin") - 我们知道至少应该有这么多单元格具有该颜色.计算最小距离可以使用简单的洪水填充或Dijkstra算法完成.(注意,整个下一部分仅讨论了单元格的数量,但没有说明它们的位置)
在您的示例中,这意味着(不计算开始和结束单元格)
dMin(orange) = 1
dMin(red) = 1
dMin(green) = 5
dMin(yellow) = 3
dMin(blue) = 5
Run Code Online (Sandbox Code Playgroud)
这意味着,在尚未确定颜色的15个细胞中,必须存在至少1个橙色,1个红色,5个绿色,3个黄色和5个蓝色细胞,也总共产生15个细胞.对于这个特定的例子,这意味着通过(最短的)最短路径连接每个颜色的起始和结束单元填充整个板 - 即在用最短路径填充板之后,没有未着色的单元保留.(这应该被视为"运气",并非每个电路板的启动配置都会导致这种情况发生).
通常,在这一步之后,我们有许多可以自由着色的单元格,让我们称这个数字为U.对于N = 5,
U = 15 - (dMin(orange) + dMin(red) + dMin(green) + dMin(yellow) + dMin(blue))
Run Code Online (Sandbox Code Playgroud)
因为这些细胞可以采用任何颜色,我们还可以确定可以具有特定颜色的最大细胞数:
dMax(orange) = dMin(orange) + U
dMax(red) = dMin(red) + U
dMax(green) = dMin(green) + U
dMax(yellow) = dMin(yellow) + U
dMax(blue) = dMin(blue) + U
Run Code Online (Sandbox Code Playgroud)
(在此特定示例中,U = 0,因此每种颜色的最小单元数也是最大值).
如果我们使用这些颜色限制来强力计算所有可能的组合,我们会担心的组合要少得多.更具体地说,在这个特定的例子中,我们将:
15! / (1! * 1! * 5! * 3! * 5!)
= 1307674368000 / 86400
= 15135120 combinations left, about a factor 2000 less.
Run Code Online (Sandbox Code Playgroud)
但是,这仍然没有给我们实际的路径.因此,更好的想法是回溯搜索,我们依次处理每种颜色并尝试找到以下所有路径:
第二个标准将减少每种颜色报告的路径数量,这会导致尝试的路径总数大大减少(由于组合效应).
在伪代码中:
function SolveLevel(initialBoard of size NxN)
{
foreach(colour on initialBoard)
{
Find startCell(colour) and endCell(colour)
minDistance(colour) = Length(ShortestPath(initialBoard, startCell(colour), endCell(colour)))
}
//Determine the number of uncoloured cells remaining after all shortest paths have been applied.
U = N^(N^2 - 2N) - (Sum of all minDistances)
firstColour = GetFirstColour(initialBoard)
ExplorePathsForColour(
initialBoard,
firstColour,
startCell(firstColour),
endCell(firstColour),
minDistance(firstColour),
U)
}
}
function ExplorePathsForColour(board, colour, startCell, endCell, minDistance, nrOfUncolouredCells)
{
maxDistance = minDistance + nrOfUncolouredCells
paths = FindAllPaths(board, colour, startCell, endCell, minDistance, maxDistance)
foreach(path in paths)
{
//Render all cells in 'path' on a copy of the board
boardCopy = Copy(board)
boardCopy = ApplyPath(boardCopy, path)
uRemaining = nrOfUncolouredCells - (Length(path) - minDistance)
//Recursively explore all paths for the next colour.
nextColour = NextColour(board, colour)
if(nextColour exists)
{
ExplorePathsForColour(
boardCopy,
nextColour,
startCell(nextColour),
endCell(nextColour),
minDistance(nextColour),
uRemaining)
}
else
{
//No more colours remaining to draw
if(uRemaining == 0)
{
//No more uncoloured cells remaining
Report boardCopy as a result
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这只会实现FindAllPaths(board,color,startCell,endCell,minDistance,maxDistance).这里棘手的问题是我们不是在寻找最短路径,而是寻找落在minDistance和maxDistance确定的范围内的任何路径.因此,我们不能只使用Dijkstra或A*,因为它们只记录到每个细胞的最短路径,而不是任何可能的弯路.
找到这些路径的一种方法是使用板的多维阵列,其中每个单元能够存储多个路点,并且路点被定义为该对(先前的路点,到原点的距离).一旦我们到达目的地,前一个航路点需要能够重建整个路径,并且到原点的距离阻止我们超过maxDistance.
然后可以通过从startCell向外使用类似于探测的泛洪填充来查找所有路径,其中对于给定的单元格,递归地探索每个无色或相同的当前颜色的邻域(除了形成的那些之外)我们到达原点的当前路径,直到我们到达endCell或超过maxDistance.
这个策略的改进是我们不会从startCell向外探索endCell,而是我们从startCell和endCell向外探索并行,使用Floor(maxDistance/2)和Ceil(maxDistance/2)作为各自的最大距离.对于较大的maxDistance值,这应该将探索的单元格数量从2*maxDistance ^ 2减少到maxDistance ^ 2.
我在我的numberlink求解器和生成器中实现了以下算法.在强制执行规则时,路径永远不会触及自身,这在大多数"硬核"数字链接应用和谜题中是正常的
我的numberlink格式使用ascii字符而不是数字.这是一个例子:
$ bin/numberlink --generate=35x20
Warning: Including non-standard characters in puzzle
35 20
....bcd.......efg...i......i......j
.kka........l....hm.n....n.o.......
.b...q..q...l..r.....h.....t..uvvu.
....w.....d.e..xx....m.yy..t.......
..z.w.A....A....r.s....BB.....p....
.D.........E.F..F.G...H.........IC.
.z.D...JKL.......g....G..N.j.......
P...a....L.QQ.RR...N....s.....S.T..
U........K......V...............T..
WW...X.......Z0..M.................
1....X...23..Z0..........M....44...
5.......Y..Y....6.........C.......p
5...P...2..3..6..VH.......O.S..99.I
........E.!!......o...."....O..$$.%
.U..&&..J.\\.(.)......8...*.......+
..1.......,..-...(/:.."...;;.%+....
..c<<.==........)./..8>>.*.?......@
.[..[....]........:..........?..^..
..._.._.f...,......-.`..`.7.^......
{{......].....|....|....7.......@..
Run Code Online (Sandbox Code Playgroud)
在这里,我通过我的解算器(相同的种子)运行它:
$ bin/numberlink --generate=35x20 | bin/numberlink --tubes
Found a solution!
????bcd???????efg???i??????i??????j
?kka????????l????hm?n????n?o???????
?b???q??q???l??r?????h?????t??uvvu?
????w?????d?e??xx????m?yy??t???????
??z?w?A????A????r?s????BB?????p????
?D?????????E?F??F?G???H?????????IC?
?z?D???JKL???????g????G??N?j???????
P???a????L?QQ?RR???N????s?????S?T??
U????????K??????V???????????????T??
WW???X???????Z0??M?????????????????
1????X???23??Z0??????????M????44???
5???????Y??Y????6?????????C???????p
5???P???2??3??6??VH???????O?S??99?I
????????E?!!??????o????"????O??$$?%
?U??&&??J?\\?(?)??????8???*???????+
??1???????,??-???(/:??"???;;?%+????
??c<<?==????????)?/??8>>?*????????@
?[??[????]????????:?????????????^??
???_??_?f???,??????-?`??`?7?^??????
{{??????]?????|????|????7???????@??
Run Code Online (Sandbox Code Playgroud)
我已经测试了用迭代地随机合并两个相邻路径的函数替换步骤(4).然而它游戏更加密集,我已经认为上面几乎太密集而不困难.
以下是我生成的不同大小的问题列表:https://github.com/thomasahle/numberlink/blob/master/puzzles/inputs3