aboutsummaryrefslogtreecommitdiff
path: root/aoc2023/src/day5
diff options
context:
space:
mode:
authorJ.J <thechairman@thechairman.info>2023-12-05 04:02:04 -0500
committerJ.J <thechairman@thechairman.info>2023-12-05 04:02:04 -0500
commitc5ebc0002aa6842e830e21701168df7d829a44db (patch)
tree96927a149c6cfcdce09ff0cf3932364dd75fe866 /aoc2023/src/day5
parente3fc8bc189f87e2d42c54e340404fbcfd1e64f65 (diff)
downloadgleam_aoc-c5ebc0002aa6842e830e21701168df7d829a44db.tar.gz
gleam_aoc-c5ebc0002aa6842e830e21701168df7d829a44db.zip
day 5 reorganizing/refactoring
Diffstat (limited to 'aoc2023/src/day5')
-rw-r--r--aoc2023/src/day5/solve.gleam112
1 files changed, 55 insertions, 57 deletions
diff --git a/aoc2023/src/day5/solve.gleam b/aoc2023/src/day5/solve.gleam
index aba405d..7a0fe33 100644
--- a/aoc2023/src/day5/solve.gleam
+++ b/aoc2023/src/day5/solve.gleam
@@ -6,11 +6,13 @@ import gleam/list.{Continue, Stop}
import gleam/int
import gleam/function
+// Types -------------------------------------------------------------------------------------------
+
pub type Almanac {
Almanac(seeds: List(Int), mappers: List(Mapper))
}
-pub type MRange {
+pub type MappingRange {
MRange(start: Int, end: Int, offset: Int)
}
@@ -19,14 +21,9 @@ pub type SeedRange {
}
type Mapper =
- List(MRange)
+ List(MappingRange)
-fn string_to_int_list(str: String) {
- str
- |> string.split(on: " ")
- |> list.map(int.parse)
- |> result.values
-}
+// Parsing -----------------------------------------------------------------------------------------
fn parse_input(input: String) {
let ["seeds: " <> raw_seeds, ..raw_mappers] = string.split(input, on: "\n\n")
@@ -40,23 +37,33 @@ fn parse_input(input: String) {
Almanac(seeds, mappers)
}
+fn string_to_int_list(str: String) {
+ str
+ |> string.split(on: " ")
+ |> list.map(int.parse)
+ |> result.values
+}
+
fn parse_mapper(strs: List(String)) -> Mapper {
let [_, ..raw_ranges] = strs
list.map(raw_ranges, parse_mrange)
- |> list.sort(compare_mranges)
+ |> list.sort(fn(a, b) { int.compare(a.start, b.start) })
}
-fn parse_mrange(str: String) -> MRange {
+fn parse_mrange(str: String) -> MappingRange {
let assert [destination, source, range_width] = string_to_int_list(str)
MRange(source, source + range_width - 1, destination - source)
}
-fn compare_mranges(mrange1: MRange, mrange2: MRange) {
- int.compare(mrange1.start, mrange2.start)
-}
+// Part 1 ------------------------------------------------------------------------------------------
-fn is_in_mrange(n: Int, mrange: MRange) {
- mrange.start <= n && n <= mrange.end
+pub fn part1(input: String) {
+ let Almanac(seeds, mappers) = parse_input(input)
+
+ list.map(seeds, list.fold(over: mappers, from: _, with: correspond))
+ |> list.reduce(int.min)
+ |> result.unwrap(0)
+ |> string.inspect
}
fn correspond(n: Int, mapper: Mapper) {
@@ -64,7 +71,7 @@ fn correspond(n: Int, mapper: Mapper) {
over: mapper,
from: n,
with: fn(acc, mrange) {
- case is_in_mrange(acc, mrange) {
+ case mrange.start <= acc && acc <= mrange.end {
True -> Stop(acc + mrange.offset)
False -> Continue(acc)
}
@@ -72,19 +79,42 @@ fn correspond(n: Int, mapper: Mapper) {
)
}
-pub fn part1(input: String) {
+// Part 2 ------------------------------------------------------------------------------------------
+
+pub fn part2(input: String) {
let Almanac(seeds, mappers) = parse_input(input)
- list.map(seeds, list.fold(over: mappers, from: _, with: correspond))
- |> list.reduce(int.min)
- |> result.unwrap(0)
- |> string.inspect
+ let [SRange(answer, _), ..] =
+ seeds
+ |> list.sized_chunk(into: 2)
+ |> list.map(fn(chunk) {
+ let [start, length] = chunk
+ [SRange(start, start + length - 1)]
+ |> remap_all_seed_ranges(mappers)
+ })
+ |> list.flatten()
+ |> list.sort(fn(a, b) { int.compare(a.start, b.start) })
+
+ string.inspect(answer)
+}
+
+fn remap_all_seed_ranges(srs: List(SeedRange), mappers: List(Mapper)) {
+ case mappers {
+ [] -> srs
+ [mapper, ..rest] ->
+ list.flat_map(srs, remap_range(_, mapper))
+ |> remap_all_seed_ranges(rest)
+ }
}
fn remap_range(r: SeedRange, mapper: Mapper) -> List(SeedRange) {
do_remap_range(r, mapper, [])
}
+fn transform_range(r: SeedRange, mapper: MappingRange) -> SeedRange {
+ SRange(r.start + mapper.offset, r.end + mapper.offset)
+}
+
fn do_remap_range(r: SeedRange, mapper: Mapper, acc: List(SeedRange)) {
case mapper {
// no more mappings -> no mapping covers this range
@@ -95,13 +125,13 @@ fn do_remap_range(r: SeedRange, mapper: Mapper, acc: List(SeedRange)) {
[m, ..ms] if r.start > m.end -> do_remap_range(r, ms, acc)
// range is fully inside mapping -> range is transformed
[m, ..] if r.start >= m.start && r.end <= m.end -> [
- SRange(r.start + m.offset, r.end + m.offset),
+ transform_range(r, m),
..acc
]
// range overlaps start but not end -> left side not transformed, right side transformed
[m, ..] if r.start < m.start && r.end <= m.end -> [
SRange(r.start, m.start - 1),
- SRange(m.start + m.offset, r.end + m.offset),
+ transform_range(SRange(m.start, r.end), m),
..acc
]
// range overlaps end but not start -> left side transformed, right side moves to next mapping
@@ -109,7 +139,7 @@ fn do_remap_range(r: SeedRange, mapper: Mapper, acc: List(SeedRange)) {
do_remap_range(
SRange(m.end + 1, r.end),
ms,
- [SRange(r.start + m.offset, m.end + m.offset), ..acc],
+ [transform_range(SRange(r.start, m.end), m), ..acc],
)
// mapping is fully inside range -> left not transformed, middle transformed, right to next
[m, ..ms] ->
@@ -118,45 +148,13 @@ fn do_remap_range(r: SeedRange, mapper: Mapper, acc: List(SeedRange)) {
ms,
[
SRange(r.start, m.start - 1),
- SRange(m.start + m.offset, m.end + m.offset),
+ transform_range(SRange(m.start, m.end), m),
..acc
],
)
}
}
-fn remap_all_seed_ranges(srs: List(SeedRange), mappers: List(Mapper)) {
- case mappers {
- [] -> srs
- [mapper, ..rest] ->
- list.flat_map(srs, remap_range(_, mapper))
- |> remap_all_seed_ranges(rest)
- }
-}
-
-fn compare_ranges(range1: SeedRange, range2: SeedRange) {
- int.compare(range1.start, range2.start)
-}
-
-pub fn part2(input: String) {
- let Almanac(seeds, mappers) = parse_input(input)
-
- let [SRange(answer, _), ..] =
- seeds
- |> list.sized_chunk(into: 2)
- |> list.map(fn(chunk) {
- let [start, length] = chunk
- [SRange(start, start + length - 1)]
- |> remap_all_seed_ranges(mappers)
- })
- |> list.flatten()
- |> list.unique()
- |> list.sort(compare_ranges)
- |> io.debug()
-
- string.inspect(answer)
-}
-
pub fn main() {
let assert Ok(part) = adglent.get_part()
let assert Ok(input) = adglent.get_input("5")