Skip to content

Instantly share code, notes, and snippets.

@eitoball
Created December 26, 2019 12:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eitoball/5d4ef25386a8e5c1aa0d0386ac7955b0 to your computer and use it in GitHub Desktop.
Save eitoball/5d4ef25386a8e5c1aa0d0386ac7955b0 to your computer and use it in GitHub Desktop.
defmodule Lifegame do
@size 5
def publish_status(_, _, []), do: :ok
def publish_status(step, status, [node|rest]) do
send(node, {status, step, status})
publish_status(step, status, rest)
end
def count_livings(_, 0, count), do: count
def count_livings(step, n, count) do
receive do
{status, ^step, status} ->
cond do
status ->
count_livings(step, n - 1, count + 1)
true ->
count_livings(step, n - 1, count)
end
end
end
def count_livings(step, neighbors),
do: count_livings(step, length(neighbors), 0)
def next_status(_, 3), do: true
def next_status(true, 2), do: true
def next_status(_, _), do: false
def cell(board, step, pos, status, neighbors) do
send(board, {step, pos, status})
publish_status(step, status, neighbors)
next_status = next_status(status, count_livings(step, neighbors))
cell(board, step + 1, pos, next_status, neighbors)
end
def generate_cell(board, {x, y} = pos) do
receive do
{:add_neighbors, cells} ->
neighbors = :lists.filtermap(fn ({{x2, y2}, cell}) ->
cond do
x == x2 && y == y2 ->
false
abs(x - x2) <= 1 && abs(y - y2) <= 1 ->
{true, cell}
true ->
false
end
end, cells)
status = :rand.uniform() >= 0.5
cell(board, 1, pos, status, neighbors)
end
end
def generate_cells(_, cells, {0, _}) do
:lists.foreach(fn ({_, cell}) -> send(cell, {:add_neighbors, cells}) end, cells)
end
def generate_cells(board, cells, {x, 0}),
do: generate_cells(board, cells, {x - 1, @size})
def generate_cells(board, cells, {x, y} = pos),
do: generate_cells(board, [{pos, spawn(fn -> generate_cell(board, pos) end)} | cells], {x, y - 1})
def generate_cells(board),
do: generate_cells(board, [], {@size, @size})
def aggregate_board(_, {0, _}, _, board), do: board
def aggregate_board(step, {x, 0}, col, board),
do: aggregate_board(step, {x - 1, @size}, [], [col|board])
def aggregate_board(step, {x, y}, col, board) do
receive do
{^step, {^x, ^y}, status} ->
aggregate_board(step, {x, y - 1}, [status|col], board)
end
end
def aggregate_board(step), do: aggregate_board(step, {@size, @size}, [], [])
def print_column([]), do: :io.nl()
def print_column([true|rest]) do
:io.format("*")
print_column(rest)
end
def print_column([false|rest]) do
:io.format(".")
print_column(rest)
end
def print_board([]), do: :ok
def print_board([col|cols]) do
print_column(col)
print_board(cols)
end
def print_separator(step), do: :io.format("==~B==~n", [step])
def board(step, before_board, pid) do
board = aggregate_board(step)
cond do
before_board == board ->
send pid, {:ok}
true ->
print_separator(step)
print_board(board)
board(step + 1, board, pid)
end
end
def generate_board(pid) do
board = spawn(fn -> board(1, :empty, pid) end)
generate_cells(board)
end
def main do
generate_board(self())
receive do
{:ok} ->
:return
end
end
end
Lifegame.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment