One thing that tripped me up for a while when solving today's puzzle is that grouping expressions in Gleam is done using {}
brackets instead of parentheses. That probably cost me a good 15 minutes to figure out.
Gleam doesn't have a whole lot of functions that let you operate on a list by index. There is index_map
and index_fold
, but no way of adding or removing an item by index. Instead, you have to split
at the index and use drop
to take out items. It took me a while to put those pieces together. There is probably a more analytical method of finding which level to remove from the report for part 2, but I ended up going with the naive approach.
import gleam/int
import gleam/io
import gleam/list
import gleam/string
import simplifile as file
const example = "
7 6 4 2 1
1 2 7 8 9
9 7 6 2 1
1 3 2 4 5
8 6 4 4 1
1 3 6 7 9
"
pub fn main() {
let assert Ok(input) = file.read("input")
let assert 2 = part1(example)
let assert 4 = part2(example)
part1(input) |> int.to_string |> io.println
part2(input) |> int.to_string |> io.println
}
fn parse_reports(input: String) -> List(List(Int)) {
input
|> string.trim
|> string.split("\n")
|> list.map(fn(line) {
string.split(line, " ")
|> list.map(fn(number) {
let assert Ok(number) = int.parse(number)
number
})
})
}
fn safe_report(report: List(Int)) -> Bool {
let diff =
list.window_by_2(report)
|> list.map(fn(pair) {
let #(left, right) = pair
left - right
})
let all_decreasing = list.all(diff, fn(level) { level < 0 })
let all_increasing = list.all(diff, fn(level) { level > 0 })
let all_in_range = list.all(diff, fn(level) {
int.absolute_value(level) <= 3 && int.absolute_value(level) > 0
})
all_in_range && {all_decreasing || all_increasing}
}
fn part1(input: String) -> Int {
let reports = parse_reports(input)
list.filter(reports, safe_report)
|> list.length
}
fn report_variations(report: List(Int)) -> List(List(Int)) {
list.index_map(report, fn(_, index) {
let #(left, right) = list.split(report, index)
list.append(left, list.drop(right, 1))
})
}
fn part2(input: String) -> Int {
let reports = parse_reports(input)
list.filter(reports, fn(report) {
list.any([report, ..report_variations(report)], safe_report)
})
|> list.length
}
Top comments (4)
To create the variations you could use the
list.combinations
That's great! Thanks for the tip!
Is that guaranteed to preserve ordering?
Yes, it preserves the order of the list.
see github.com/gleam-lang/stdlib/blob/...
Good to know!