Logo

dev-resources.site

for different kinds of informations.

Advent of Code #8 (in Gleam)

Published at
12/8/2024
Categories
adventofcode
gleam
Author
sethcalebweeks
Categories
2 categories in total
adventofcode
open
gleam
open
Author
14 person written this
sethcalebweeks
open
Advent of Code #8 (in Gleam)

I'm not particularly proud of my code for today's solution. I could definitely refactor it to reduce a lot of the duplication, but I have a lot of other things going on, so I'm just going to leave it as is. The only other thing I'll mention is that this problem would really benefit from generator functions, list comprehensions, or lazy evaluated ranges, but without those features, I resorted to recursion. I suppose this is an example of where my brain decided that recursion was easier to wrap my head around than fold_until. Anyway, here's the code:

import gleam/int
import gleam/io
import gleam/list
import gleam/string
import gleam/pair
import gleam/set.{type Set}
import gleam/option.{Some, None}
import gleam/dict.{type Dict}
import simplifile as file

const example = "
............
........0...
.....0......
.......0....
....0.......
......A.....
............
............
........A...
.........A..
............
............
"

pub fn main() {
  let assert Ok(input) = file.read("input")
  let assert 14 = part1(example)
  let assert 34 = part2(example)
  part1(input) |> int.to_string |> io.println
  part2(input) |> int.to_string |> io.println
}

type Bounds = #(Int, Int)
type Coord = #(Int, Int)
type Map = Dict(String, List(Coord))

fn parse_input(input: String) -> #(Bounds, Map) {
  input
  |> string.trim
  |> string.split("\n")
  |> list.index_fold(#(#(0, 0), dict.new()), fn(acc, line, x) {
    line
    |> string.to_graphemes
    |> list.index_fold(acc, fn(acc, char, y) {
      let #(_, map) = acc
      let map = 
        dict.upsert(map, char, fn(val) {
          case char, val {
            ".", _ -> []
            _, Some(positions) -> list.append(positions, [#(x, y)])
            _, None -> [#(x, y)]
          }
        })
      #(#(x, y), map)
    })
  })
}

fn in_bounds(bounds: Bounds, coord: Coord) -> Bool {
  let #(x, y) = coord
  let #(max_x, max_y) = bounds
  x >= 0 && x <= max_x && y >= 0 && y <= max_y
}

fn part1(input: String) -> Int {
  let #(bounds, map) = parse_input(input)
  map
  |> dict.fold(set.new(), fn(antinodes, _, positions) {
    positions
    |> list.combination_pairs
    |> list.fold(antinodes, fn(antinodes, pair) {
      let #(x1, y1) = pair.first(pair)
      let #(x2, y2) = pair.second(pair)
      let a1 = #(2 * x1 - x2, 2 * y1 - y2)
      let a2 = #(2 * x2 - x1, 2 * y2 - y1)
      case in_bounds(bounds, a1), in_bounds(bounds, a2) {
        True, True -> antinodes |> set.insert(a1) |> set.insert(a2)
        True, False -> antinodes |> set.insert(a1)
        False, True -> antinodes |> set.insert(a2)
        False, False -> antinodes
      }
    })
  })
  |> set.size
}

fn get_antinodes(bounds: Bounds, pair: #(Coord, Coord)) -> Set(Coord) {
  set.new()
  |> set.insert(pair.first(pair))
  |> set.insert(pair.second(pair))
  |> direction_1(bounds, pair)
  |> direction_2(bounds, pair)
}

fn direction_1(set: Set(Coord), bounds: Bounds, pair: #(Coord, Coord)) -> Set(Coord) {
  let #(x1, y1) = pair.first(pair)
  let #(x2, y2) = pair.second(pair)
  let d1 = #(2 * x1 - x2, 2 * y1 - y2)
  case in_bounds(bounds, d1) {
    True -> set |> set.insert(d1) |> direction_1(bounds, #(d1, #(x1, y1)))
    False -> set
  }
}

fn direction_2(set: Set(Coord), bounds: Bounds, pair: #(Coord, Coord)) -> Set(Coord) {
  let #(x1, y1) = pair.first(pair)
  let #(x2, y2) = pair.second(pair)
  let d2 = #(2 * x2 - x1, 2 * y2 - y1)
  case in_bounds(bounds, d2) {
    True -> set |> set.insert(d2) |> direction_2(bounds, #(#(x2, y2), d2))
    False -> set
  }
}

fn part2(input: String) -> Int {
  let #(bounds, map) = parse_input(input)
  map
  |> dict.fold(set.new(), fn(antinodes, _, positions) {
    positions
    |> list.combination_pairs
    |> list.fold(antinodes, fn(antinodes, pair) {
      set.union(antinodes, get_antinodes(bounds, pair))
    })
  })
  |> set.size
}
Enter fullscreen mode Exit fullscreen mode
adventofcode Article's
30 articles in total
Favicon
Climbing a depth-first search hill, Advent of Code 2024, day 10
Favicon
Hoof It
Favicon
How to parse computer code, Advent of Code 2024 day 3
Favicon
Disk Fragmenter
Favicon
How to repair a bridge, Advent of Code 2024 Day 7
Favicon
Resonant Collinearity
Favicon
Advent of Code 2024 - Day 23: LAN Party
Favicon
How to trace steps in a map, Advent of Code 2024 day 6
Favicon
Advent of Code 2024 - Day 21: Keypad Conundrum
Favicon
Advent of Code 2024 - Day 18: Ram Run
Favicon
Advent of Code 2024 - Day 17: Chronospatial Computer
Favicon
Guard Gallivant
Favicon
Advent of Code 2024 Day 5 in Golang: Ordering Pages
Favicon
Advent of Code '24 - Day9: Disk Fragmenter (Python)
Favicon
Advent of Code #8 (in Gleam)
Favicon
Advent of Code #7 (in Gleam)
Favicon
Advent of Code #6 (in Gleam)
Favicon
Advent of Code #5 (in Gleam)
Favicon
AoC 24 - Day 4: Ceres Search
Favicon
Wednesday Links – Edition 2024-12-04
Favicon
Mull It Over
Favicon
Bridge Repair
Favicon
Advent of Code #3 (in Gleam)
Favicon
Day 3: Mull It Over | Advent of Code 2024 | Swift | δΈ­ζ–‡
Favicon
Red-Nosed Reports
Favicon
Day 1: Historian Hysteria | Advent of Code 2024 | Swift | δΈ­ζ–‡
Favicon
Advent of Code 2024 - Day 19: Linen Layout
Favicon
Advent of Code - It's More Than a Competition
Favicon
Advent of Code '24 - Day 10: Hoof It
Favicon
Advent of Code 2024 Retro: What could you do if you didn't care whether you failed?

Featured ones: