Day 2: Gift Shop

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

FAQ

you are viewing a single comment's thread
view the rest of the comments
[โ€“] 2 points 11 months ago

Futhark

I translated my Haskell solution to Futhark, basically. It runs abysmally faster.

The syntax highlighting is likely very off, because the closest language highlighter I could find was ocaml.

def fst 'a 'b ((a, _b): (a, b)): a = a
def snd 'a 'b ((_a, b): (a, b)): b = b
def (>>>) 'a 'b 'c (f: a -> b) (g: b -> c) (x: a): c = g (f x)
def (|) '^a 'b (f: a -> b) (x: a): b = f x -- $ is not allowed
def even (x: i64): bool = x % 2 == 0

def digitCount (x: i64): i64
  = snd | 
      loop (i, len) = (x, 0)
      while i != 0
      do (i / 10, len + 1)

def digitAt (n: i64) (i: i64): i64 = (n / 10 ** i) % 10

def keepTrue (p: i64 -> bool) (x: i64): i64
  = if p x
      then x
      else 0

def tup2RangeArray ((start, end): (i64, i64)): []i64
  = (start ... end)

def sumInvalidIds (p: i64 -> bool) (rangeTup: (i64, i64)): i64 
  = let range = tup2RangeArray rangeTup in
  reduce (+) 0 (map (keepTrue p) range)

def tup2FromArray 'a (as: [2]a): (a, a) = (as[0], as[1])

def impl (p: i64 -> bool) (ranges: [](i64, i64)): i64 
  = reduce (+) 0 (map (sumInvalidIds p) ranges)

def withValidRepeatOffsets (nDigits: i64) (f: i64 -> bool): bool
  = match nDigits
    case 2  -> map f >>> or | [1]
    case 3  -> map f >>> or | [1]
    case 4  -> map f >>> or | [1, 2]
    case 5  -> map f >>> or | [1]
    case 6  -> map f >>> or | [1, 2, 3]
    case 7  -> map f >>> or | [1]
    case 8  -> map f >>> or | [1, 2, 4]
    case 9  -> map f >>> or | [1, 3]
    case 10 -> map f >>> or | [1, 2, 5]
    case 11 -> map f >>> or | [1]
    case 12 -> map f >>> or | [1, 2, 3, 4, 6]
    case _ -> false

def isValid2 (x: i64): bool = 
  let len = digitCount x in
  let lookupDigit = digitAt x in
  withValidRepeatOffsets len | \ repeatOffset ->
    let repeatCount = len / repeatOffset in
    let digitIndices = (0..< repeatOffset) in
    let repeatIndices = (0..<repeatCount) in
    and | 
      map (\ digitIndex -> 
        and |
          map (\ repeatIndex -> 
            let expectedDigit = lookupDigit digitIndex in
            let actualDigit   = lookupDigit | repeatIndex * repeatOffset + digitIndex in
            expectedDigit == actualDigit
          ) 
          repeatIndices
      ) digitIndices

def part2 : [](i64, i64) -> i64 = impl isValid2 

def isValid1 (x: i64): bool = 
  let len = digitCount x in
  let halfLength = len / 2 in
  let first = x / 10 ** halfLength in
  let second = x % 10 ** halfLength in
  even len && first == second

def part1 : [](i64, i64) -> i64 = impl isValid1 

def main (rangeArrays: [][2]i64) 
  = let rangeTuples = map tup2FromArray rangeArrays in
    (part1 rangeTuples, part2 rangeTuples)

Sed-Script to Transform input for Futhark

i [
s/\([0-9]\+\)-\([0-9]\+\)/\[\1, \2]/g
a ]

  • source