Recursion Erlang数独解算器-如何找到空白点并递归尝试可能的值

Recursion Erlang数独解算器-如何找到空白点并递归尝试可能的值,recursion,erlang,sudoku,Recursion,Erlang,Sudoku,我昨天和今天都在二郎忙着数独游戏。我现在的工作功能是,我可以检查列表形式的数独,例如 [6,7,1,8,2,3,4,9,5,5,4,9,1,7,6,3,2,8,3,2,8,5,4,9,1,6,7,1,3,2,6,5,7,8,4,9,9,8,6,4,1,2,5,7,3,4,5,7,3,9,8,6,1,2,8,9,3,2,6,4,7,5,1,7,1,4,9,3,5,2,8,6,2,6,5,7,8,1,9,3,4]. 通过查看约束(正方形、行和列中没有重复项),可以确定是否有效 此函数称为valid

我昨天和今天都在二郎忙着数独游戏。我现在的工作功能是,我可以检查列表形式的数独,例如

[6,7,1,8,2,3,4,9,5,5,4,9,1,7,6,3,2,8,3,2,8,5,4,9,1,6,7,1,3,2,6,5,7,8,4,9,9,8,6,4,1,2,5,7,3,4,5,7,3,9,8,6,1,2,8,9,3,2,6,4,7,5,1,7,1,4,9,3,5,2,8,6,2,6,5,7,8,1,9,3,4].
通过查看约束(正方形、行和列中没有重复项),可以确定是否有效

此函数称为valid(S),它接受一个数独,如果它是有效的数独,则返回true;如果不是,则返回false。该函数忽略用于表示空值的0。这是一个相同数独的示例,其中包含一些随机空值:

[0,7,1,8,2,3,4,0,5,5,4,9,0,7,6,3,2,8,3,0,8,5,0,9,1,6,7,1,3,2,6,5,7,8,4,9,0,8,6,4,1,2,5,7,0,4,5,7,3,9,8,6,1,0,8,9,3,2,6,4,7,5,1,7,1,4,9,3,0,2,8,6,2,6,5,7,8,1,9,3,4].
下一步是找到列表中的第一个0,然后尝试从1到9的值,并检查它是否生成有效的数独。如果是这样,我们可以继续到下一个0并在那里尝试值,看看它是否有效。一旦我们不能再进一步,我们就回到之前的0,尝试下一个值等等,直到我们最终得到一个已解的数独

到目前为止,我的代码看起来是这样的(基于一个几乎可以正常工作的人):

pos()是由1到9的值组成的列表。我们的想法是为First输入一个空列表,为[| Last]输入一个数独列表,在其中查找0(Nom?)。然后我们尝试一个值,如果结果列表根据我们的函数是有效的,我们继续,直到我们失败的立场或有一个结果。当我们失败时,我们返回一个新的try_值和剩余的可能性(Pos)值

当然,这不起作用,而且会返回:

5> sudoku:solve([],0,S).
** exception error: bad argument
     in operator  ++/2
        called as {[6]}
                  ++
                  [1,1,8,2,3,4,0,5,5,4,9,0,7,6,3,2,8,3,2,8,5,4,9,1,6,7,1,3,2|...]
     in call from sudoku:try_values/2 (sudoku.erl, line 140)
     in call from sudoku:try_values/2 (sudoku.erl, line 142)
由于我缺乏经验,我无法掌握我需要做什么才能使代码合乎逻辑并正常工作。如果有经验丰富的人能给我一些建议,我将不胜感激。

try_values([],[])->错误(“找不到解决方案”);
try_values([], []) -> error("No solution found");
try_values([Solution], []) -> Solution;
try_values(_, []) -> error("Bad sudoku: multiple solutions");
try_values(Heads, [0|Tail]) ->
    NewHeads = case Heads of
                   [] -> [[P] || P <- pos()];
                   _ -> [Head++[P] || P <- pos(), Head <- Heads]
              end,
    ValidHeads = [Head || Head <- NewHeads, valid(Head++Tail)],
    try_values(ValidHeads, Tail);
