day 13
This commit is contained in:
parent
f17388b5ec
commit
49a5fd7b52
3 changed files with 221 additions and 0 deletions
15
sample/day13-sample.txt
Normal file
15
sample/day13-sample.txt
Normal file
|
@ -0,0 +1,15 @@
|
|||
Button A: X+94, Y+34
|
||||
Button B: X+22, Y+67
|
||||
Prize: X=8400, Y=5400
|
||||
|
||||
Button A: X+26, Y+66
|
||||
Button B: X+67, Y+21
|
||||
Prize: X=12748, Y=12176
|
||||
|
||||
Button A: X+17, Y+86
|
||||
Button B: X+84, Y+37
|
||||
Prize: X=7870, Y=6450
|
||||
|
||||
Button A: X+69, Y+23
|
||||
Button B: X+27, Y+71
|
||||
Prize: X=18641, Y=10279
|
105
src/day13_p1.gleam
Normal file
105
src/day13_p1.gleam
Normal file
|
@ -0,0 +1,105 @@
|
|||
import gleam/int
|
||||
import gleam/io
|
||||
import gleam/iterator
|
||||
import gleam/list.{map, reduce}
|
||||
import gleam/option.{type Option}
|
||||
import gleam/string
|
||||
import stdin.{stdin}
|
||||
|
||||
pub fn main() {
|
||||
stdin()
|
||||
|> read_input
|
||||
|> map(calculate_win_cost)
|
||||
|> option.values
|
||||
|> reduce(int.add)
|
||||
|> io.debug
|
||||
}
|
||||
|
||||
fn calculate_win_cost(machine: ClawMachine) -> Option(Int) {
|
||||
let Machine(a, b, prize) = machine
|
||||
let #(a_x, a_y) = a
|
||||
let #(b_x, b_y) = b
|
||||
let #(p_x, p_y) = prize
|
||||
|
||||
let a_min = min_presses(a, prize)
|
||||
|
||||
list.range(0, a_min)
|
||||
|> list.filter_map(fn(a_times) {
|
||||
let prize_rem_x = p_x - a_x * a_times
|
||||
let prize_rem_y = p_y - a_y * a_times
|
||||
let b_times = min_presses(b, #(prize_rem_x, prize_rem_y))
|
||||
case prize_rem_x - b_x * b_times, prize_rem_y - b_y * b_times {
|
||||
0, 0 -> Ok(#(a_times, b_times))
|
||||
_, _ -> Error(Nil)
|
||||
}
|
||||
})
|
||||
|> map(calculate_cost)
|
||||
|> reduce(int.min)
|
||||
|> option.from_result
|
||||
}
|
||||
|
||||
fn calculate_cost(combo: #(Int, Int)) -> Int {
|
||||
let #(a, b) = combo
|
||||
a * 3 + b
|
||||
}
|
||||
|
||||
fn min_presses(advance: #(Int, Int), target: #(Int, Int)) -> Int {
|
||||
let #(a_x, a_y) = advance
|
||||
let #(t_x, t_y) = target
|
||||
let assert Ok(a_min_x) = int.divide(t_x, a_x)
|
||||
let assert Ok(a_min_y) = int.divide(t_y, a_y)
|
||||
int.min(a_min_x, a_min_y)
|
||||
}
|
||||
|
||||
pub type ClawMachine {
|
||||
Machine(a: #(Int, Int), b: #(Int, Int), prize: #(Int, Int))
|
||||
}
|
||||
|
||||
fn read_input(it: iterator.Iterator(String)) -> List(ClawMachine) {
|
||||
it
|
||||
|> iterator.fold([], fn(acc, line) {
|
||||
case string.trim(line) {
|
||||
"Button A: " <> rest -> [
|
||||
Machine(parse_button(rest), #(0, 0), #(0, 0)),
|
||||
..acc
|
||||
]
|
||||
"Button B: " <> rest -> acc |> patch_b(parse_button(rest))
|
||||
"Prize: " <> rest -> acc |> patch_prize(parse_prize(rest))
|
||||
_ -> acc
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_button(text) -> #(Int, Int) {
|
||||
let assert [Ok(x), Ok(y)] =
|
||||
text
|
||||
|> string.drop_start(2)
|
||||
|> string.split(", Y+")
|
||||
|> map(int.parse)
|
||||
|
||||
#(x, y)
|
||||
}
|
||||
|
||||
fn parse_prize(text) -> #(Int, Int) {
|
||||
let assert [Ok(x), Ok(y)] =
|
||||
text
|
||||
|> string.drop_start(2)
|
||||
|> string.split(", Y=")
|
||||
|> map(int.parse)
|
||||
|
||||
#(x, y)
|
||||
}
|
||||
|
||||
fn patch_b(acc: List(ClawMachine), b: #(Int, Int)) -> List(ClawMachine) {
|
||||
case acc {
|
||||
[] -> [Machine(#(0, 0), b, #(0, 0))]
|
||||
[Machine(a, _, p), ..rest] -> [Machine(a, b, p), ..rest]
|
||||
}
|
||||
}
|
||||
|
||||
fn patch_prize(acc: List(ClawMachine), p: #(Int, Int)) -> List(ClawMachine) {
|
||||
case acc {
|
||||
[] -> [Machine(#(0, 0), #(0, 0), p)]
|
||||
[Machine(a, b, _), ..rest] -> [Machine(a, b, p), ..rest]
|
||||
}
|
||||
}
|
101
src/day13_p2.gleam
Normal file
101
src/day13_p2.gleam
Normal file
|
@ -0,0 +1,101 @@
|
|||
import gleam/int
|
||||
import gleam/io
|
||||
import gleam/iterator
|
||||
import gleam/list.{map, reduce}
|
||||
import gleam/option.{type Option, None, Some}
|
||||
import gleam/string
|
||||
import stdin.{stdin}
|
||||
|
||||
pub fn main() {
|
||||
stdin()
|
||||
|> read_input
|
||||
|> map(calculate_win_cost)
|
||||
|> option.values
|
||||
|> reduce(int.add)
|
||||
|> io.debug
|
||||
}
|
||||
|
||||
fn calculate_win_cost(machine: ClawMachine) -> Option(Int) {
|
||||
let Machine(a, b, prize) = machine
|
||||
let #(a_x, a_y) = a
|
||||
let #(b_x, b_y) = b
|
||||
let #(p_x, p_y) = prize
|
||||
|
||||
let assert Ok(a_times) =
|
||||
int.divide(b_y * p_x - b_x * p_y, a_x * b_y - a_y * b_x)
|
||||
|
||||
let prize_rem_x = p_x - a_x * a_times
|
||||
let prize_rem_y = p_y - a_y * a_times
|
||||
let b_times = min_presses(b, #(prize_rem_x, prize_rem_y))
|
||||
case prize_rem_x - b_x * b_times, prize_rem_y - b_y * b_times {
|
||||
0, 0 -> Some(#(a_times, b_times))
|
||||
_, _ -> None
|
||||
}
|
||||
|> option.map(calculate_cost)
|
||||
}
|
||||
|
||||
fn calculate_cost(combo: #(Int, Int)) -> Int {
|
||||
let #(a, b) = combo
|
||||
a * 3 + b
|
||||
}
|
||||
|
||||
fn min_presses(advance: #(Int, Int), target: #(Int, Int)) -> Int {
|
||||
let #(a_x, a_y) = advance
|
||||
let #(t_x, t_y) = target
|
||||
let assert Ok(a_min_x) = int.divide(t_x, a_x)
|
||||
let assert Ok(a_min_y) = int.divide(t_y, a_y)
|
||||
int.min(a_min_x, a_min_y)
|
||||
}
|
||||
|
||||
pub type ClawMachine {
|
||||
Machine(a: #(Int, Int), b: #(Int, Int), prize: #(Int, Int))
|
||||
}
|
||||
|
||||
fn read_input(it: iterator.Iterator(String)) -> List(ClawMachine) {
|
||||
it
|
||||
|> iterator.fold([], fn(acc, line) {
|
||||
case string.trim(line) {
|
||||
"Button A: " <> rest -> [
|
||||
Machine(parse_button(rest), #(0, 0), #(0, 0)),
|
||||
..acc
|
||||
]
|
||||
"Button B: " <> rest -> acc |> patch_b(parse_button(rest))
|
||||
"Prize: " <> rest -> acc |> patch_prize(parse_prize(rest))
|
||||
_ -> acc
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_button(text) -> #(Int, Int) {
|
||||
let assert [Ok(x), Ok(y)] =
|
||||
text
|
||||
|> string.drop_start(2)
|
||||
|> string.split(", Y+")
|
||||
|> map(int.parse)
|
||||
|
||||
#(x, y)
|
||||
}
|
||||
|
||||
fn parse_prize(text) -> #(Int, Int) {
|
||||
let assert [Ok(x), Ok(y)] =
|
||||
text
|
||||
|> string.drop_start(2)
|
||||
|> string.split(", Y=")
|
||||
|> map(int.parse)
|
||||
|
||||
#(x + 10_000_000_000_000, y + 10_000_000_000_000)
|
||||
}
|
||||
|
||||
fn patch_b(acc: List(ClawMachine), b: #(Int, Int)) -> List(ClawMachine) {
|
||||
case acc {
|
||||
[] -> [Machine(#(0, 0), b, #(0, 0))]
|
||||
[Machine(a, _, p), ..rest] -> [Machine(a, b, p), ..rest]
|
||||
}
|
||||
}
|
||||
|
||||
fn patch_prize(acc: List(ClawMachine), p: #(Int, Int)) -> List(ClawMachine) {
|
||||
case acc {
|
||||
[] -> [Machine(#(0, 0), #(0, 0), p)]
|
||||
[Machine(a, b, _), ..rest] -> [Machine(a, b, p), ..rest]
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue