| 1 | -module(life). |
| 2 | -behaviour(application). |
| 3 | |
| 4 | |
| 5 | %% API |
| 6 | -export([bang/0]). |
| 7 | |
| 8 | %% Callbacks |
| 9 | -export([start/2, stop/1]). |
| 10 | |
| 11 | |
| 12 | -define(DIRECTIONS, ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW']). |
| 13 | |
| 14 | |
| 15 | %% ============================================================================ |
| 16 | %% API |
| 17 | %% ============================================================================ |
| 18 | |
| 19 | bang() -> |
| 20 | application:start(?MODULE). |
| 21 | |
| 22 | |
| 23 | %% ============================================================================ |
| 24 | %% Callbacks |
| 25 | %% ============================================================================ |
| 26 | |
| 27 | start(_StartType, _StartArgs) -> |
| 28 | {ok, X} = application:get_env(?MODULE, x), |
| 29 | {ok, Y} = application:get_env(?MODULE, y), |
| 30 | CellData = cell_data(X, Y), |
| 31 | life_god:start_link(X, Y, CellData). |
| 32 | |
| 33 | |
| 34 | stop(_State) -> |
| 35 | ok. |
| 36 | |
| 37 | |
| 38 | %% ============================================================================ |
| 39 | %% Internal |
| 40 | %% ============================================================================ |
| 41 | |
| 42 | cell_data(X, Y) -> |
| 43 | N = X * Y, |
| 44 | [cell_datum(X, N, ID) || ID <- lists:seq(1, N)]. |
| 45 | |
| 46 | |
| 47 | cell_datum(X, N, ID) -> |
| 48 | Name = integer_to_atom(ID), |
| 49 | NeighborNames = filter_offsides(N, |
| 50 | [integer_to_atom(neighbor_id(Dir, X, ID)) || Dir <- ?DIRECTIONS] |
| 51 | ), |
| 52 | {ID, Name, NeighborNames}. |
| 53 | |
| 54 | |
| 55 | neighbor_id(Direction, X, ID) -> ID + offset(Direction, X). |
| 56 | |
| 57 | |
| 58 | offset('N' , X) -> ensure_negative(X); |
| 59 | offset('NE', X) -> ensure_negative(X - 1); |
| 60 | offset('E' , _) -> 1; |
| 61 | offset('SE', X) -> X + 1; |
| 62 | offset('S' , X) -> X; |
| 63 | offset('SW', X) -> X - 1; |
| 64 | offset('W' , _) -> ensure_negative( 1); |
| 65 | offset('NW', X) -> ensure_negative(X + 1). |
| 66 | |
| 67 | |
| 68 | ensure_negative(N) when N < 0 -> N; |
| 69 | ensure_negative(N) -> -(N). |
| 70 | |
| 71 | |
| 72 | filter_offsides(N, IDs) -> |
| 73 | [ID || ID <- IDs, is_onside(N, atom_to_integer(ID))]. |
| 74 | |
| 75 | |
| 76 | is_onside(_, ID) when ID < 1 -> false; |
| 77 | is_onside(N, ID) when ID > N -> false; |
| 78 | is_onside(_, _) -> true. |
| 79 | |
| 80 | |
| 81 | atom_to_integer(Atom) -> |
| 82 | list_to_integer(atom_to_list(Atom)). |
| 83 | |
| 84 | |
| 85 | integer_to_atom(Integer) -> |
| 86 | list_to_atom(integer_to_list(Integer)). |