LoginSignup
2
2

More than 5 years have passed since last update.

「エイト・クイーン問題」をErlangで

Posted at

エイト・クイーン問題(Wikipedia)をErlangで解いてみました。

工夫した点:

  • バックトラッキング方式です。
  • 2つのクイーンが同じ行に来ない性質を利用し、1行ごとに1つのクイーンの場所を探しています。
  • クイーンがぶつかるかどうかは、これから置こうとしている場所がすでに置かれたクイーンと同じ列にあるか、行の差と列の差が等しい(=斜めに位置している)かで判断しています。
  • 解の総数が合っているかどうか確認するため、カウンターを別プロセスで起動し、解を発見するごとにカウントアップし、処理の最後に値を表示しています。
eq.erl
% solve 8-queens problem.

-module(eq).
-compile(export_all).

solve() ->
  register(counter, spawn(fun() -> counter(0) end)),
  solve(cols(), []),
  counter ! show.

cols() -> [1,2,3,4,5,6,7,8].

solve(_, Queens) when length(Queens) == 8 -> display(Queens);

solve([], _) -> ok;

solve([Col|T], Queens) ->
  case not conflict(Col, Queens) of
    true  -> solve(cols(), [Col | Queens]);
    false -> ok
  end,
  solve(T, Queens).

conflict(Col, Queens) ->
  Conflict = fun({N, QCol}) -> Col == QCol orelse abs(Col - QCol) == N end,
  lists:any(Conflict, with_idx(Queens)).

with_idx(L) -> lists:zip(lists:seq(1, length(L)), L).

display(Queens) ->
  counter ! countup,
  Frame = "**********",
  io:fwrite("~s~n", [Frame]),
  lists:foreach(fun(X) -> io:fwrite("*~s*~n", [make_line(X)]) end, Queens),
  io:fwrite("~s~n~n", [Frame]).

make_line(X) -> string:chars($., X - 1) ++ "Q" ++ string:chars($., 8 - X).

counter(N) ->
  receive
    countup -> counter(N + 1);
    show    -> io:fwrite("Count: ~w~n", [N])
  end.

「c(eq).」「eq:solve().」を実行すると、解を延々と表示します。最後の部分は次のような感じになります。


**********
*....Q...*
*......Q.*
*.Q......*
*.....Q..*
*..Q.....*
*Q.......*
*...Q....*
*.......Q*
**********

Count: 92

92と表示されます。Wikipediaによると解の総数は92個とのことですので、合っているようです。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2