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

时间:2013-10-04 15:18:07

标签: recursion erlang sudoku

昨天和今天,我一直忙于在Erlang玩数独游戏。我现在的工作功能是我可以检查列表形式的数据,例如

[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].
通过查看约束(正方形,行和列中没有重复项),

是否有效。

此函数称为有效(S),它接受数独的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并尝试下一个值等等,直到我们最终得到一个解决的数独。

到目前为止我的代码看起来像这样(基于让它几乎工作的人):

solve(First,Nom,[_|Last]) -> try_values({First,Nom,Last},pos()).

try_values(_,[]) -> {error, "No solution found"};
try_values({First,Nom,Last},[N|Pos]) ->
  case valid(First++[N]++Last) of
    true ->
      case solve({First++[N]},Nom,Last) of
        {ok,_} -> {ok, "Result"};
        {error,_} -> try_values({First,N,Last},Pos)
      end;
    false -> try_values({First,N,Last},Pos)
  end.

pos()是一个由1到9的值组成的列表。我们的想法是输入First的空列表和[_ | Last]的Sudoku列表,我们在其中查找0(Nom?) 。然后我们尝试一个值,如果结果列表根据我们的函数有效,我们会继续,直到我们失败的位置或结果。当我们失败时,我们返回一个新的try_values,其剩余(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)

由于我缺乏经验,我无法理解我需要做些什么来使代码合乎逻辑和有效。如果有经验的人可以给我一些指示,我将非常感激。

1 个答案:

答案 0 :(得分:1)

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_values做你所描述的。它通过遍历Board来构建解决方案,在找到pos()并在0中收集valid个解决方案时尝试所有可能的解决方案(来自ValidHeads)以进一步传递接着说。因此,它采用了所有可能的方式,如果在某些时候有多个valid数据,它们都将被添加到Heads,并将在valid上按照以下步骤进行测试。 solve只是一个调用try_values([], Board)的包装器。

基本上,iterate recursively over 0's的方法是跳过所有非零(最后try_values表达式2)并在零上完成工作(第四个try_values表达式)。

前三个try_values表达式检查解决方案是否存在且单个并在此情况下返回。