Setting process limit to no more than necessary.
[cellular-automata.git] / 003 / src / life.erl
CommitLineData
7f968603
SK
1-module(life).
2
3-export([bang/1]).
4
5
6-define(CHAR_DEAD, 32). % " "
7-define(CHAR_ALIVE, 111). % "o"
8-define(INTERVAL, 100).
9
10
11%% ============================================================================
12%% API
13%% ============================================================================
14
15bang(Args) ->
16 [X, Y] = [atom_to_integer(A) || A <- Args],
17 Board = init_board(X, Y),
68194920 18 life_loop(X, Y, Board).
7f968603
SK
19
20
21%% ============================================================================
22%% Internal
23%% ============================================================================
24
68194920 25life_loop(X, Y, Board) ->
7f968603
SK
26 ok = do_print_board(Board),
27 timer:sleep(?INTERVAL),
68194920 28 life_loop(X, Y, next_generation(X, Y, Board)).
7f968603
SK
29
30
31do_print_board(Board) ->
32 CharLists = array:to_list(
33 array:map(
34 fun(_, Row) ->
35 array:to_list(
36 array:map(
37 fun(_, State) ->
38 state_to_char(State)
39 end,
40 Row
41 )
42 )
43 end,
44 Board
45 )
46 ),
47
48 ok = lists:foreach(
49 fun(CharList) ->
50 ok = io:format("~s~n", [CharList])
51 end,
52 CharLists
53 ).
54
55
56state_to_char(0) -> ?CHAR_DEAD;
57state_to_char(1) -> ?CHAR_ALIVE.
58
59
68194920 60next_generation(W, H, Board) ->
7f968603
SK
61 array:map(
62 fun(Y, Row) ->
63 array:map(
64 fun(X, State) ->
65 Neighbors = filter_offsides(H, W, neighbors(X, Y)),
66 States = neighbor_states(Board, Neighbors),
67 LiveNeighbors = lists:sum(States),
68 new_state(State, LiveNeighbors)
69 end,
70 Row
71 )
72 end,
73 Board
74 ).
75
76
77new_state(1, LiveNeighbors) when LiveNeighbors < 2 -> 0;
78new_state(1, LiveNeighbors) when LiveNeighbors < 4 -> 1;
79new_state(1, LiveNeighbors) when LiveNeighbors > 3 -> 0;
80new_state(0, LiveNeighbors) when LiveNeighbors =:= 3 -> 1;
81new_state(State, _LiveNeighbors) -> State.
82
83
84neighbor_states(Board, Neighbors) ->
85 [array:get(X, array:get(Y, Board)) || {X, Y} <- Neighbors].
86
87
88filter_offsides(H, W, Coordinates) ->
89 [{X, Y} || {X, Y} <- Coordinates, is_onside(X, Y, H, W)].
90
91
92is_onside(X, Y, H, W) when (X >= 0) and (Y >= 0) and (X < W) and (Y < H) -> true;
93is_onside(_, _, _, _) -> false.
94
95
96neighbors(X, Y) ->
97 [{X + OffX, Y + OffY} || {OffX, OffY} <- offsets()].
98
99
100offsets() ->
101 [offset(D) || D <- directions()].
102
103
104offset('N') -> { 0, -1};
105offset('NE') -> { 1, -1};
106offset('E') -> { 1, 0};
107offset('SE') -> { 1, 1};
108offset('S') -> { 0, 1};
109offset('SW') -> {-1, 1};
110offset('W') -> {-1, 0};
111offset('NW') -> {-1, -1}.
112
113
114directions() ->
115 ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'].
116
117
118init_board(X, Y) ->
119 array:map(fun(_, _) -> init_row(X) end, array:new(Y)).
120
121
122init_row(X) ->
123 array:map(fun(_, _) -> init_cell_state() end, array:new(X)).
124
125
126init_cell_state() ->
127 crypto:rand_uniform(0, 2).
128
129
130atom_to_integer(Atom) ->
131 list_to_integer(atom_to_list(Atom)).
This page took 0.029605 seconds and 4 git commands to generate.