Skip to content

Instantly share code, notes, and snippets.

@cableray
Created December 28, 2017 06:17
Show Gist options
  • Save cableray/f54d2392a49d6e6b2978c1b77fcccd3b to your computer and use it in GitHub Desktop.
Save cableray/f54d2392a49d6e6b2978c1b77fcccd3b to your computer and use it in GitHub Desktop.
Brainf**k interpreter from code wars
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
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