Erlang version
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 16.03.06 11:02
Оценка: 15 (1)
Mamut,

M>Дан рисунок, представленный ASCII кодами (. — белый, # — черный). Задача...

Решение Трурля
Автор: Трурль
Дата: 09.03.06


Да, Хаскель очень красив, выкладывать здесь клон на Эрланге (который по синтаксической красоте находится где-то между C++ и C#) означает вызвать саркастические улыбки. Так что я решил сделать дополнительный шаг.

Шаг к унификации. Можно заметить, что все функции — это трансформеры Picture + Data -> Picture. Data естественно может отсутствовать. В эту стройную картинку не вписывалась только функция bounds/1, так что пришлось взять напильничек и подровнять её, чтобы она вписалась таки

Весь модуль-с
-module(image).
-compile(export_all).
-import(lists, [append/1, duplicate/2, map/2, merge/3, 
    reverse/1, split/2, sublist/3, unzip/1, zip/2, zipwith/3]).

%% Font for bounds/1
%% ### ##  ##  ###   # ###  ## ### ### ###
%% # #  #    #   #  ## #   #   # # # # # #
%% # #  #   #   #  # # ##  ###   #  #  ###
%% # #  #  #     # ###   # # #  #  # #   #
%% ### ### ### ###   # ##  ###  #  ### ## 
-define(Font, {8#75557, 8#62227, 8#61247, 8#71217, 8#13571,
               8#74616, 8#34757, 8#75122, 8#75257, 8#75716}).
-define(Fwidth,  3).
-define(Fheight, 5).

test() ->
    L = [
    "....................",
    ".###...##.###..#..#.",
    ".#..#.#...#..#.##.#.",
    ".###....#.#..#.#.##.",
    ".#..#.##..###..#..#.",
    "...................."
    ],
    Lt = [{id,   L},
        {scale,  L, {1, 2}},
        {bounds, L} ],
    
    Ft =fun (Tr) when is_tuple(Tr) ->
            TrName = element(1, Tr),        
            io:format("~p =>~n~p~n", [TrName, transform(Tr)])
        end,

    map(Ft, Lt), % Go!
    
    ok.

%%% mega transformation function :-)
transform({Transform, Picture}) when is_function(Transform, 1) ->
    Transform(Picture);
transform({Transform, Picture, _Data}) when is_function(Transform, 1) ->
    Transform(Picture);
transform({Transform, Picture, Data}) when is_function(Transform, 2) ->
    Transform(Picture, Data);
transform({Transform, Picture}) when is_atom(Transform) ->
    apply(?MODULE, Transform, [Picture]);
transform({Transform, Picture, Data}) when is_atom(Transform) ->
    apply(?MODULE, Transform, [Picture, Data]).


%%% particular transformations
id(L) -> L.

mv(L) -> map({lists,reverse}, L).

mh(L) -> reverse(L).

mvh(L) -> mv(mh(L)).

transpose([]) ->
    [];
transpose([[] | Tail]) ->
    transpose(Tail);
transpose([[H | T] | Tail]) ->
    {Headz, Tailz} = unzip([{H, T} || [H | T] <- Tail]),
    [[H | Headz] | transpose([T | Tailz])].
    
r90(L) -> mh(transpose(L)).
    
r_90(L) -> transpose(mh(L)).

invert(L) ->
    F = fun ($.) -> $#; ($#) -> $. end,
    map(fun (R)-> [F(X) || X <- R] end, L).

scale(L, {M, N}) ->
    Ds = fun (S) -> duplicate(M, S) end,  % "duplicate string" fun
    Di = fun (X) -> duplicate(N, X) end,  % "duplicate item" fun
    map(fun (S) -> append(map(Di, S)) end, append(map(Ds, L))).

diff(L1, L2) ->
    D = fun (S1, S2) ->
        F = fun ( X,  Y) when X==Y -> $.;
                (_X, _Y)               -> $#
            end,
        zipwith(F, S1, S2)
        end,
    zipwith(D, L1, L2).

%%% make sure that 1 <= X <= X+W <= N; 1 <= Y <= Y+H <= M
crop(L, {Y, X, W, H}) ->
    sublist(
        map(fun (S) -> sublist(S, X, W) end, L),
    Y, H).

%%% bounds
bounds(L) ->
    convert_bounds(tuple_to_list(bounds_y(L))).

%% bounds on Y axis
bounds_y(L) ->
    bounds_y(0, empty, L).

bounds_y(Y, Val, [Hs | Ts]) ->
    bounds_y(Y + 1, bounds_x(1, Y + 1, Val, Hs), Ts);
bounds_y(_Y, Val, []) ->
    Val.

%% bounds on X axis
bounds_x(X, Y, Val, [H | T]) ->
    case {H, Val} of
        {$#, empty}                       -> bounds_x(X + 1, Y, {X,  X,  Y, Y}, T);
        {$#, {X0,_X1,Y0,_Y1}} when X > X0 -> bounds_x(X + 1, Y, {X0, X, Y0, Y}, T);
        {$#, {_X0,X1,Y0,_Y1}}             -> bounds_x(X + 1, Y, {X, X1, Y0, Y}, T);
        _anything_else_                   -> bounds_x(X + 1, Y, Val, T)
    end;    
bounds_x(_X, _Y, Val, []) ->
    Val.

%%% conversion helpers

%% input [Xmin, Xmax, Ymin, Ymax]
convert_bounds([]) ->
    [];
convert_bounds([N]) ->
    convert_int(N);
convert_bounds([Nh | Nt]) ->
    Concat = fun (L1, L2) -> L1 ++ "..." ++ L2 end,
    zipwith(Concat,
        convert_int(Nh), convert_bounds(Nt)).

%% input like 123
convert_int(N) when is_integer(N) ->
    convert_digits(integer_to_list(N)).

%% input like "1234567890"
convert_digits([]) ->
    [];
convert_digits([D]) ->
    convert_char(element(D - $0 + 1, ?Font));
convert_digits([D | Dlist]) ->
    Concat = fun (L1, L2) -> L1 ++ "." ++ L2 end,
    zipwith(Concat,
        convert_char(element(D - $0 + 1, ?Font)),
        convert_digits(Dlist)).

%% input like 6009 (== 8#13571)
convert_char(C) when is_integer(C) ->
    Bins = erlang:integer_to_list(C, 2),
    Align = duplicate(?Fwidth * ?Fheight - length(Bins), $0),
    convert_bins(Align ++ Bins).

%% input like "110010010010111"
convert_bins([]) ->
    [];
convert_bins(Blist) ->
    F = fun ($1) -> $#; (_)->$. end,
    {H, T} = split(?Fwidth, Blist),
    [map(F, H) | convert_bins(T)].


Жирным помечены требуемые функции. А вот результат:
19 > image:test().
id =>
["....................",
 ".###...##.###..#..#.",
 ".#..#.#...#..#.##.#.",
 ".###....#.#..#.#.##.",
 ".#..#.##..###..#..#.",
 "...................."]
scale =>
["........................................",
 "..######......####..######....##....##..",
 "..##....##..##......##....##..####..##..",
 "..######........##..##....##..##..####..",
 "..##....##..####....######....##....##..",
 "........................................"]
bounds =>
["##....##..###...##....###",
 "..#....#..#.#.....#...#..",
 ".#.....#..###....#....##.",
 "#......#....#...#.......#",
 "###...###.##....###...##."]
ok
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.