try_values([], [H|Tail]) -> try_values([[H]], Tail);
try_values(Heads, [H|Tail]) -> try_values([Head++[H] || Head <- Heads], Tail).

solve(Board) ->
    case valid(Board) of
        true -> try_values([], Board);
        false -> error("No solution found")
    end.
尝试_值([解决方案])->解决方案; try_值(u,[])->错误(“糟糕的数独:多个解决方案”); 尝试_值(头,[0|尾])-> NewHeads=案例负责人 []->[[P]| | P[Head++[P]| | P try_值([]板); false->错误(“未找到解决方案”) 结束。
try\u values
按照您所描述的方式进行操作。它通过查看
Board
,尝试所有可能的解决方案来构建解决方案(从
pos()
)当它发现
0
并在
ValidHeads
中收集
valid
解决方案以进一步传递它们以继续时。因此,它采取了所有可能的方法,如果在某个时候有多个
valid
数独游戏,它们都将被添加到
Heads
中,并将在
valid
上进行以下步骤的测试。
solve
只是一个用来调用
try\u值([],Board)
的包装器

基本上,
在0上递归迭代的方法是跳过所有非零(最后两个
try_值
表达式)并在零上执行操作(第四个
try_值
表达式)


前三个
try\u值
表达式检查解决方案是否存在,并在这种情况下返回它。

错误来自
solve({First++[N]},Nom,Last)
,据我所知
solve
希望
First
是一个列表,那么您可能是指
solve(First++[N],Nom,Last)再次感谢你,谢谢!-这真的不对。不幸的是,我现在仍然有这个问题。我的主要问题是我不知道如何递归地在0上迭代。我认为NOM变量必须与此相关联,但我不知道如何。完整的代码在这里。非常感谢!我很难理解PAR。t、 当head+tailH++tail无效时,head(fun(H)?)会从列表中删除。然后你使用一个end并在逗号后面加上一个NewHeads?的Erlang手册没有解释这是怎么回事。我也不明白[]和[Validhead | uuu]的情况如何最后但并非最不重要的一点是,对于难度稍大的数独游戏,它说“未找到解决方案”(虽然有解决方案)。我不明白这是怎么回事,因为这只是暴力强迫。@user2609980对不起,我的错。我做错了。我假设在任何给定的点上只有一个
有效的
解决方案,并跳过了所有其他解决方案。因此,以前的代码在所有可能的电路板树中只走了一条路。我更新了我的答案。
dropwhile/2
跳过元素直到给定谓词为
true
,然后返回列表的其余部分。这样,当
dropwhile
匹配
[]
时,没有有效的解决方案,而当它匹配[ValidHead | |]时,有效是一种可能的解决方案。无论如何,它是错误的。啊哈!现在我明白前面的代码出了什么问题。以及“结束”我不明白的一点现在在你输入代码后就清楚了。当然,如果一个数独有多个解,它也不错,但它应该显示这两个解。我把这作为一个练习留给自己;-)。非常感谢好的先生!它适用于大多数数独,但当我尝试世界上最难的数独时,它会思考10分钟和10分钟如果您得到以下错误:“Crash dump被写入:erl_Crash.dump eheap_alloc:无法分配1366780092字节的内存(类型为“heap”)。这怎么可能?:-)@user2609980这意味着算法(bruteforce)不够好,需要太多内存来解决这些情况。您需要找到更好的数独求解算法。
try_values([], []) -> error("No solution found");
try_values([Solution], []) -> Solution;
try_values(_, []) -> error("Bad sudoku: multiple solutions");
try_values(Heads, [0|Tail]) ->
    NewHeads = case Heads of
                   [] -> [[P] || P <- pos()];
                   _ -> [Head++[P] || P <- pos(), Head <- Heads]
              end,
    ValidHeads = [Head || Head <- NewHeads, valid(Head++Tail)],
    try_values(ValidHeads, Tail);
try_values([], [H|Tail]) -> try_values([[H]], Tail);
try_values(Heads, [H|Tail]) -> try_values([Head++[H] || Head <- Heads], Tail).

solve(Board) ->
    case valid(Board) of
        true -> try_values([], Board);
        false -> error("No solution found")
    end.