day 5
This commit is contained in:
parent
28036847e2
commit
fc530ec5f8
3 changed files with 311 additions and 0 deletions
28
sample/day5-sample.txt
Normal file
28
sample/day5-sample.txt
Normal file
|
@ -0,0 +1,28 @@
|
|||
47|53
|
||||
97|13
|
||||
97|61
|
||||
97|47
|
||||
75|29
|
||||
61|13
|
||||
75|53
|
||||
29|13
|
||||
97|29
|
||||
53|29
|
||||
61|53
|
||||
97|53
|
||||
61|29
|
||||
47|13
|
||||
75|47
|
||||
97|75
|
||||
47|61
|
||||
75|61
|
||||
47|29
|
||||
75|13
|
||||
53|13
|
||||
|
||||
75,47,61,53,29
|
||||
97,61,53,29,13
|
||||
75,29,13
|
||||
75,97,47,61,53
|
||||
61,13,29
|
||||
97,13,75,29,47
|
119
src/day5_p1.gleam
Normal file
119
src/day5_p1.gleam
Normal file
|
@ -0,0 +1,119 @@
|
|||
import gleam/bool
|
||||
import gleam/dict.{type Dict}
|
||||
import gleam/int
|
||||
import gleam/io
|
||||
import gleam/iterator
|
||||
import gleam/list.{contains, filter, fold, group, map, split_while}
|
||||
import gleam/pair
|
||||
import gleam/result
|
||||
import gleam/string
|
||||
import stdin.{stdin}
|
||||
|
||||
pub fn main() {
|
||||
stdin()
|
||||
|> read_input
|
||||
|> calculate
|
||||
|> io.debug
|
||||
}
|
||||
|
||||
fn calculate(input: #(Dict(Int, List(Int)), List(List(Int)))) {
|
||||
let #(rules, updates) = input
|
||||
|
||||
updates
|
||||
|> filter(fn(x) { is_valid([], x, rules) })
|
||||
|> map(middle)
|
||||
|> fold(0, int.add)
|
||||
}
|
||||
|
||||
fn is_valid(
|
||||
processed: List(Int),
|
||||
remaining: List(Int),
|
||||
rules: Dict(Int, List(Int)),
|
||||
) {
|
||||
case remaining {
|
||||
[] -> True
|
||||
[x] -> check_rules(processed, x, rules)
|
||||
[x, ..rest] ->
|
||||
check_rules(processed, x, rules)
|
||||
&& is_valid([x, ..processed], rest, rules)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_rules(processed: List(Int), page: Int, rules: Dict(Int, List(Int))) {
|
||||
case dict.get(rules, page) {
|
||||
Ok(before) -> distinct(processed, before)
|
||||
_ -> True
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that none of the needles are in the haystacks
|
||||
// i.e. none of the pages we need to print after have been processed
|
||||
fn distinct(haystack: List(Int), needles: List(Int)) -> Bool {
|
||||
haystack
|
||||
|> list.any(fn(elem) { needles |> contains(elem) })
|
||||
|> bool.negate
|
||||
}
|
||||
|
||||
fn middle(update: List(Int)) -> Int {
|
||||
case update {
|
||||
[elem] -> elem
|
||||
[_, ..rest] ->
|
||||
rest
|
||||
|> list.reverse
|
||||
|> list.drop(1)
|
||||
|> middle
|
||||
_ -> panic as "uneven list"
|
||||
}
|
||||
}
|
||||
|
||||
fn read_input(
|
||||
it: iterator.Iterator(String),
|
||||
) -> #(Dict(Int, List(Int)), List(List(Int))) {
|
||||
let #(rules_lines, update_lines) =
|
||||
it
|
||||
|> iterator.to_list
|
||||
|> map(string.trim)
|
||||
|> filter(not(string.is_empty))
|
||||
|> split_while(fn(s) { s |> string.contains("|") })
|
||||
|
||||
let rules =
|
||||
rules_lines
|
||||
|> map(parse_rule)
|
||||
|> collect_rules
|
||||
|
||||
let updates =
|
||||
update_lines
|
||||
|> map(parse_update)
|
||||
|
||||
#(rules, updates)
|
||||
}
|
||||
|
||||
fn parse_rule(str: String) -> #(Int, Int) {
|
||||
let assert Ok([a, b]) =
|
||||
str
|
||||
|> string.split(on: "|")
|
||||
|> map(int.parse)
|
||||
|> result.all
|
||||
|
||||
#(a, b)
|
||||
}
|
||||
|
||||
fn collect_rules(rules: List(#(Int, Int))) -> Dict(Int, List(Int)) {
|
||||
rules
|
||||
|> group(by: pair.first)
|
||||
|> dict.map_values(fn(_, v) { v |> map(pair.second) })
|
||||
}
|
||||
|
||||
fn parse_update(str: String) -> List(Int) {
|
||||
let assert Ok(list) =
|
||||
str
|
||||
|> string.split(",")
|
||||
|> map(int.parse)
|
||||
|> result.all
|
||||
|
||||
list
|
||||
}
|
||||
|
||||
fn not(a: fn(a) -> Bool) {
|
||||
fn(param: a) -> Bool { !a(param) }
|
||||
}
|
164
src/day5_p2.gleam
Normal file
164
src/day5_p2.gleam
Normal file
|
@ -0,0 +1,164 @@
|
|||
import gleam/bool
|
||||
import gleam/dict.{type Dict}
|
||||
import gleam/int
|
||||
import gleam/io
|
||||
import gleam/iterator
|
||||
import gleam/list.{contains, filter, fold, group, map, split_while}
|
||||
import gleam/pair
|
||||
import gleam/result
|
||||
import gleam/string
|
||||
import stdin.{stdin}
|
||||
|
||||
pub fn main() {
|
||||
stdin()
|
||||
|> read_input
|
||||
|> calculate
|
||||
|> io.debug
|
||||
}
|
||||
|
||||
fn calculate(input: #(Dict(Int, List(Int)), List(List(Int)))) {
|
||||
let #(rules, updates) = input
|
||||
|
||||
updates
|
||||
|> filter(fn(x) { is_valid([], x, rules) |> bool.negate })
|
||||
|> map(fn(seq) {
|
||||
seq
|
||||
|> fix(rules)
|
||||
|> middle
|
||||
})
|
||||
|> fold(0, int.add)
|
||||
}
|
||||
|
||||
fn fix(sequence: List(Int), rules: Dict(Int, List(Int))) -> List(Int) {
|
||||
fix_loop([], sequence, rules)
|
||||
}
|
||||
|
||||
fn fix_loop(
|
||||
sequence: List(Int),
|
||||
remaining: List(Int),
|
||||
rules: Dict(Int, List(Int)),
|
||||
) -> List(Int) {
|
||||
case remaining {
|
||||
[] -> sequence
|
||||
_ -> {
|
||||
// Find next applicable rule
|
||||
let assert Ok(next) =
|
||||
remaining
|
||||
|> map(fn(page) {
|
||||
case dict.get(rules, page) {
|
||||
Ok(before) -> #(page, before)
|
||||
_ -> #(page, [])
|
||||
}
|
||||
})
|
||||
|> list.find(fn(entry) {
|
||||
let #(_, after) = entry
|
||||
distinct(remaining, after)
|
||||
})
|
||||
|> result.map(pair.first)
|
||||
|
||||
let leftover = remaining |> filter(fn(page) { page != next })
|
||||
let updated_rules = rules |> remove_rule(next)
|
||||
|
||||
fix_loop([next, ..sequence], leftover, updated_rules)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_rule(rules: Dict(Int, List(Int)), page: Int) -> Dict(Int, List(Int)) {
|
||||
rules
|
||||
|> dict.map_values(fn(_, v) { v |> filter(fn(rule) { rule != page }) })
|
||||
|> dict.drop([page])
|
||||
}
|
||||
|
||||
fn is_valid(
|
||||
processed: List(Int),
|
||||
remaining: List(Int),
|
||||
rules: Dict(Int, List(Int)),
|
||||
) {
|
||||
case remaining {
|
||||
[] -> True
|
||||
[x] -> check_rules(processed, x, rules)
|
||||
[x, ..rest] ->
|
||||
check_rules(processed, x, rules)
|
||||
&& is_valid([x, ..processed], rest, rules)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_rules(processed: List(Int), page: Int, rules: Dict(Int, List(Int))) {
|
||||
case dict.get(rules, page) {
|
||||
Ok(before) -> distinct(processed, before)
|
||||
_ -> True
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that none of the needles are in the haystacks
|
||||
// i.e. none of the pages we need to print after have been processed
|
||||
fn distinct(haystack: List(Int), needles: List(Int)) -> Bool {
|
||||
haystack
|
||||
|> list.any(fn(elem) { needles |> contains(elem) })
|
||||
|> bool.negate
|
||||
}
|
||||
|
||||
fn middle(update: List(Int)) -> Int {
|
||||
case update {
|
||||
[elem] -> elem
|
||||
[_, ..rest] ->
|
||||
rest
|
||||
|> list.reverse
|
||||
|> list.drop(1)
|
||||
|> middle
|
||||
_ -> panic as "uneven list"
|
||||
}
|
||||
}
|
||||
|
||||
fn read_input(
|
||||
it: iterator.Iterator(String),
|
||||
) -> #(Dict(Int, List(Int)), List(List(Int))) {
|
||||
let #(rules_lines, update_lines) =
|
||||
it
|
||||
|> iterator.to_list
|
||||
|> map(string.trim)
|
||||
|> filter(not(string.is_empty))
|
||||
|> split_while(fn(s) { s |> string.contains("|") })
|
||||
|
||||
let rules =
|
||||
rules_lines
|
||||
|> map(parse_rule)
|
||||
|> collect_rules
|
||||
|
||||
let updates =
|
||||
update_lines
|
||||
|> map(parse_update)
|
||||
|
||||
#(rules, updates)
|
||||
}
|
||||
|
||||
fn parse_rule(str: String) -> #(Int, Int) {
|
||||
let assert Ok([a, b]) =
|
||||
str
|
||||
|> string.split(on: "|")
|
||||
|> map(int.parse)
|
||||
|> result.all
|
||||
|
||||
#(a, b)
|
||||
}
|
||||
|
||||
fn collect_rules(rules: List(#(Int, Int))) -> Dict(Int, List(Int)) {
|
||||
rules
|
||||
|> group(by: pair.first)
|
||||
|> dict.map_values(fn(_, v) { v |> map(pair.second) })
|
||||
}
|
||||
|
||||
fn parse_update(str: String) -> List(Int) {
|
||||
let assert Ok(list) =
|
||||
str
|
||||
|> string.split(",")
|
||||
|> map(int.parse)
|
||||
|> result.all
|
||||
|
||||
list
|
||||
}
|
||||
|
||||
fn not(a: fn(a) -> Bool) {
|
||||
fn(param: a) -> Bool { !a(param) }
|
||||
}
|
Loading…
Add table
Reference in a new issue