Home Posts Tags Post Search Tag Search

Post 74

Hacker Rank 30 - Fractal Tree

Published on: 2025-09-23 Tags: elixir, Blog, Hacker Rank
Ill just put the code here and if you have any questions please feel free to post in the comments.

defmodule Solution do
    def run(print \\ true) do
        read()
        |> print(print, "read")
        |> build_tree_helper()
        |> print(print, "build_tree_helper")
        |> print_tree()
    end
    
    @doc """
    Reads the input and turns the value into an integer
    """
    def read() do
       IO.read(:stdio, :all)
       |> String.trim()
       |> String.to_integer()
    end
    
    @doc """
    Starts the recursive function to compute the value for any given row, column.
    """
    def build_tree_helper(depth) do
        build_tree(depth, 0, 0, [])
    end
    
    
    @doc """
    Runs through each row column. Checks every depth against each row column up to the depth 
    we are given
    """
    def build_tree(_depth, 63, _col, list), do: list
    def build_tree(depth, row, 100, list),  do: build_tree(depth, row + 1, 0, list)
    def build_tree(depth, row, column, list) do
        character = is_one_at_depths(row, column, depth)   # <- use this instead
        build_tree(depth, row, column + 1, [character | list])
    end
    
    @doc """
    Uses function to return the set of values for height, row_mid, and column_mid(list).
    """
    def build_values(depth) do
        %{
          height: div(32, trunc(:math.pow(2, depth))),
          row_mid: row_mid(depth),
          column_mid: column_mid(depth)
        }
    end
      
    @doc """
    Sets all the mid points of any given Y based off the depth given
    """
    def column_mid(1), do: [49]
    def column_mid(depth) when depth > 1 do
        prev = column_mid(depth - 1)
        offset = div(32, trunc(:math.pow(2, depth - 1)))  # height of previous depth

        Enum.flat_map(prev, fn mid ->
            [mid - offset, mid + offset]
        end)
    end

    @doc """
    Sets the mid point of the Y for a given depth. 
    """
    def row_mid(depth) do
        offsets = [47, 23, 11, 5, 2]
        Enum.at(offsets, depth - 1)     
    end
    
    @doc """
    Given a set of values for the height, row mid-point, and a list of column mid-points, will 
    determine if the row/column given is meant to be a "1" or a "_"
    """
    def is_one(row, column, %{height: height, row_mid: row_mid, column_mid: column_mid}) do
        cond do
            row <= row_mid + height and row > row_mid and Enum.member?(column_mid, column) -> "1"
            row < row_mid and row >= row_mid - height and
                Enum.any?(column_mid, fn col ->
                    offset = row_mid - row
                    column == col - offset or column == col + offset
                end) ->  "1"
            row == row_mid and Enum.member?(column_mid, column) -> "1"
            true -> "_"
        end
    end
    
    @doc """
    Will check every value set for each depth against the row/column given.
    """
    def is_one_at_depths(row, column, max_depth) do
        Enum.any?(1..max_depth, fn depth ->
            values = build_values(depth)
            is_one(row, column, values) == "1"
        end)
        |> set_ones()
    end
      
    @doc """
    Changes the true false values of the Enum.any? to useful characters.
    """
    defp set_ones(true), do: "1"
    defp set_ones(false), do: "_"

    @doc """
    Prints the final version of the diagram
    """
    defp print_tree(list) do
        list
        |> Enum.reverse()
        |> Enum.chunk_every(100)
        |> Enum.each(&IO.puts(Enum.join(&1)))
    end

    @doc """
    Used to debug the code as we build each step.
    """
    defp print(data, false, _label), do: data
    defp print(data, true, label) do
        IO.inspect(data, label: label)
    end
end

Solution.run(false)