% Програма моделювання одновимірних клітинних автоматів
%% encoding: utf8
get_bit(Index, Bits) when is_bitstring(Bits), is_integer(Index), Index >= 0, Index < bit_size(Bits) ->
<<_:Index, Val:1, _/bitstring>> = Bits,
Val.
get_state(Index, Bits) when is_bitstring(Bits), is_integer(Index), Index >= 0, Index < bit_size(Bits) ->
get_bit(Index, Bits);
get_state(Index, Bits) when is_bitstring(Bits), is_integer(Index), (Index =:= -1) orelse (Index =:= bit_size(Bits)) -> 0.
get_state_wide(Index, Bits) when is_bitstring(Bits), is_integer(Index), bit_size(Bits) > 0, Index >= 0, Index < bit_size(Bits) ->
get_state_wide(Index, Bits, 0, 0).
get_state_wide(Index, Bits, 3, Acc) when is_bitstring(Bits), is_integer(Index), bit_size(Bits) > 0, Index >= 0, Index < bit_size(Bits) -> Acc;
get_state_wide(Index, Bits, Rel, Acc) when is_bitstring(Bits), is_integer(Index), bit_size(Bits) > 0, Index >= 0, Index < bit_size(Bits) ->
get_state_wide(Index, Bits, Rel + 1, Acc + get_state(Index + Rel - 1, Bits) * trunc(math:pow(2, (2 - Rel)))).
next_state(WideState, Rule) when is_integer(WideState), is_integer(Rule), WideState >= 0, WideState < 8, Rule < 256, Rule >= 0 ->
get_bit(7-WideState, <<Rule:8>>);
next_state(Bits, Rule) when is_bitstring(Bits), is_integer(Rule), Rule < 256, Rule >= 0, bit_size(Bits) > 0 ->
<< << (next_state(get_state_wide(X, Bits), Rule)):1 >> || X <- lists:seq(0, bit_size(Bits)-1) >>.
gen_state(Bits, Rule, Count) when is_bitstring(Bits), is_integer(Rule), is_integer(Count), Rule < 256, Rule >= 0, bit_size(Bits) > 0, Count > 0 ->
gen_state_loop(Rule, Count-1, [Bits]).
gen_state_loop(Rule, 0, Acc) when is_integer(Rule), is_list(Acc), Rule < 256, Rule >= 0 -> lists:reverse(Acc);
gen_state_loop(Rule, Reminder, Acc)
when is_integer(Rule), is_list(Acc), is_integer(Reminder), Rule < 256, Rule >= 0, Reminder > 0 ->
[Prev|_] = Acc,
gen_state_loop(Rule, Reminder-1, [next_state(Prev, Rule)|Acc]).
write_state(Bits) when is_bitstring(Bits), bit_size(Bits) > 0 ->
Symbols = ".O",
io:fwrite([lists:nth(get_bit(X, Bits) + 1, Symbols) || X <- lists:seq(0, bit_size(Bits) - 1)] ++ "~n");
write_state([]) -> ok;
write_state([H|T]) -> write_state(H), write_state(T).
read_rule() ->
Input = io:fread("Введіть правило (ціле число від 0 до 255 включно): ", "~d"),
case Input of
{ok, [Rule]} when Rule < 256, Rule >= 0 -> Rule;
_ -> io:fwrite("Помилка вводу. Спробуйте ще раз.~n~n"), read_rule()
end.
read_gens() ->
Input = io:fread("Введіть кількість поколінь (ціле число від 1 до 80 включно): ", "~d"),
case Input of
{ok, [Gens]} when Gens =< 80, Gens > 0 -> Gens;
_ -> io:fwrite("Помилка вводу. Спробуйте ще раз.~n~n"), read_gens()
end.
read_state() ->
io:fwrite("Введіть початковий стан (крапка означає порожню кілтинку, а латинська велика літера Х означає заповнену клітинку).~n"),
Input = lists:droplast(io:get_line("")),
case Input of
"" -> io:fwrite("Ввід порожній. Спробуйте ще раз.~n~n"), read_state();
_ ->
Valid = lists:all(fun(X) -> X =:= $. orelse X =:= $X end, Input),
if Valid -> << << (if I =:= $X -> 1; true -> 0 end):1 >> || I <- Input >>; true -> io:fwrite("Стрічка містить зайві символи. Спробуйте ще раз.~n~n"), read_state() end
end.
main(_) ->
io:setopts([{encoding, unicode}]),
io:fwrite("Програма моделювання одновимірних клітинних автоматів~n~n"),
State = read_state(),
Gens = read_gens(),
Rule = read_rule(),
Picture = gen_state(State, Rule, Gens),
write_state(Picture),
io:nl().