Created
December 28, 2017 06:17
-
-
Save cableray/f54d2392a49d6e6b2978c1b77fcccd3b to your computer and use it in GitHub Desktop.
Brainf**k interpreter from code wars
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Brainluck do | |
defstruct data: <<0>>, data_pointer: 0, | |
output: <<>>, | |
instructions: "", inst_pointer: 0, | |
input: <<>>, | |
skip_depth: 0, | |
block_stack: [] | |
def brain_luck(program, inputs) do | |
%Brainluck{instructions: program, input: inputs} |> process | |
end | |
defp process(%Brainluck{instructions: instructions, inst_pointer: pointer, output: output}) when (pointer+1) > byte_size(instructions) do | |
output | |
end | |
defp process(state = %Brainluck{instructions: instructions, inst_pointer: pointer}) do | |
<<instruction>> = String.at(instructions, pointer) | |
process(process(instruction, %{state|inst_pointer: pointer+1})) | |
end | |
# scanning for closing brace | |
defp process(instruction, state = %Brainluck{skip_depth: depth}) when depth > 0 do | |
case instruction do | |
?[ -> %{state|skip_depth: depth+1} | |
?] -> %{state|skip_depth: depth-1} | |
_ -> state | |
end | |
end | |
defp process(?+, state) do | |
state |> update_datum(fn | |
#255 -> 0 # because we are using the default 8-bit unsigned binary field, this is handled implicitly | |
x -> x+1 | |
end) | |
end | |
defp process(?-, state) do | |
state |> update_datum(fn | |
# 0 -> 255 # because we are using the default 8-bit unsigned binary field, this is handled implicitly | |
x -> x-1 | |
end) | |
end | |
defp process(?., state=%Brainluck{output: output}) do | |
%{state|output: output <> <<get_datum(state)>>} | |
end | |
defp process(?,, state=%Brainluck{input: <<input>> <> rest}) do | |
state = state |> update_datum(fn | |
_ -> input | |
end) | |
%{state|input: rest} | |
end | |
defp process(?>, state=%Brainluck{data_pointer: pointer, data: data}) when (pointer+1) == byte_size(data) do | |
%{state|data_pointer: pointer + 1, data: data <> <<0>>} | |
end | |
defp process(?>, state=%Brainluck{data_pointer: pointer}) do | |
%{state|data_pointer: pointer + 1} | |
end | |
defp process(?<, state=%Brainluck{data_pointer: 0, data: data}) do | |
%{state|data: <<0>> <> data} | |
end | |
defp process(?<, state=%Brainluck{data_pointer: pointer}) do | |
%{state|data_pointer: pointer - 1} | |
end | |
defp process(?[, state=%Brainluck{inst_pointer: pointer, block_stack: block_stack}) do | |
if get_datum(state) == 0 do | |
%{state|skip_depth: 1} | |
else | |
# note that pointer is the next instruction, not the current instruction | |
%{state|block_stack: [pointer|block_stack]} | |
end | |
end | |
defp process(?], state=%Brainluck{block_stack: [prev|rest]}) do | |
if get_datum(state) != 0 do | |
%{state|inst_pointer: prev} | |
else | |
%{state|block_stack: rest} | |
end | |
end | |
defp get_datum(%Brainluck{data_pointer: pointer, data: data}) do | |
<<_::binary-size(pointer), datum, _::binary>> = data | |
datum | |
end | |
defp update_datum(state = %Brainluck{data_pointer: pointer, data: data}, update) do | |
<<first::binary-size(pointer), original, rest::binary>> = data | |
data = first <> <<update.(original)>> <> rest | |
%{state | data: data} | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule TestBrainluck do | |
use ExUnit.Case | |
test "increment and print" do | |
assert Brainluck.brain_luck("+.", "") == <<1>> | |
assert Brainluck.brain_luck("+.+.", "") == <<1,2>> | |
assert Brainluck.brain_luck("+++.", "") == <<3>> | |
end | |
test "decrement and print" do | |
assert Brainluck.brain_luck("-.", "") == <<255>> | |
assert Brainluck.brain_luck("-.-.", "") == <<255,254>> | |
assert Brainluck.brain_luck("---.", "") == <<253>> | |
end | |
test "move to uninitialized cell" do | |
assert Brainluck.brain_luck(">.", "") == <<0>> | |
assert Brainluck.brain_luck(">.++.>.", "") == <<0,2,0>> | |
assert Brainluck.brain_luck("<.", "") == <<0>> | |
assert Brainluck.brain_luck("<.++.<.", "") == <<0,2,0>> | |
end | |
test "shift through initialized cells" do | |
assert Brainluck.brain_luck("+>++>+++><.<.<.>.>.", "") == <<3,2,1,2,3>> | |
end | |
test "read input" do | |
assert Brainluck.brain_luck(",.,.,.", "abc") == <<?a, ?b, ?c>> | |
end | |
test "skips block if data is 0" do | |
assert Brainluck.brain_luck("[[>+++.]>++.]+.", "") == <<1>> | |
assert Brainluck.brain_luck("+.-[[>+++.]>++.]", "") == <<1>> | |
end | |
test "echo until byte 255 is encoutered" do | |
assert Brainluck.brain_luck(",+[-.,+]", "Codewars" <> << 255 >>) == "Codewars" | |
end | |
test "echo until byte 0 is encoutered" do | |
assert Brainluck.brain_luck(",[.[-],]", "Codewars" <> << 0 >>) == "Codewars" | |
assert Brainluck.brain_luck(",[.,]", "Codewars" <> << 0 >>) == "Codewars" | |
end | |
test "multiplies two number" do | |
assert Brainluck.brain_luck(",>,<[>[->+>+<<]>>[-<<+>>]<<<-]>>.", << 8, 9 >>) == << 72 >> | |
assert Brainluck.brain_luck(",>,<[>[->+>+<<]>>[-<<+>>]<<<-]>>.", << 0, 7 >>) == << 0 >> | |
end | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment