X-Git-Url: https://git.xandkar.net/?a=blobdiff_plain;f=003%2Fsrc%2Flife.erl;h=605fa95ce873533b2b4d2da920001db536cb531c;hb=917c9b6f1878c44e497d0e8dafc16920ffd8dcaf;hp=ea6b499f59e49f160258fb6f19ad2871b03ded65;hpb=7a9e70eb6700efa601ab5bd975cf4046b6bd3532;p=cellular-automata.git diff --git a/003/src/life.erl b/003/src/life.erl index ea6b499..605fa95 100644 --- a/003/src/life.erl +++ b/003/src/life.erl @@ -7,7 +7,18 @@ -define(CHAR_ALIVE, 111). % "o" -define(CHAR_BAR, 45). % "-" --define(INTERVAL, 100). +-define(GEN_INTERVAL, 100). + + +-record(state, {x :: non_neg_integer() + ,y :: non_neg_integer() + ,n :: pos_integer() + ,bar :: nonempty_string() + ,board :: array() + ,gen_count :: pos_integer() + ,gen_duration :: non_neg_integer() + ,print_time :: non_neg_integer() + }). %% ============================================================================ @@ -17,37 +28,83 @@ bang(Args) -> [X, Y] = [atom_to_integer(A) || A <- Args], {Time, Board} = timer:tc(fun() -> init_board(X, Y) end), - Generation = 1, - life_loop(X, Y, Generation, Time, Board). + State = #state{x = X + ,y = Y + ,n = X * Y + ,bar = [?CHAR_BAR || _ <- lists:seq(1, X)] + ,board = Board + ,gen_count = 1 % Consider inital state to be generation 1 + ,gen_duration = Time + ,print_time = 0 % There was no print time yet + }, + life_loop(State). %% ============================================================================ %% Internal %% ============================================================================ -life_loop(X, Y, Generation, Time, Board) -> - ok = do_print_status(X, Y, Generation, Time), - ok = do_print_board(Board), +life_loop( + #state{x = X + ,y = Y + ,n = N + ,bar = Bar + ,board = Board + ,gen_count = GenCount + ,gen_duration = Time + ,print_time = LastPrintTime + }=State) -> + + {PrintTime, ok} = timer:tc( + fun() -> + do_print_screen(Board, Bar, X, Y, N, GenCount, Time, LastPrintTime) + end + ), + + {NewTime, NewBoard} = timer:tc( + fun() -> + next_generation(X, Y, Board) + end + ), + + NewState = State#state{board = NewBoard + ,gen_count = GenCount + 1 + ,gen_duration = NewTime + ,print_time = PrintTime + }, + + NewTimeMil = NewTime / 1000, + NextGenDelay = at_least_zero(round(?GEN_INTERVAL - NewTimeMil)), + timer:sleep(NextGenDelay), + + life_loop(NewState). + + +at_least_zero(Integer) when Integer >= 0 -> Integer; +at_least_zero(_) -> 0. + - {NextTime, NextBoard} = timer:tc(fun() -> next_generation(X, Y, Board) end), - NextGeneration = Generation + 1, - timer:sleep(?INTERVAL), - life_loop(X, Y, NextGeneration, NextTime, NextBoard). +do_print_screen(Board, Bar, X, Y, N, GenCount, Time, PrintTime) -> + ok = do_print_status(Bar, X, Y, N, GenCount, Time, PrintTime), + ok = do_print_board(Board). -do_print_status(X, Y, Generation, TimeMic) -> +do_print_status(Bar, X, Y, N, GenCount, TimeMic, PrintTimeMic) -> TimeSec = TimeMic / 1000000, - Bar = [?CHAR_BAR || _ <- lists:seq(1, X)], + PrintTimeSec = PrintTimeMic / 1000000, ok = io:format("~s~n", [Bar]), ok = io:format( - "X: ~b Y: ~b CELLS: ~b GENERATION: ~b DURATION: ~f~n", - [X, Y, X * Y, Generation, TimeSec] + "X: ~b Y: ~b CELLS: ~b GENERATION: ~b DURATION: ~f PRINT TIME: ~f~n", + [X, Y, N, GenCount, TimeSec, PrintTimeSec] ), ok = io:format("~s~n", [Bar]). do_print_board(Board) -> - CharLists = array:to_list( + % It seems that just doing a fold should be faster than map + to_list + % combo, but, after measuring several times, map + to_list has been + % consistently (nearly twice) faster than either foldl or foldr. + RowStrings = array:to_list( array:map( fun(_, Row) -> array:to_list( @@ -64,10 +121,10 @@ do_print_board(Board) -> ), ok = lists:foreach( - fun(CharList) -> - ok = io:format("~s~n", [CharList]) + fun(RowString) -> + ok = io:format("~s~n", [RowString]) end, - CharLists + RowStrings ).