Created
January 12, 2017 18:25
-
-
Save smpallen99/a840db02971d1051e2375d34d8f21be3 to your computer and use it in GitHub Desktop.
Tree of Life Implementation in Elixir
This file contains hidden or 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
| # Refer to https://www.hackerrank.com/challenges/the-tree-of-life for the problem description | |
| defmodule Life do | |
| use Bitwise | |
| def run do | |
| rule = read_int | |
| initial_state = IO.gets("") |> String.trim | |
| for _ <- 1..read_int() do | |
| [i, node] = IO.gets("") |> String.trim |> String.split(" ") | |
| {String.to_integer(i), node} | |
| end | |
| |> simulate(rule, initial_state) | |
| |> Enum.map(&IO.puts/1) | |
| end | |
| def init, do: %{count: 0, history: %{}} | |
| def simulate(cases, rule, initial_state) do | |
| init | |
| |> build_tree(initial_state) | |
| |> build_rules(rule) | |
| |> run_cases(cases) | |
| end | |
| def build_tree(state, initial_state) do | |
| tree = do_build_tree([], initial_state) | |
| put_in(state, [:tree], tree) | |
| |> put_in([:history,0],tree) | |
| end | |
| def do_build_tree([tree], ""), do: tree | |
| def do_build_tree(stack, " " <> str), do: do_build_tree(stack, str) | |
| def do_build_tree(stack, "(" <> str), do: do_build_tree(stack, str) | |
| def do_build_tree([right, mid, left|stack], ")" <> str) do | |
| [{mid, left, right}|stack] | |
| |> do_build_tree(str) | |
| end | |
| def do_build_tree(stack, <<char::size(8), str::bitstring>>) do | |
| [get_value(char)|stack] | |
| |> do_build_tree(str) | |
| end | |
| def get_value(?.), do: 0 | |
| def get_value(?X), do: 1 | |
| def get_symbol(0), do: "." | |
| def get_symbol(1), do: "X" | |
| def run_cases(state, cases, acc \\ []) | |
| def run_cases(_state, [], acc), do: Enum.reverse(acc) | |
| def run_cases(%{count: count, history: history} = state, [{num, query}|cases], acc) when num < 0 do | |
| query = parse_query(query) | |
| count = count + num | |
| tree = Map.get(history, count) | |
| state = put_in(state, [:count], count) | |
| |> put_in([:tree], tree) | |
| state | |
| |> run_cases(cases, [find_value(tree, query)|acc]) | |
| end | |
| def run_cases(state, [{0, query}|cases], acc) do | |
| run_cases(state, cases, [find_value(state[:tree], parse_query(query))|acc]) | |
| end | |
| def run_cases(%{count: count} = state, [{i, query}|cases], acc) do | |
| query = parse_query(query) | |
| {state, tree} = case get_in(state, [:history, count + i]) do | |
| nil -> | |
| do_run_case(state, i) | |
| tree -> {put_in(state, [:count], count + i), tree} | |
| end | |
| put_in(state, [:tree], tree) | |
| |> run_cases(cases, [find_value(tree, query)|acc]) | |
| end | |
| def do_run_case(state, i) do | |
| 1..i | |
| |> Enum.reduce({state, state[:tree]}, fn _, {state, acc} -> | |
| new_new = run_case(state, acc) | |
| state = update_in(state, [:count], &(&1 + 1)) | |
| state = put_in(state, [:history, state[:count]], new_new) | |
| {state, new_new} | |
| end) | |
| end | |
| def run_case(state, tree) do | |
| parent = elem(tree,0) | |
| new_parent = new_value(state, 0, {parent, elem(tree,1), elem(tree,2)}) | |
| {new_parent, do_run_case(state, parent, elem(tree,1)), do_run_case(state, parent, elem(tree,2))} | |
| end | |
| def do_run_case(state, one, tree) do | |
| case new_value(state, one, tree) do | |
| false -> | |
| new_value_leaf(state, one, tree) | |
| nv -> | |
| {nv, do_run_case(state, elem(tree,0), elem(tree,1)), do_run_case(state, elem(tree,0), elem(tree,2))} | |
| end | |
| end | |
| def new_value(%{rules: rules}, one, {three, two, four}) do | |
| inx = (one <<< 3) + (get_node_value(two) <<< 2) + (three <<< 1) + get_node_value(four) | |
| rules[inx] | |
| end | |
| def new_value(_, _, _), do: false | |
| def new_value_leaf(%{rules: rules}, one, node) do | |
| inx = (one <<< 3) + 0 + (node <<< 1) | |
| rules[inx] | |
| end | |
| def get_node_value({v, _, _}), do: v | |
| def get_node_value(v), do: v | |
| def find_value(tree, query) do | |
| _find_value(tree, query) | |
| end | |
| def _find_value(tree, []) when is_tuple(tree) do | |
| elem(tree, 0) |> get_symbol | |
| end | |
| def _find_value(tree, []), do: get_symbol(tree) | |
| def _find_value(tree, [:right|query]), do: _find_value(elem(tree,2), query) | |
| def _find_value(tree, [:left|query]), do: _find_value(elem(tree,1), query) | |
| def parse_query(query, acc \\ []) | |
| def parse_query("[" <> str, acc), do: parse_query(str, acc) | |
| def parse_query("]" <> _, acc), do: Enum.reverse(acc) | |
| def parse_query(">" <> str, acc), do: parse_query(str, [:right|acc]) | |
| def parse_query("<" <> str, acc), do: parse_query(str, [:left|acc]) | |
| def build_rules(state, rule) do | |
| rules = for i <- 0..15 do | |
| {i, (rule >>> i) &&& 1} | |
| end | |
| |> Enum.into(%{}) | |
| put_in state, [:rules], rules | |
| end | |
| def read_int do | |
| IO.gets("") |> String.trim |> String.to_integer | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment