• 0 Posts
  • 9 Comments
Joined 2 years ago
cake
Cake day: June 10th, 2023

help-circle
  • Scheme/Guile

    I was stuck on part 3 for a while, for not taking account that a child scale that I’m evaluating may already be a parent scale in some group.

    (import (rnrs io ports (6))
            (srfi srfi-1))
    #!curly-infix
    
    (define (parse-file file-name)
      (let* ((lines (string-split (string-trim-both (call-with-input-file file-name get-string-all)) #\newline))
             (split-lines (map (lambda (l) (string-split l #\:)) lines))
             (parsed-lines (map (lambda (l) (cons (string->number (car l)) (string->list (cadr l)))) split-lines)))
        parsed-lines))
    
    (define (child-score child p1 p2 p1-sim p2-sim)
      (if (and-map null? (list child p1 p2))
          (* p1-sim p2-sim)
          (let ((matches-p1 (eq? (car child) (car p1)))
                (matches-p2 (eq? (car child) (car p2))))
            (cond
              ((not (or matches-p1 matches-p2)) #f)
              (else (child-score (cdr child) (cdr p1) (cdr p2) (+ p1-sim (if matches-p1 1 0)) (+ p2-sim (if matches-p2 1 0))))))))
    (let ((dna-lines (parse-file "notes/everybody_codes_e2025_q09_p1.txt")))
      (format #t "P1 Answer: ~a\n\n" (or
        (child-score (cdar dna-lines) (cdadr dna-lines) (cdaddr dna-lines) 0 0)
        (child-score (cdadr dna-lines) (cdar dna-lines) (cdaddr dna-lines) 0 0)
        (child-score (cdaddr dna-lines) (cdadr dna-lines) (cdar dna-lines) 0 0))))
    
    
    (let ((dna-lines (list->vector (parse-file "notes/everybody_codes_e2025_q09_p2.txt"))))
      (let loop ((child 0) (total-sim 0))
        (if {child < (vector-length dna-lines)}
            (loop (1+ child) (+ total-sim (let loop ((i 0))
              (cond
                ((eq? i child) (loop (1+ i)))
                ({i >= {(vector-length dna-lines) - 1}} 0)
                (else
                  (or
                    (let loop ((j (1+ i)))
                      (cond
                        ((eq? j child) (loop (1+ j)))
                        ({j >= (vector-length dna-lines)} #f)
                        (else (let ((res (child-score
                                   (cdr (vector-ref dna-lines child))
                                   (cdr (vector-ref dna-lines i))
                                   (cdr (vector-ref dna-lines j)) 0 0)))
                          (or res (loop (1+ j)))))))
                    (loop (1+ i))))))))
            (format #t "P2 Answer: ~a\n\n" total-sim))))
    
    
    (define (init-id-to-group dna-lines)
      (let ((table (make-hash-table)))
        (let loop ((i 0))
          (if {i < (vector-length dna-lines)}
              (let ((id (car (vector-ref dna-lines i))))
                (hash-set! table id id)
                (loop (1+ i)))
              table))))
    (define (init-group-to-ids dna-lines)
      (let ((table (make-hash-table)))
        (let loop ((i 0))
          (if {i < (vector-length dna-lines)}
              (let ((id (car (vector-ref dna-lines i))))
                (hash-set! table id (list id))
                (loop (1+ i)))
              table))))
    (let ((dna-lines (list->vector (parse-file "notes/everybody_codes_e2025_q09_p3.txt"))))
      (let ((id-to-group (init-id-to-group dna-lines)) (group-to-ids (init-group-to-ids dna-lines)))
      (let child-loop ((child 0))
        (if {child < (vector-length dna-lines)}
          (let i-loop ((i 0))
            (cond
              ((eq? i child) (i-loop (1+ i)))
              ({i >= {(vector-length dna-lines) - 1}} (child-loop (1+ child)))
              (else
                (let j-loop ((j (1+ i)))
                  (cond
                    ((eq? j child) (j-loop (1+ j)))
                    ({j >= (vector-length dna-lines)} (i-loop (1+ i)))
                    (else (let* ((cl (vector-ref dna-lines child))
                                 (pil (vector-ref dna-lines i))
                                 (pjl (vector-ref dna-lines j))
                                 (res (child-score (cdr cl) (cdr pil) (cdr pjl) 0 0)))
                      (if res
                          (let* ((i-group (hash-ref id-to-group (car pil)))
                                 (j-group (hash-ref id-to-group (car pjl)))
                                 (child-group (hash-ref id-to-group (car cl)))
                                 (i-group-ids (hash-ref group-to-ids i-group))
                                 (j-group-ids (hash-ref group-to-ids j-group))
                                 (child-group-ids (hash-ref group-to-ids child-group))
                                 (new-group-ids (delete-duplicates (append child-group-ids (or i-group-ids '()) (or j-group-ids '())))))
                            (map (lambda (id) (hash-set! id-to-group id child-group)) new-group-ids)
                            (hash-remove! group-to-ids i-group)
                            (hash-remove! group-to-ids j-group)
                            (hash-set! group-to-ids child-group new-group-ids)
                            (child-loop (1+ child)))
                          (j-loop (1+ j))))))))))
            (format #t "P3 Answer: ~a\n\n" (cdr (hash-fold
                    (lambda (_ id-list prior)
                            (let ((group-size (length id-list))
                                  (group-sum (apply + id-list)))
                              (if {group-size > (car prior)}
                                  (cons group-size group-sum)
                                  prior)))
                    (cons 0 0)
                    group-to-ids)))))))
    

  • Scheme/Guile

    Takes about 5 seconds.

    (import (rnrs io ports (6))
            (srfi srfi-1))
    #!curly-infix
    
    (define (parse-file file-name)
      (let ((sequence (map string->number (string-split (string-trim-both (call-with-input-file file-name get-string-all)) #\,))))
        (zip sequence (cdr sequence))))
    
    (let loop ((sequence (parse-file "notes/everybody_codes_e2025_q08_p1.txt")) (count 0))
      (if (null? sequence)
          (format #t "P1 Answer: ~a\n\n" count)
          (loop (cdr sequence) (+ count (if (and last (eq? (modulo (- (cadar sequence) (caar sequence)) 32) 16)) 1 0)))))
    
    (define (crosses-over? a b)
      (let ((a1 (car a))
            (a2 (cadr a))
            (b1 (car b))
            (b2 (cadr b)))
        (let ((a2 (modulo {a2 - a1} 256))
              (b1 (modulo {b1 - a1} 256))
              (b2 (modulo {b2 - a1} 256)))
          (and (not (eq? b1 0)) (not (eq? b2 0))
          (or
            (and {b1 < a2} {b2 > a2})
            (and {b1 > a2} {b2 < a2}))))))
    (define (count-cross-overs sequence a)
      (let loop ((sequence sequence) (count 0))
        (if (null? sequence)
            count
            (loop (cdr sequence) (+ count (if (crosses-over? (car sequence) a) 1 0))))))
    (let loop ((sequence (parse-file "notes/everybody_codes_e2025_q08_p2.txt")) (passed '()) (count 0))
      (if (null? sequence)
          (format #t "P2 Answer: ~a\n\n" count)
          (loop (cdr sequence) (cons (car sequence) passed) (+ count (count-cross-overs passed (car sequence))))))
    
    
    (let ((sequence (parse-file "notes/everybody_codes_e2025_q08_p3.txt")))
      (let loop ((i 1) (greatest 0))
        (if {i > 256}
            (format #t "P3 Answer: ~a\n\n" greatest)
            (loop (1+ i) (max greatest (let loop ((j i) (greatest 0))
                  (if {j > 256}
                      greatest
                      (loop (1+ j) (max greatest (count-cross-overs sequence (list i j)))))))))))
    

  • Scheme/Guile

    You could probably build a (letter, length) => combination-count mapping pretty quickly for part 3, but dealing with overlap in the input elements seems like a pain if handled this way.

    (import (rnrs io ports (6)))
    #!curly-infix
    
    (define (parse-file file-name) (let*
      ((lines (string-split (string-trim-both (call-with-input-file file-name get-string-all)) #\newline))
       (names (string-split (car lines) #\,))
       (rule-lines (cddr lines))
       (rules (map (lambda (l) (let*
                           ((sides (string-split l #\space))
                            (r-left (string-ref (car sides) 0))
                            (r-right (caddr sides)))
                           (cons r-left (map (lambda (x) (string-ref x 0)) (string-split r-right #\,))))) rule-lines)))
      (cons names rules)))
    
    (define (check-name rules name)
      (if (eq? 1 (string-length name))
          #t
          (let* ((letter (string-ref name 0))
                 (right (assq-ref rules letter))
                 (next-letter (string-ref name 1)))
            (if (memq next-letter right)
                (check-name rules (substring/read-only name 1))
                #f))))
    (let* ((parsed (parse-file "notes/everybody_codes_e2025_q07_p1.txt"))
           (names (car parsed))
           (rules (cdr parsed)))
      (let loop ((names names))
        (let* ((name (car names)) (name-matches (check-name rules name)))
          (if name-matches
              (format #t "P1 Answer: ~a\n\n" name)
              (loop (cdr names))))))
    
    
    (let* ((parsed (parse-file "notes/everybody_codes_e2025_q07_p2.txt"))
           (names (car parsed))
           (rules (cdr parsed)))
      (let loop ((i 1) (names names) (name-sum 0))
        (if (null? names)
            (format #t "P2 Answer: ~a\n\n" name-sum)
            (let* ((name (car names)) (name-matches (check-name rules name)))
              (loop (1+ i) (cdr names) (+ name-sum (if name-matches i 0)))))))
    
    
    (define discovered-prefixes (make-hash-table))
    (define (count-prefixes rules name)
      (if (hash-ref discovered-prefixes name)
          0
          (begin
            (hash-set! discovered-prefixes name #t)
            (if {(string-length name) >= 11}
                1
                (+
                  (apply + (map
                         (lambda (c) (count-prefixes rules (string-append name (string c))))
                         (or (assq-ref rules (string-ref name (1- (string-length name)))) '())))
                  (if {(string-length name) >= 7} 1 0))))))
    (let* ((parsed (parse-file "notes/everybody_codes_e2025_q07_p3.txt"))
           (names (car parsed))
           (rules (cdr parsed)))
      (let ((name-count (apply + (map (lambda (name) (count-prefixes rules name)) (filter (lambda (name) (check-name rules name)) names)))))
        (format #t "P3 Answer: ~a\n\n" name-count)))
    

  • Scheme/Guile

    Part 3 was a fun little challenge.

    (import (rnrs io ports (6)))
    #!curly-infix
    
    (define (parse-file file-name) (string-trim-both (call-with-input-file file-name get-string-all)))
    
    (let* ((line (parse-file "notes/everybody_codes_e2025_q06_p1.txt"))
           (line-length (string-length line)))
      (let loop ((i 0) (knight-count 0) (mentor-count 0))
        (if {i < line-length}
            (let ((letter (string-ref line i)))
              (loop (1+ i) (+ knight-count (if (eq? letter #\A) 1 0)) (+ mentor-count (if (eq? letter #\a) knight-count 0))))
            (format #t "P1 Answer: ~a\n\n" mentor-count))))
    
    (let* ((line (parse-file "notes/everybody_codes_e2025_q06_p2.txt"))
           (line-length (string-length line)))
      (let loop ((i 0) (knight-counts '()) (mentor-count 0))
        (if {i < line-length}
            (let ((letter (string-ref line i)))
              (loop
                (1+ i)
                (if (char-upper-case? letter) (assq-set! knight-counts letter (1+ (or (assq-ref knight-counts letter) 0))) knight-counts)
                (+ mentor-count (if (char-lower-case? letter) (or (assq-ref knight-counts (char-upcase letter)) 0) 0))))
            (format #t "P2 Answer: ~a\n\n" mentor-count))))
    
    
    (let* ((line (parse-file "notes/everybody_codes_e2025_q06_p3.txt"))
           (line-length (string-length line)))
      (let loop ((i 0) (mentor-count 0))
        (if {i < line-length}
            (let ((letter (string-ref line i)))
              (loop
                (1+ i)
                (+ mentor-count
                   (if (char-lower-case? letter)
                       (let loop ((j (- i 1000)) (mentors-here 0))
                         (if {j <= (+ i 1000)}
                             (loop
                               (1+ j)
                               (+ mentors-here
                                  (if {(string-ref line {j modulo line-length}) eq? (char-upcase letter)}
                                      (if (and {0 <= j} {j < line-length}) 1000 999)
                                      0)))
                             mentors-here))
                       0))))
            (format #t "P3 Answer: ~a\n\n" mentor-count))))
    

  • What a fiddlybit. I needed records to save me from list-hell on this one.

    Scheme/Guile

    (import (rnrs io ports (6))
            (rnrs records syntactic))
    
    (define (parse-file file-name)
      (let* ((lines (string-split (string-trim-both (call-with-input-file file-name get-string-all)) #\newline)))
        (map (lambda (line)
           (let* ((colon-split (string-split line #\:))
                 (segments (map string->number (string-split (cadr colon-split) #\,)))
                 (label (string->number (car colon-split))))
            (cons label segments)))
           lines)))
    
    (define-record-type fishbone-segment (fields middle left right))
    (define (construct-fishbone fishbone segments)
      (if (null? segments)
          fishbone
          (let ((fishbone (add-fishbone-segment fishbone (car segments))))
            (construct-fishbone fishbone (cdr segments)))))
    (define (add-fishbone-segment fishbone segment)
      (if (null? fishbone)
          (list (make-fishbone-segment segment #f #f))
          (let* ((fish-head (car fishbone))
                 (fish-middle (fishbone-segment-middle fish-head))
                 (fish-left (fishbone-segment-left fish-head))
                 (fish-right (fishbone-segment-right fish-head)))
            (cond
              ((and (< segment fish-middle) (not fish-left)) (cons (make-fishbone-segment fish-middle segment fish-right) (cdr fishbone)))
              ((and (> segment fish-middle) (not fish-right)) (cons (make-fishbone-segment fish-middle fish-left segment) (cdr fishbone)))
              (else (cons fish-head (add-fishbone-segment (cdr fishbone) segment)))))))
    (define (score-fishbone fishbone)
      (string->number (string-join (map (compose number->string fishbone-segment-middle) fishbone) "")))
    
    (define-record-type sword (fields id fishbone quality))
    (define (parse-swords file-name)
      (map (lambda (sword-line)
              (let ((fishbone (construct-fishbone '() (cdr sword-line))))
                (make-sword (car sword-line) fishbone (score-fishbone fishbone))))
        (parse-file file-name)))
    
    (format #t "P1 Answer: ~a\n\n" (sword-quality (car (parse-swords "notes/everybody_codes_e2025_q05_p1.txt"))))
    
    (let* ((swords (parse-swords "notes/everybody_codes_e2025_q05_p2.txt"))
           (sword-scores (map sword-quality swords)))
      (format #t "P2 Answer: ~a\n\n" (- (apply max sword-scores) (apply min sword-scores))))
    
    
    (define (segment-score segment)
      (string->number
        (string-join
         (map (lambda (n) (if (eqv? #f n) "" (number->string n)))
          (list (fishbone-segment-left segment) (fishbone-segment-middle segment) (fishbone-segment-right segment)))
         "")))
    (define (sort-fishbones a b)
      (if (null? a) '()
      (let ((line-score-a (segment-score (car a)))
            (line-score-b (segment-score (car b))))
        (cond
          ((> line-score-a line-score-b) #t)
          ((< line-score-a line-score-b) #f)
          (else (sort-fishbones (cdr a) (cdr b)))))))
    (define (sort-swords a b)
      (cond
        ((> (sword-quality a) (sword-quality b)) #t)
        ((< (sword-quality a) (sword-quality b)) #f)
        (else (let ((fb-sort (sort-fishbones (sword-fishbone a) (sword-fishbone b))))
          (cond
            ((null? fb-sort) (> (sword-id a) (sword-id b)))
            (else fb-sort))))))
    (let* ((swords (parse-swords "notes/everybody_codes_e2025_q05_p3.txt"))
           (sorted-swords (sort swords sort-swords))
           (swords-length (length swords)))
      (let loop ((i 1) (total 0) (sorted-swords sorted-swords))
        (if (<= i swords-length)
            (loop (1+ i) (+ total (* i (sword-id (car sorted-swords)))) (cdr sorted-swords))
            (format #t "P2 Answer: ~a\n\n" total))))
    

  • maaath

    Scheme/Guile

    (import (rnrs io ports (6)))
    
    (define (parse-file file-name)
           (map string->number (string-split (call-with-input-file file-name get-string-all) #\newline)))
    
    (let* ((gears (parse-file "notes/everybody_codes_e2025_q04_p1.txt")))
      (format #t "P1 Answer: ~a\n\n" (* 2025 (/ (car gears) (car (last-pair gears))))))
    
    
    (let* ((gears (parse-file "notes/everybody_codes_e2025_q04_p2.txt")))
      (format #t "P2 Answer: ~a\n\n" (ceiling (* 10000000000000 (/ (car (last-pair gears)) (car gears))))))
    
    
    (define (parse-file-p3 file-name)
           (map
                  (lambda (line) (map string->number(string-split line #\|)))
                  (string-split (call-with-input-file file-name get-string-all) #\newline)))
    (let* ((gears (parse-file-p3 "notes/everybody_codes_e2025_q04_p3.txt")))
      (format #t "P2 Answer: ~a\n\n"
              (floor (* 100
                 (apply * (map (lambda (gear) (if (= 1 (length gear)) 1 (/ (cadr gear) (car gear)))) gears))
                 (/ (caar gears) (caar (last-pair gears)))))))
    

  • Scheme/Guile

    Guile doesn’t seem to come with a bag implementation :(. Not a big deal, a linear scan works about as well.

    (use-modules (ice-9 rdelim))
    (use-modules (srfi srfi-1))
    
    (define (parse-file file-name)
      (let* ((p (open-input-file file-name))
            (comma-split (string-split (read-line p) #\,))
            (number-list (map string->number comma-split)))
        number-list))
    
    (let* ((crates (parse-file "notes/everybody_codes_e2025_q03_p1.txt"))
           (dedup-crates (delete-duplicates crates)))
      (format #t "P1 Answer: ~a\n\n" (apply + dedup-crates)))
    
    
    (let* ((crates (parse-file "notes/everybody_codes_e2025_q03_p2.txt"))
           (dedup-crates (delete-duplicates crates))
           (sorted-crates (sort dedup-crates <)))
      (format #t "P2 Answer: ~a\n\n" (apply + (take sorted-crates 20))))
    
    
    (let* ((crates (parse-file "notes/everybody_codes_e2025_q03_p3.txt"))
           (sorted-crates (sort crates <))
           (largest-set-size (let loop ((count 0) (l sorted-crates) (c #f) (max-count 0))
             (if (nil? l)
                 max-count
                 (let* ((new-c (car l))
                        (new-count (if (equal? new-c c) (+ count 1) 1)))
                   (loop new-count (cdr l) new-c (max new-count max-count)))))))
      (format #t "P3 Answer: ~a\n\n" largest-set-size))
    

  • I was stuck for a while on part 2. I thought I was running into precision errors, so I re-implemented everything using exact integers, then I re-implemented it in python, but it turns out that I just had an off-by-1 error. It just so happened that my off-by-1 algorithm gave the correct solution to the sample input. Part 3 takes a while to compute.

    Scheme/Guile

    (use-modules (ice-9 rdelim))
    (use-modules (ice-9 format))
    (use-modules (srfi srfi-1))
    
    (define (parse-file file-name)
      (let* ((p (open-input-file file-name))
            (equality-split (string-split (read-line p) #\=))
            (complex-str (list-ref equality-split 1))
            (complex-parts (map string->number (string-split
              (substring/read-only complex-str 1 (- (string-length complex-str) 1))
              #\,))))
        (+ (car complex-parts) (* 0+1i (list-ref complex-parts 1)))))
    (define (special-div numerator divisor)
      (+
        (truncate/ (real-part numerator) (real-part divisor))
        (* 0+1i (truncate/ (imag-part numerator) (imag-part divisor)))))
    
    (let* ((A (parse-file "notes/everybody_codes_e2025_q02_p1.txt")))
      (format #t "Input is ~a\n" A)
      (let loop ((R 0+0i) (i 3))
        (if (> i 0)
          (loop (+ (special-div (* R R) 10+10i) A) (- i 1))
          (format #t "P1 Answer: [~d,~a]\n\n"
                  (inexact->exact (real-part R))
                  (inexact->exact (imag-part R))))))
    
    
    (define (check-engrave-range value)
      (and-map (lambda (x) (<= (abs x) 1000000)) (list (real-part value) (imag-part value))))
    (define (check-engrave point)
      (let loop ((result 0+0i) (i 100))
        (if (and (> i 0) (check-engrave-range result))
          (loop (+ point (special-div (* result result) 100000+100000i)) (- i 1))
          (check-engrave-range result))))
    (let* ((origin (parse-file "notes/everybody_codes_e2025_q02_p2.txt"))
           (engrave-count 0))
      (format #t "Input is ~a\n" origin)
      (let loop ((i 0))
        (if (<= i 1000) (begin
          (let loop ((j 0))
            (if (<= j 1000) (begin
              (set! engrave-count (+ engrave-count
                                     (if (check-engrave (+ origin (+ i (* j 0+1i)))) 1 0)))
              (loop (+ j 10)))))
          (loop (+ i 10)))))
      (format #t "P2 answer: ~a\n\n" engrave-count))
    
    
    (let* ((origin (parse-file "notes/everybody_codes_e2025_q02_p3.txt"))
           (engrave-count 0))
      (format #t "Input is ~a\n" origin)
      (let loop ((i 0))
        (if (<= i 1000) (begin
          (let loop ((j 0))
            (if (<= j 1000) (begin
              (set! engrave-count
                    (+ engrave-count (if (check-engrave (+ origin (+ i (* j 0+1i)))) 1 0)))
              (loop (+ j 1)))))
          (loop (+ i 1)))))
      (format #t "P3 answer: ~a\n\n" engrave-count))
    

  • I’m still learning Scheme, but I wrote a solution in Guile:

    (use-modules (ice-9 rdelim ))
    (use-modules (srfi srfi-1))
    
    (define (parse-step s) (*
        (if (eq? (string-ref s 0) #\L) -1 1)
        (string->number (substring s 1))
    ))
    (define (parse-file file-name) (begin
      (define p (open-input-file file-name))
      (define names-str (read-line p))
      (read-line p)
      (define steps-str (read-line p))
      (cons
        (string-split names-str #\,)
        (map parse-step (string-split steps-str #\,))
      )
    ))
    
    (let* ((parsed-file (parse-file "notes/everybody_codes_e2025_q01_p1.txt"))
           (names (car parsed-file))
           (steps (cdr parsed-file)))
      (format #t "names: ~a\nsteps: ~a\n" names steps)
      (define name-count (length names))
      (define chosen-name-idx (reduce
        (lambda (pos change) (max 0 (min (- name-count 1) (+ pos change))))
        0 steps))
      (format #t "P1: Chosen name(~a): ~a\n\n" chosen-name-idx (list-ref names chosen-name-idx))
    )
    
    (let* ((parsed-file (parse-file "notes/everybody_codes_e2025_q01_p2.txt"))
           (names (car parsed-file))
           (steps (cdr parsed-file)))
      (format #t "names: ~a\nsteps: ~a\n" names steps)
      (define name-count (length names))
      (define chosen-name-idx (modulo (reduce + 0 steps) name-count))
      (format #t "P2: Chosen name(~a): ~a\n\n" chosen-name-idx (list-ref names chosen-name-idx))
    )
    
    (let* ((parsed-file (parse-file "notes/everybody_codes_e2025_q01_p3.txt"))
           (names (list->vector (car parsed-file)))
           (steps (cdr parsed-file)))
      (format #t "names: ~a\nsteps: ~a\n" names steps)
      (define name-count (vector-length names))
      (for-each (lambda (s)
          (define head (vector-ref names 0))
          (define swap-pos (modulo s name-count))
          (vector-set! names 0 (vector-ref names swap-pos))
          (vector-set! names swap-pos head)
        ) steps)
      (format #t "P3: Chosen name: ~a\n" (vector-ref names 0))
    )