~/adam.log

Hacker Rank 30 - Fractal Tree

Published 2025-09-23

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)