Commit | Line | Data |
---|---|---|
982ec720 | 1 | -module(life_time). |
d2a0e2f9 SK |
2 | -behaviour(gen_server). |
3 | ||
4 | ||
5 | %% API | |
6 | -export([start_link/2 | |
172421cb | 7 | ,tock/2 |
d2a0e2f9 SK |
8 | ]). |
9 | ||
10 | %% Callbacks | |
11 | -export([init/1 | |
12 | ,handle_call/3 | |
13 | ,handle_cast/2 | |
14 | ,handle_info/2 | |
15 | ,terminate/2 | |
16 | ,code_change/3 | |
17 | ]). | |
18 | ||
19 | ||
81dbcc6e | 20 | -define(INTERVAL, 100). % In milliseconds |
d2a0e2f9 SK |
21 | |
22 | -define(CHAR_DEAD, 32). % Space | |
23 | -define(CHAR_ALIVE, 111). % o | |
24 | -define(CHAR_BAR, 61). % = | |
25 | ||
26 | ||
27 | -record(state, {x :: integer() | |
28 | ,cells :: list(atom()) | |
29 | ,num_cells :: integer() | |
30 | ,state_pairs :: list(tuple(integer(), integer())) | [] | |
31 | ,replies_pending :: integer() | |
f7349482 | 32 | ,gen_count = 0 :: integer() |
d2a0e2f9 SK |
33 | }). |
34 | ||
35 | ||
36 | %% ============================================================================ | |
37 | %% API | |
38 | %% ============================================================================ | |
39 | ||
40 | start_link(X, Cells) -> | |
41 | ServerName = {local, ?MODULE}, | |
42 | Args = [X, Cells], | |
43 | Opts = [], | |
44 | gen_server:start_link(ServerName, ?MODULE, Args, Opts). | |
45 | ||
46 | ||
172421cb SK |
47 | tock(CellID, CellState) -> |
48 | gen_server:cast(?MODULE, {tock, {CellID, CellState}}). | |
d2a0e2f9 SK |
49 | |
50 | ||
51 | %% ============================================================================ | |
52 | %% Callbacks | |
53 | %% ============================================================================ | |
54 | ||
55 | init([X, Cells]) -> | |
56 | State = #state{x=X | |
57 | ,cells=Cells | |
58 | ,num_cells=length(Cells) | |
59 | ,state_pairs=[] | |
60 | ,replies_pending=0 | |
61 | }, | |
172421cb | 62 | schedule_next_tick(), |
d2a0e2f9 SK |
63 | {ok, State}. |
64 | ||
65 | ||
66 | terminate(_Reason, State) -> | |
67 | {ok, State}. | |
68 | ||
69 | ||
70 | code_change(_Old, State, _Other) -> | |
71 | {ok, State}. | |
72 | ||
73 | ||
74 | handle_call(_Msg, _From, State) -> | |
75 | {reply, ok, State}. | |
76 | ||
77 | ||
172421cb SK |
78 | handle_cast(next_tick, |
79 | #state{cells=Cells | |
80 | ,num_cells=NumCells | |
81 | ,state_pairs=[] | |
82 | }=State) -> | |
83 | ||
84 | ok = cast_all(Cells, tick), | |
d2a0e2f9 SK |
85 | {noreply, State#state{replies_pending=NumCells}}; |
86 | ||
87 | handle_cast({tock, {ID, CellState}}, | |
88 | #state{x=X | |
89 | ,state_pairs=StatePairs | |
90 | ,replies_pending=RepliesPending | |
f7349482 | 91 | ,gen_count=GenCount |
812a14ea | 92 | ,num_cells=NumCells |
d2a0e2f9 SK |
93 | }=State) -> |
94 | ||
95 | NewStatePairs = [{ID, CellState} | StatePairs], | |
96 | NewRepliesPending = RepliesPending - 1, | |
97 | NewState = State#state{replies_pending=NewRepliesPending}, | |
98 | ||
99 | case NewRepliesPending of | |
100 | 0 -> | |
f7349482 | 101 | NewGenCount = GenCount + 1, |
d2a0e2f9 SK |
102 | SortedStatePairs = lists:sort(NewStatePairs), |
103 | StateChars = [state_to_char(S) || {_, S} <- SortedStatePairs], | |
104 | ok = do_print_bar(X), | |
812a14ea SK |
105 | ok = io:format( |
106 | "CELLS: ~b GENERATIONS: ~b~n", | |
107 | [NumCells, NewGenCount] | |
108 | ), | |
f7349482 | 109 | ok = do_print_bar(X), |
d2a0e2f9 SK |
110 | ok = do_print_state_chars(X, StateChars), |
111 | ok = do_print_bar(X), | |
112 | ok = timer:sleep(?INTERVAL), | |
172421cb | 113 | schedule_next_tick(), |
f7349482 | 114 | {noreply, NewState#state{state_pairs=[], gen_count=NewGenCount}}; |
d2a0e2f9 SK |
115 | |
116 | _N -> | |
117 | {noreply, NewState#state{state_pairs=NewStatePairs}} | |
118 | end; | |
119 | ||
120 | handle_cast(_Msg, State) -> | |
121 | {noreply, State}. | |
122 | ||
123 | ||
124 | handle_info(_Msg, State) -> | |
125 | {noreply, State}. | |
126 | ||
127 | ||
128 | %% ============================================================================ | |
129 | %% Internal | |
130 | %% ============================================================================ | |
131 | ||
172421cb SK |
132 | schedule_next_tick() -> |
133 | gen_server:cast(?MODULE, next_tick). | |
134 | ||
135 | ||
136 | cast_all([], _) -> ok; | |
137 | cast_all([Server | Servers], Msg) -> | |
138 | ok = gen_server:cast(Server, Msg), | |
139 | cast_all(Servers, Msg). | |
d2a0e2f9 SK |
140 | |
141 | ||
142 | state_to_char(0) -> ?CHAR_DEAD; | |
143 | state_to_char(1) -> ?CHAR_ALIVE. | |
144 | ||
145 | ||
146 | do_print_state_chars(_, []) -> ok; | |
147 | do_print_state_chars(X, Chars) -> | |
148 | {XChars, RestChars} = lists:split(X, Chars), | |
149 | ok = io:format([XChars, $\n]), | |
150 | do_print_state_chars(X, RestChars). | |
151 | ||
152 | ||
153 | do_print_bar(X) -> | |
154 | io:format("~s~n", [[?CHAR_BAR || _ <- lists:seq(1, X - 1)]]). |