Binary numbers toy in Erlang GS graphics

Because of popular demand, I have ported the previous example to Erlang using it's built-in GS package. Enjoy! :-D



All code and text in this post is Copyright (c) bkil.hu [also known as bkil], 2009; and is licensed under the GNU GPL v2. Refer to the standard license texts from June 1991 for exact conditions. Here is an example link: http://www.gnu.org/licenses/gpl-2.0.html





Here's the core (simbins.erl):
-module(simbins).
-export([radix/3, binaries/2, simbins/1]).

%% Radix conversion with LSB output.
radix(_,0,_) -> [];
radix(R,W,N) -> [N rem R | radix(R, (W-1), (N div R))].

%% A full-matrix transpose stub.
transpose([H|T]) when is_list(H) ->
Append = fun(V, M) -> lists:zipwith(fun(E,L) -> [E|L] end, V, M) end,
Vector = fun(L) -> lists:map(fun(E) -> [E] end, L) end,
[RH|RT] = lists:reverse([H|T]),
lists:foldl(Append, Vector(RH), RT).

%% 'binaries' is a solution to Paul R. Potts's idea.
%% Prepend `lists:reverse( ` to get MSB.
binaries(W,L) -> transpose( lists:map( fun(N)->radix(2,W,N) end, L ) ).

%% A lame math power function, but at least it's short.
pow(_,0) -> 1;
pow(R,N) when N>0 -> R * pow(R,N-1).

simbins(W) ->
Cols = binaries(W, lists:seq(0, pow(2,W)-1) ),
Dbl = lists:map(fun(S) -> S ++ lists:reverse(S) end, Cols),
lists:reverse(Dbl) ++ Dbl.




Standard output text interface (textbin.erl):
-module(textbin).
-export([start/0]).
-import(simbins).

unlines(L) ->
Strings = lists:map(fun(S)-> S ++ "\n" end, L),
lists:append( Strings ).

toChar(0) -> $ ;
toChar(_) -> $@.

toChars(S) -> lists:map(fun toChar/1, S).

textOut(L) ->
Strings = lists:map(fun toChars/1, L),
io:format( unlines( Strings ) ).

start() -> textOut( simbins:simbins(5) ).




Graphics interface (graphbin.erl):
-module(graphbin).
-export([start/0]).
-import(simbins).

catMaybes([H|T]) when is_list(H) -> lists:append([H|T]).

put(Canvas, W, H) ->
fun({X,Y}) ->
X0 = W*X, X1 = W*(X+1),
Y0 = H*Y, Y1 = H*(Y+1),
gs:rectangle( Canvas, [ {bw,0}, {fill, white},
{coords, [{X0,Y0}, {X1,Y1}]} ]) end.

visDots([H|T]) ->
LH = lists:seq(0,length(H)-1),
LT = lists:seq(0,length(T)),
Elem = fun(Y) -> fun(_,0) -> [];
(X,_) -> [{X,Y}] end end,
Rows = fun(Y,Col) -> lists:zipwith(Elem(Y), LH, Col) end,
Dots = lists:zipwith(Rows, LT, [H|T]),
catMaybes( lists:append(Dots) ).

graphOut(DW, DH, [H|T]) ->
WinSize = [{width,DW*length(H)}, {height,DH*length([H|T])}],
Win = gs:window(gs:start(), WinSize ++
[ {title,"Simbins"}, {keypress,true} ]),
Canvas = gs:canvas( Win, WinSize ++ [{bg, black}] ),
lists:foreach( put(Canvas, DW, DH), visDots([H|T]) ),
gs:config(Win, {map,true}),
case getKey() of
cancel -> cancel;
_ -> gs:destroy(Win)
end.

getKey() ->
receive
{gs, _, destroy, _, _ } -> cancel;
{gs, _, keypress, _, Args} -> Args
end.

start() -> graphOut( 2, 4, simbins:simbins(6) ).

Comments

  1. I see you are really keen on functional programming. It's okay.
    But now I am publishing this just for telling you about something else. Did you know that your blog site has a comment feed @ http://bkil.blogspot.com/feeds/comments/default ? Gee! :O For me it was a surprise. More info: http://isuman.blogspot.com/2008/08/blogger-feeds.html :)

    ReplyDelete
  2. Hey, thanks for the idea! :) I have been planning to install a feed reader for some time now, but it looks like other duties got priority... Well, primarily I wanted to do that to help me in following _your_ blog, but using it on my own one too also sounds reasonable! :-D So now I have added a feeds-reader addon to my mail client (it took hundreds of kilobytes!). XD

    And you bet I'm keen on functional programming ever since I made my first fractals in LOGO some years ago! :-D Come to think of it, that gave me an idea! ;-) Anyway, ever since I've been into these paradigms better nowadays, I seem to have improved tremendously. Not that I'd have characterized myself as someone weak in programming before! ;-) (But frankly, who does? XD) However, you should have seen my latest PIC microcontroller firmware! ;) I have also done a pretty slick (and pure!) little ANSI C m-ary tree toy last year that I plan to upload someday... Though, I have started to grow a habit of developing my C++/STL software in an ever purer way in recent years!

    By the way, at a quick glance, I may not have tagged all of my posts correctly. It looks like some FP stuff gone into the general 'programming' category. I will fix that eventually.

    ReplyDelete
  3. Take two on visDots vs catMaybe:

    visDots([H|T]) ->
        [ {X,Y} || X <- lists:seq(0,length(H)-1),
                   Y <- lists:seq(0,length(T)),
                   0 /= lists:nth(X+1, lists:nth(Y+1, [H|T]) ) ].

    This is a bit more imperative and theoretically more expensive method, but it's a hell lot more conscious! :) Actually this was one of the first solutions that popped into my mind, but I have originally dismissed it as being too inefficient.

    ReplyDelete

Post a Comment

Popular posts from this blog

Tftp secret of TL-WR740N uncovered

Hidden TFTP of TP-Link routers

Haskell for embedded: C output, compilers, monads, Timber