-module(conway). -export([mochiweb_request/1, start/1, handle_request/2]). start(PortString) -> %{Port, _} = string:to_integer(PortString), Port = 3001, mochiweb_http:start([{port, Port}, {loop, {?MODULE, mochiweb_request}}]), receive stop -> stop end. % http://www.trapexit.org/String_join_with string_join(Items, Sep) -> lists:flatten(lists:reverse(string_join1(Items, Sep, []))). string_join1([Head | []], _Sep, Acc) -> [Head | Acc]; string_join1([Head | Tail], Sep, Acc) -> string_join1(Tail, Sep, [Sep, Head | Acc]). random_matrix(XSize, YSize) -> array:from_list([random:uniform(2)-1 || _ <- lists:seq(1, XSize*YSize)]). neighbor_count(CellPos, Matrix, SX, SY) -> X = CellPos rem SX, Y = erlang:trunc(CellPos/SX), % http://ejohn.org/apps/processing.js/examples/topics/conway.html lists:sum( [ array:get((X + 1) rem SX + (Y)*SX, Matrix), array:get((X) + ((Y + 1) rem SY)*SX, Matrix), array:get((X + SX - 1) rem SX + (Y)*SX, Matrix), array:get((X) + ((Y + SY - 1) rem SY)*SX, Matrix), array:get((X + 1) rem SX + ((Y + 1) rem SY)*SX, Matrix), array:get((X + SX - 1) rem SX + ((Y + 1) rem SY)*SX, Matrix), array:get((X + SX - 1) rem SX + ((Y + SY - 1) rem SY)*SX, Matrix), array:get((X + 1) rem SX + ((Y + SY - 1) rem SY)*SX, Matrix) ]). cell_status(2, S) -> S; cell_status(3, _) -> 1; cell_status(_, _) -> 0. next_cell(CellPos, CellState, Matrix, SX, SY) -> Neighbors = neighbor_count(CellPos, Matrix, SX, SY), cell_status(Neighbors, CellState). next_iteration(Matrix, SX, SY) -> array:map(fun (N, Z) -> next_cell(N, Z, Matrix, SX, SY) end, Matrix). state_to_symbol(0) -> " "; state_to_symbol(1) -> "#"; state_to_symbol(2) -> " \n"; state_to_symbol(3) -> "#\n". handle_request(Req, Path) -> SX = 80, % size x of conway grid SY = 40, % size y of conway grid case Path of "/_reset" -> Matrix = random_matrix(SX, SY), put(matrix, Matrix), Req:ok({"text/plain", "Reset OK."}); _ -> OldMatrix = get(matrix), Matrix = case OldMatrix of undefined -> random_matrix(SX, SY); _ -> next_iteration(OldMatrix, SX, SY) end, put(matrix, Matrix), % print newlines when we're at a right-edge PrettyGrid = array:to_list(array:map( fun (N, Cell) when N rem SX == 0, N =/= 0 -> state_to_symbol(Cell+2); (N, Cell) -> state_to_symbol(Cell) end, Matrix) ), Req:ok({"text/plain", PrettyGrid ++ "\n"}) end. mochiweb_request(Req) -> {Path, _, _} = mochiweb_util:urlsplit_path(Req:get(raw_path)), handle_request(Req, Path).