aoc-all

My solutions to all Advent of Code
git clone https://git.instinctive.eu/aoc-all.git
Log | Files | Refs | README | LICENSE

day05.nim (2296B)


      1 # Copyright (c) 2024, Natacha Porté
      2 #
      3 # Permission to use, copy, modify, and distribute this software for any
      4 # purpose with or without fee is hereby granted, provided that the above
      5 # copyright notice and this permission notice appear in all copies.
      6 #
      7 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      8 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      9 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     10 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     11 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     12 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     13 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     14 
     15 from std/sequtils import allIt, count, deduplicate, filterIt, foldl, map, mapIt, toSeq, concat
     16 from std/strutils import parseInt, split
     17 
     18 # Read input file
     19 
     20 func process_input(s: seq[string], sep: string): seq[seq[int]] =
     21   s.mapIt(it.split(sep)).filterIt(it.len() >= 2).mapIt(it.map(parseInt))
     22 
     23 func listmax(s: seq[int]): int = s.foldl(max(a, b))
     24 func listmin(s: seq[int]): int = s.foldl(min(a, b))
     25 
     26 let
     27   raw_data = stdin.lines().toSeq()
     28   part1 = process_input(raw_data, "|")
     29   part2 = process_input(raw_data, ",")
     30   smallest = min(part1.map(listmin).listmin(), part2.map(listmin).listmin())
     31   largest = max(part1.map(listmax).listmax(), part2.map(listmax).listmax())
     32 
     33 # Puzzle 1
     34 
     35 var needs: seq[seq[int]]
     36 
     37 for i in 0 .. largest:
     38   needs.add(part1.filterIt(it[1] == i).mapIt(it[0]))
     39 
     40 proc is_ordered(s: seq[int]): bool =
     41   len(s) < 2 or
     42   (s[1 .. ^1].allIt(needs[s[0]].count(it) == 0) and is_ordered(s[1 .. ^1]))
     43 
     44 proc score1(s: seq[int]): int =
     45   if is_ordered(s):
     46     result = s[(len(s)-1) div 2]
     47 
     48 echo "Puzzle 1: ", part2.map(score1).foldl(a + b)
     49 
     50 # Puzzle 2
     51 
     52 proc local_min(s: seq[int]): int =
     53   result = -1
     54   for i in 0 ..< len(s):
     55     if s.allIt(needs[s[i]].count(it) == 0):
     56       return s[i]
     57 
     58 proc local_sort(s: seq[int]): seq[int] =
     59   if len(s) < 2:
     60     return s
     61   else:
     62     let m = local_min(s)
     63     result = local_sort(s.filterIt(it != m))
     64     result.add(m)
     65 
     66 proc score2(s: seq[int]): int =
     67   if not is_ordered(s):
     68     let s2 = local_sort(s)
     69     result = s2[(len(s2) - 1) div 2]
     70 
     71 echo "Puzzle 2: ", part2.map(score2).foldl(a + b)