Home Posts Tags Post Search Tag Search

Post 73

Hacker Rank 29 - Sierpiński triangle

Published on: 2025-09-16 Tags: elixir, Blog, Hacker Rank
Sierpiński Triangle Elixir Program – Step-by-Step

defmodule Solution do
    def main do
      depth = read()
      print(0, 0, 32, depth, "")
    end
  
    # Read the recursion depth
    def read do
      IO.read(:stdio, :line)
      |> String.trim()
      |> String.to_integer()
    end
  
    # Stop printing after row 32
    def print(32, _col, _size, _depth, _row_string), do: :ok
  
    # End of a row, print it and move to next
    def print(row, 63, _size, depth, row_string) do
      IO.puts(row_string)
      print(row + 1, 0, 32, depth, "")
    end
  
    # Print each cell
    def print(row, col, _size, depth, row_string) do
      char =
        if filled?(row, col, 0, 31, 32, depth), do: "1", else: "_"
  
      print(row, col + 1, 32, depth, row_string <> char)
    end
  
    # Check if a cell is part of the fractal
    def filled?(row, col, r0, c0, h, depth) do
      # Base case: smallest triangle, just fill it
      if depth == 0 do
        inside_triangle?(row, col, r0, c0, h)
      else
        half = div(h, 2)
  
        # Recurse into the three upright sub-triangles
        filled?(row, col, r0, c0, half, depth - 1) or
          filled?(row, col, r0 + half, c0 - half, half, depth - 1) or
          filled?(row, col, r0 + half, c0 + half, half, depth - 1)
      end
    end
  
    # Check if a cell is inside an upright triangle of height h
    def inside_triangle?(row, col, top_row, mid_col, height) do
      row >= top_row and row < top_row + height and
        col >= mid_col - (row - top_row) and
        col <= mid_col + (row - top_row)
    end
  end
  
  Solution.main()

1. Canvas
   • Size: 32 rows × 63 columns.
   • Coordinates: (row, col) with row 0..31, col 0..62.
   • The outermost triangle is an upright triangle of height 32, centered on column 31.

2. Base Function: inside_triangle?/5
   inside_triangle?(row, col, top_row, mid_col, height) checks whether a cell is inside a single upright triangle.
   - row >= top_row and row < top_row + height → vertical span
   - col >= mid_col - (row - top_row) → left edge
   - col <= mid_col + (row - top_row) → right edge

3. Recursive Fractal: filled?/6
   filled?(row, col, r0, c0, h, depth) decides if a cell should be "1".
   Parameters:
     • (row, col) – cell being evaluated
     • (r0, c0) – apex (top midpoint) of the current triangle
     • h – height of the current triangle
     • depth – recursion depth remaining
   Logic:
     a. Base case (depth == 0):
        Return inside_triangle?(row, col, r0, c0, h)
        → fill the smallest triangle completely.
     b. Recursive case:
        half = div(h, 2)
        Return true if the cell is inside ANY of the three upright sub-triangles:
          1. Top:    apex (r0,       c0)
          2. Bottom-left:  apex (r0+half, c0-half)
          3. Bottom-right: apex (r0+half, c0+half)
        Notice there is no recursive call for the central downward-pointing triangle.
        That omission leaves the “hole” that forms the fractal.

4. Why Holes Appear
   Because we only recurse into the three upright sub-triangles and never into the central inverted one,
   each level automatically leaves a blank triangular hole. Repeating this for every sub-triangle
   creates the Sierpiński pattern.

5. Printing the Canvas
   print(row, col, _size, depth, row_string):
     • For each cell, call filled?(row, col, 0, 31, 32, depth).
     • If true → add "1" to the row string, else "_".
     • After 63 columns, print the row and move to the next row until 32 rows are done.

6. Entry Point
   main():
     • Reads depth from input.
     • Calls print(0, 0, 32, depth, "") to start drawing from the top-left cell.

7. Recursion Visualization
   Depth 0: Single filled triangle (height 32).
   Depth 1: One large hole carved, leaving three upright triangles (height 16 each).
   Depth 2: Each of those three triangles is processed again,
            leaving nine upright triangles (height 8 each).
   And so on.

Summary
   • inside_triangle?/5 determines if a cell is inside any given upright triangle.
   • filled?/6 recurses into three sub-triangles only, leaving the middle blank.
   • print/5 walks through all 32×63 cells, printing "1" or "_".
   • main/0 sets everything in motion.
   The omission of the central downward triangle at each recursion level is what generates
   the classic Sierpiński triangle without explicitly drawing “holes.”