Commit | Line | Data |
---|---|---|
d2a0e2f9 SK |
1 | -module(time). |
2 | -behaviour(gen_server). | |
3 | ||
4 | ||
5 | %% API | |
6 | -export([start_link/2 | |
7 | ,cast/1 | |
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 | ||
47 | cast(Msg) -> | |
48 | gen_server:cast(?MODULE, Msg). | |
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 | }, | |
62 | cast(next_tick), | |
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 | ||
78 | handle_cast(next_tick, #state{cells=Cells, num_cells=NumCells, state_pairs=[]}=State) -> | |
79 | ok = send_all(Cells, tick), | |
80 | {noreply, State#state{replies_pending=NumCells}}; | |
81 | ||
82 | handle_cast({tock, {ID, CellState}}, | |
83 | #state{x=X | |
84 | ,state_pairs=StatePairs | |
85 | ,replies_pending=RepliesPending | |
f7349482 | 86 | ,gen_count=GenCount |
d2a0e2f9 SK |
87 | }=State) -> |
88 | ||
89 | NewStatePairs = [{ID, CellState} | StatePairs], | |
90 | NewRepliesPending = RepliesPending - 1, | |
91 | NewState = State#state{replies_pending=NewRepliesPending}, | |
92 | ||
93 | case NewRepliesPending of | |
94 | 0 -> | |
f7349482 | 95 | NewGenCount = GenCount + 1, |
d2a0e2f9 SK |
96 | SortedStatePairs = lists:sort(NewStatePairs), |
97 | StateChars = [state_to_char(S) || {_, S} <- SortedStatePairs], | |
98 | ok = do_print_bar(X), | |
f7349482 SK |
99 | ok = io:format("GENERATIONS: ~b~n", [NewGenCount]), |
100 | ok = do_print_bar(X), | |
d2a0e2f9 SK |
101 | ok = do_print_state_chars(X, StateChars), |
102 | ok = do_print_bar(X), | |
103 | ok = timer:sleep(?INTERVAL), | |
104 | cast(next_tick), | |
f7349482 | 105 | {noreply, NewState#state{state_pairs=[], gen_count=NewGenCount}}; |
d2a0e2f9 SK |
106 | |
107 | _N -> | |
108 | {noreply, NewState#state{state_pairs=NewStatePairs}} | |
109 | end; | |
110 | ||
111 | handle_cast(_Msg, State) -> | |
112 | {noreply, State}. | |
113 | ||
114 | ||
115 | handle_info(_Msg, State) -> | |
116 | {noreply, State}. | |
117 | ||
118 | ||
119 | %% ============================================================================ | |
120 | %% Internal | |
121 | %% ============================================================================ | |
122 | ||
123 | send_all([], _) -> ok; | |
124 | send_all([PID | PIDs], Msg) -> | |
125 | PID ! Msg, | |
126 | send_all(PIDs, Msg). | |
127 | ||
128 | ||
129 | state_to_char(0) -> ?CHAR_DEAD; | |
130 | state_to_char(1) -> ?CHAR_ALIVE. | |
131 | ||
132 | ||
133 | do_print_state_chars(_, []) -> ok; | |
134 | do_print_state_chars(X, Chars) -> | |
135 | {XChars, RestChars} = lists:split(X, Chars), | |
136 | ok = io:format([XChars, $\n]), | |
137 | do_print_state_chars(X, RestChars). | |
138 | ||
139 | ||
140 | do_print_bar(X) -> | |
141 | io:format("~s~n", [[?CHAR_BAR || _ <- lists:seq(1, X - 1)]]). |