Commit | Line | Data |
---|---|---|
d2a0e2f9 SK |
1 | -module(cell). |
2 | -behaviour(gen_server). | |
3 | ||
4 | ||
5 | %% API | |
6 | -export([start_link/1]). | |
7 | ||
8 | %% Callbacks | |
9 | -export([init/1 | |
10 | ,handle_call/3 | |
11 | ,handle_cast/2 | |
12 | ,handle_info/2 | |
13 | ,terminate/2 | |
14 | ,code_change/3 | |
15 | ]). | |
16 | ||
17 | ||
18 | -record(state, {id :: integer() | |
19 | ,name :: string() | |
20 | ,cell_state :: 0 | 1 | |
21 | ,neighbors :: list(atom()) | |
22 | ,live_neighbors :: integer() | |
23 | ,num_neighbors :: integer() | |
24 | ,replies_pending :: integer() | |
25 | }). | |
26 | ||
27 | ||
28 | %% ============================================================================ | |
29 | %% API | |
30 | %% ============================================================================ | |
31 | ||
32 | start_link({_ID, Name, _NeighborNames}=Datum) -> | |
33 | ServerName = {local, Name}, | |
34 | Args = [Datum], | |
35 | Opts = [], | |
36 | gen_server:start_link(ServerName, ?MODULE, Args, Opts). | |
37 | ||
38 | ||
39 | %% ============================================================================ | |
40 | %% Callbacks | |
41 | %% ============================================================================ | |
42 | ||
43 | init([{ID, Name, NeighborNames}]) -> | |
44 | State = #state{id=ID | |
45 | ,name=Name | |
46 | ,cell_state=crypto:rand_uniform(0, 2) | |
47 | ,neighbors=NeighborNames | |
48 | ,num_neighbors=length(NeighborNames) | |
49 | ,live_neighbors=0 | |
50 | ,replies_pending=0 | |
51 | }, | |
52 | {ok, State}. | |
53 | ||
54 | ||
55 | terminate(_Reason, State) -> | |
56 | {ok, State}. | |
57 | ||
58 | ||
59 | code_change(_Old, State, _Other) -> | |
60 | {ok, State}. | |
61 | ||
62 | ||
63 | handle_call(_Msg, _From, State) -> | |
64 | {reply, ok, State}. | |
65 | ||
66 | ||
172421cb | 67 | handle_cast(tick, |
d2a0e2f9 SK |
68 | #state{name=Name |
69 | ,neighbors=Neighbors | |
70 | ,num_neighbors=NumNeighbors | |
71 | }=State) -> | |
172421cb | 72 | ok = cast_all(Neighbors, {request_state, Name}), |
d2a0e2f9 SK |
73 | {noreply, State#state{replies_pending=NumNeighbors}}; |
74 | ||
75 | ||
172421cb SK |
76 | handle_cast({request_state, Requester}, State) -> |
77 | ok = gen_server:cast(Requester, {response_state, State#state.cell_state}), | |
d2a0e2f9 SK |
78 | {noreply, State}; |
79 | ||
80 | ||
172421cb | 81 | handle_cast({response_state, NeighborState}, |
d2a0e2f9 SK |
82 | #state{id=ID |
83 | ,replies_pending=Pending | |
84 | ,cell_state=CellState | |
85 | ,live_neighbors=LiveNeighbors | |
86 | }=State) -> | |
87 | ||
88 | NewPending = Pending - 1, | |
89 | NewLiveNeighbors = LiveNeighbors + NeighborState, | |
90 | ||
91 | NewState = State#state{replies_pending=NewPending | |
92 | ,live_neighbors=NewLiveNeighbors | |
93 | }, | |
94 | ||
95 | case NewPending of | |
96 | 0 -> | |
97 | NewCellState = new_state(CellState, NewLiveNeighbors), | |
172421cb | 98 | ok = time:tock(ID, NewCellState), |
d2a0e2f9 SK |
99 | |
100 | {noreply, NewState#state{live_neighbors=0 | |
101 | ,cell_state=NewCellState | |
172421cb SK |
102 | } |
103 | }; | |
d2a0e2f9 SK |
104 | |
105 | _N -> | |
106 | {noreply, NewState} | |
107 | end; | |
108 | ||
172421cb SK |
109 | |
110 | handle_cast(_Msg, State) -> | |
111 | {noreply, State}. | |
d2a0e2f9 SK |
112 | |
113 | ||
114 | handle_info(_Msg, State) -> | |
115 | {noreply, State}. | |
116 | ||
117 | ||
118 | %% ============================================================================ | |
119 | %% Internal | |
120 | %% ============================================================================ | |
121 | ||
172421cb SK |
122 | cast_all([], _) -> ok; |
123 | cast_all([Server | Servers], Msg) -> | |
124 | ok = gen_server:cast(Server, Msg), | |
125 | cast_all(Servers, Msg). | |
d2a0e2f9 SK |
126 | |
127 | ||
128 | new_state(1, LiveNeighbors) when LiveNeighbors < 2 -> 0; | |
129 | new_state(1, LiveNeighbors) when LiveNeighbors < 4 -> 1; | |
130 | new_state(1, LiveNeighbors) when LiveNeighbors > 3 -> 0; | |
131 | new_state(0, LiveNeighbors) when LiveNeighbors =:= 3 -> 1; | |
132 | new_state(State, _LiveNeighbors) -> State. |