Home Posts Tags Post Search Tag Search

Post 57

Hacker Rank 28 - Captain Prime

Published on: 2025-08-06 Tags: elixir, Blog, Side Project, Hacker Rank
You're given a list of numbers. For each number, determine whether it is:

    "CENTRAL": If the number is prime, and all of its left and right truncations are also prime.

    "LEFT": If only all left truncations are prime.

    "RIGHT": If only all right truncations are prime.

    "DEAD": If any truncation (or the number itself) contains a 0, or is not prime.

Input:
5
3137
1367
2333
101
12

Output:
CENTRAL
RIGHT
LEFT
DEAD
DEAD

For each number:

    Check if the number is prime.

    Check its left and right truncations:

        Left truncations: chop digits from the right (313, 31, 3 for 3137)

        Right truncations: chop digits from the left (137, 37, 7)

    Validate all truncations are prime (unless one contains 0).

is_prime/2
Efficiently checks primality with memoization. Edge cases (0, 1) are handled explicitly.
  defp check_prime(n, primes) do
    case Map.fetch(primes, n) do
      {:ok, cached} ->
        {cached, primes}

      :error ->
        is_prime =
          cond do
            n <= 1 -> false
            rem(n, 2) == 0 and n != 2 -> false
            true -> is_prime_loop(n, 3, :math.sqrt(n) |> trunc)
          end

        {is_prime, Map.put(primes, n, is_prime)}
    end
  end

  defp is_prime_loop(_n, i, limit) when i > limit, do: true
  defp is_prime_loop(n, i, _) when rem(n, i) == 0, do: false
  defp is_prime_loop(n, i, limit), do: is_prime_loop(n, i + 2, limit)

left_truncations/1 and right_truncations/1
Generates all possible left/right truncations as integers:
    left_truncations(3137) → [137, 37, 7]
    right_truncations(3137) → [313, 31, 3]

  defp left_truncations(n) do
    digits = Integer.to_string(n)
    len = String.length(digits)

    1..(len - 1)
    |> Enum.map(fn i -> String.slice(digits, i..-1) end)
    |> Enum.filter(&(&1 != ""))
    |> Enum.map(&String.to_integer/1)
  end

  defp right_truncations(n) do
    digits = Integer.to_string(n)
    len = String.length(digits)

    1..(len - 1)
    |> Enum.map(fn i -> String.slice(digits, 0..(len - i - 1)) end)
    |> Enum.filter(&(&1 != ""))
    |> Enum.map(&String.to_integer/1)
  end

assign_fates/1
Given the original number and the results of the truncation checks:
    If the number contains 0, immediately marks as "DEAD"
    If all left and right truncations are prime → "CENTRAL"
    If only left are prime → "LEFT"
    If only right are prime → "RIGHT"
    Otherwise → "DEAD"

  defp assign_fates(results) do
    Enum.map(results, fn
      {number, false} ->
        {number, "DEAD"}

      {number, left_list, right_list} ->
        if String.contains?(Integer.to_string(number), "0") do
          {number, "DEAD"}
        else
          left_ok? = Enum.all?(left_list, fn {_n, is_prime} -> is_prime end)
          right_ok? = Enum.all?(right_list, fn {_n, is_prime} -> is_prime end)

          cond do
            left_ok? and right_ok? -> {number, "CENTRAL"}
            left_ok? -> {number, "LEFT"}
            right_ok? -> {number, "RIGHT"}
            true -> {number, "DEAD"}
          end
        end
    end)
  end

This should be what you need in order to deal with these cases.