Знаю, что баян, но для меня было весьма показательно.
Например, вот вариант, который я написал где-то за полчаса:
-module(queens_classic).
-export([solve/0]).
solve() ->
    solve(lists:seq(1, 8), lists:seq(1, 15 + 15), 1, []).
print_board([]) -> io:format("~n", []);
print_board([H|T]) ->
    Line = [string:copies(". ", H - 1), "@ ", string:copies(". ", 8 - H)],
    io:format("~s~n", [Line]),
    print_board(T).
solve(_, _, Cols, Result) when Cols > 8 ->
    io:format("~p~n", [Result]),
    print_board(Result);
solve(Rows, Diags, Col, Result) ->
    lists:foreach(fun(Row) ->
                     D1 = Row + Col,
                     D2 = Row - Col + 8 + 15,
                     T = lists:member(Row, Rows) andalso
                         lists:member(D1, Diags) andalso
                         lists:member(D2, Diags),
                     if T ->
                         Rows1 = Rows -- [Row],
                         Diags1 = Diags -- [D1, D2],
                         solve(Rows1, Diags1, Col + 1, [Row | Result]);
                        true -> void
                     end
                  end, Rows).
Выглядит ужасно, и стиль однозначно понятно какой: C/Python на стероидах (циклы, if'ы).
А вот над этим вариантом я провозился несколько часов:
-module(queens).
-export([solve/0]).
solve() ->
    solve(1, []).
print_board([]) -> io:format("~n", []);
print_board([{_X, Y}|T]) ->
    Line = [string:copies(". ", Y - 1), "@ ", string:copies(". ", 8 - Y)],
    io:format("~s~n", [Line]),
    print_board(T).
solve(X, Taken) when X > 8 ->
    io:format("~p~n", [Taken]),
    print_board(Taken);
solve(X, Taken) ->
    L = [{X, Y} || Y <- lists:seq(1, 8), not under_attack({X, Y}, Taken)],
    row(L, Taken).
row([], _) -> [];
row([{X, Y}|L], Taken) ->
    solve(X + 1, [{X, Y} | Taken]),
    row(L, Taken).
under_attack(_, []) -> false;
under_attack({X, Y}, [{Xt, Yt}|L]) ->
    Y == Yt orelse abs(Y - Yt) == abs(X - Xt) orelse
    under_attack({X, Y}, L).
Вся работа со списками вручную без циклоподобных конструкций.
Печатает типа такого:
[4,7,5,2,6,1,3,8] . . . @ . . . . . . . . . . @ . . . . . @ . . . . @ . . . . . . . . . . . @ . . @ . . . . . . . . . @ . . . . . . . . . . . . @ [5,7,2,6,3,1,4,8] . . . . @ . . . . . . . . . @ . . @ . . . . . . . . . . . @ . . . . @ . . . . . @ . . . . . . . . . . @ . . . . . . . . . . . @ ...
Увы, но вот эта версия мне кажется более красивой с точки зрения фукнционального стиля.
На всякий случай Makefile для обоих вариантов:
target = queens
all:
    erlc $(target).erl
    erl -noshell -s $(target) solve -s init stop
classic:
    erlc $(target)_classic.erl
    erl -noshell -s $(target)_classic solve -s init stop
clean:
    -rm *.beam *.dump
 
 
 
 
 Сообщения
Сообщения
 
 
Комментариев нет:
Отправить комментарий