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

  • VegOwOtenks@lemmy.world
    link
    fedilink
    arrow-up
    2
    ·
    2 days 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 ]