Advent of Code 2020 in Elixir - Day 3

Toboggan Trajectory

defmodule Aoc2020.Day3 do
  @moduledoc "Toboggan Trajectory"

  def parse_input() do
    File.read!("priv/inputs/2020/day3.txt")
    |> String.trim()
    |> String.split("\n")
  end

  def plot_route(maxY) do
    for y <- 0..maxY, do: {y * 3, y}
  end

  def tree_at_location(map, x, y) do
    row = Enum.at(map, y)
    String.at(row, x) == "#"
  end

  def plot_trees(map, maxX) do
    repeated_map = Enum.map(map, &String.duplicate(&1, ceil(maxX / String.length(&1))))

    Enum.flat_map(Enum.with_index(repeated_map), fn {row, y} ->
      String.codepoints(row)
      |> Enum.with_index()
      |> Enum.filter(fn {cell, _} -> cell == "#" end)
      |> Enum.map(fn {_, x} -> {x, y} end)
    end)
  end

  # part2
  def plot_route_with_steps(maxY, xStep, yStep) do
    for y <- 0..maxY, do: {y * xStep, y * yStep}
  end

  def route_tree_count(map, route) do
    {maxX, _} = List.last(route)
    trees = plot_trees(map, maxX)
    length(Enum.filter(trees, fn tree -> Enum.member?(route, tree) end))
  end

  def part1(map) do
    maxY = length(map) - 1
    route = plot_route(maxY)
    route_tree_count(map, route)
  end

  def part2(map) do
    maxY = length(map) - 1

    routes = [
      plot_route_with_steps(maxY, 1, 1),
      plot_route_with_steps(maxY, 3, 1),
      plot_route_with_steps(maxY, 5, 1),
      plot_route_with_steps(maxY, 7, 1),
      plot_route_with_steps(maxY, 1, 2)
    ]

    Enum.map(routes, &route_tree_count(map, &1))
    |> Enum.reduce(&*/2)
  end

  def run do
    map = parse_input()
    # part1(map)
    part2(map)
  end
end