Commit | Line | Data |
---|---|---|
d2a0e2f9 SK |
1 | -module(time). |
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 | ||
20 | -define(INTERVAL, 0). % In milliseconds | |
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 |
d2a0e2f9 SK |
92 | }=State) -> |
93 | ||
94 | NewStatePairs = [{ID, CellState} | StatePairs], | |
95 | NewRepliesPending = RepliesPending - 1, | |
96 | NewState = State#state{replies_pending=NewRepliesPending}, | |
97 | ||
98 | case NewRepliesPending of | |
99 | 0 -> | |
f7349482 | 100 | NewGenCount = GenCount + 1, |
d2a0e2f9 SK |
101 | SortedStatePairs = lists:sort(NewStatePairs), |
102 | StateChars = [state_to_char(S) || {_, S} <- SortedStatePairs], | |
103 | ok = do_print_bar(X), | |
f7349482 SK |
104 | ok = io:format("GENERATIONS: ~b~n", [NewGenCount]), |
105 | ok = do_print_bar(X), | |
d2a0e2f9 SK |
106 | ok = do_print_state_chars(X, StateChars), |
107 | ok = do_print_bar(X), | |
108 | ok = timer:sleep(?INTERVAL), | |
172421cb | 109 | schedule_next_tick(), |
f7349482 | 110 | {noreply, NewState#state{state_pairs=[], gen_count=NewGenCount}}; |
d2a0e2f9 SK |
111 | |
112 | _N -> | |
113 | {noreply, NewState#state{state_pairs=NewStatePairs}} | |
114 | end; | |
115 | ||
116 | handle_cast(_Msg, State) -> | |
117 | {noreply, State}. | |
118 | ||
119 | ||
120 | handle_info(_Msg, State) -> | |
121 | {noreply, State}. | |
122 | ||
123 | ||
124 | %% ============================================================================ | |
125 | %% Internal | |
126 | %% ============================================================================ | |
127 | ||
172421cb SK |
128 | schedule_next_tick() -> |
129 | gen_server:cast(?MODULE, next_tick). | |
130 | ||
131 | ||
132 | cast_all([], _) -> ok; | |
133 | cast_all([Server | Servers], Msg) -> | |
134 | ok = gen_server:cast(Server, Msg), | |
135 | cast_all(Servers, Msg). | |
d2a0e2f9 SK |
136 | |
137 | ||
138 | state_to_char(0) -> ?CHAR_DEAD; | |
139 | state_to_char(1) -> ?CHAR_ALIVE. | |
140 | ||
141 | ||
142 | do_print_state_chars(_, []) -> ok; | |
143 | do_print_state_chars(X, Chars) -> | |
144 | {XChars, RestChars} = lists:split(X, Chars), | |
145 | ok = io:format([XChars, $\n]), | |
146 | do_print_state_chars(X, RestChars). | |
147 | ||
148 | ||
149 | do_print_bar(X) -> | |
150 | io:format("~s~n", [[?CHAR_BAR || _ <- lists:seq(1, X - 1)]]). |