DEV Community

Caleb Weeks
Caleb Weeks

Posted on

Advent of Code #2 (in Gleam)

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 } 
Enter fullscreen mode Exit fullscreen mode

Top comments (4)

Collapse
 
mvlootman profile image
Michiel Vlootman

To create the variations you could use the list.combinations

 let n = list.length(report) list.combinations(report, n - 1) 
Enter fullscreen mode Exit fullscreen mode
Collapse
 
sethcalebweeks profile image
Caleb Weeks • Edited

That's great! Thanks for the tip!

Is that guaranteed to preserve ordering?

Collapse
 
mvlootman profile image
Michiel Vlootman

Yes, it preserves the order of the list.
see github.com/gleam-lang/stdlib/blob/...

Thread Thread
 
sethcalebweeks profile image
Caleb Weeks

Good to know!