├── inputs ├── day01.test2 ├── day05.test1 ├── day01.test1 ├── day08.test1 ├── day03.test1 ├── day02.test2 ├── day02.test1 └── day04.test1 ├── day01a ├── aoc ├── rect.sld └── rect.scm ├── day01b ├── day02a ├── day02b ├── day03 └── day08 /inputs/day01.test2: -------------------------------------------------------------------------------- 1 | +1 -1 2 | -------------------------------------------------------------------------------- /inputs/day05.test1: -------------------------------------------------------------------------------- 1 | dabAcCaCBAcCcaDA 2 | -------------------------------------------------------------------------------- /inputs/day01.test1: -------------------------------------------------------------------------------- 1 | +1 2 | -2 3 | +3 4 | +1 5 | -------------------------------------------------------------------------------- /inputs/day08.test1: -------------------------------------------------------------------------------- 1 | 2 3 0 3 10 11 12 1 1 0 1 99 2 1 1 2 2 | -------------------------------------------------------------------------------- /inputs/day03.test1: -------------------------------------------------------------------------------- 1 | #1 @ 1,3: 4x4 2 | #2 @ 3,1: 4x4 3 | #3 @ 5,5: 2x2 4 | -------------------------------------------------------------------------------- /inputs/day02.test2: -------------------------------------------------------------------------------- 1 | abcde 2 | fghij 3 | klmno 4 | pqrst 5 | fguij 6 | axcye 7 | wvxyz 8 | -------------------------------------------------------------------------------- /inputs/day02.test1: -------------------------------------------------------------------------------- 1 | abcdef 2 | bababc 3 | abbcde 4 | abcccd 5 | aabcdd 6 | abcdee 7 | ababab 8 | -------------------------------------------------------------------------------- /day01a: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env -S chibi-scheme -q 2 | ; vim:set ft=scheme: 3 | 4 | (import (chibi io)) ;; port-fold 5 | 6 | (display (port-fold + 0 read)) 7 | (newline) 8 | -------------------------------------------------------------------------------- /aoc/rect.sld: -------------------------------------------------------------------------------- 1 | ; vim:set ft=scheme: 2 | 3 | (define-library 4 | (aoc rect) 5 | (export rect rect? 6 | rect-x rect-y rect-w rect-h 7 | rect-l rect-t rect-r rect-b 8 | rect-area 9 | rect-intersect? 10 | rect-intersection) 11 | (import (scheme base) 12 | (srfi 95) 13 | (srfi 145)) 14 | (include "rect.scm")) 15 | 16 | -------------------------------------------------------------------------------- /inputs/day04.test1: -------------------------------------------------------------------------------- 1 | [1518-11-01 00:00] Guard #10 begins shift 2 | [1518-11-01 00:05] falls asleep 3 | [1518-11-01 00:25] wakes up 4 | [1518-11-01 00:30] falls asleep 5 | [1518-11-01 00:55] wakes up 6 | [1518-11-01 23:58] Guard #99 begins shift 7 | [1518-11-02 00:40] falls asleep 8 | [1518-11-02 00:50] wakes up 9 | [1518-11-03 00:05] Guard #10 begins shift 10 | [1518-11-03 00:24] falls asleep 11 | [1518-11-03 00:29] wakes up 12 | [1518-11-04 00:02] Guard #99 begins shift 13 | [1518-11-04 00:36] falls asleep 14 | [1518-11-04 00:46] wakes up 15 | [1518-11-05 00:03] Guard #99 begins shift 16 | [1518-11-05 00:45] falls asleep 17 | [1518-11-05 00:55] wakes up 18 | -------------------------------------------------------------------------------- /day01b: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env -S chibi-scheme -q 2 | ; vim:ft=scheme: 3 | 4 | (import (chibi io) 5 | (scheme set)) 6 | 7 | 8 | (define (find-calibration-frequency change-list) 9 | (define (run-list cur-freq seen-freqs items) 10 | (if (null? items) 11 | (run-list cur-freq seen-freqs change-list) ; Restart list. 12 | (if (set-contains? seen-freqs cur-freq) 13 | cur-freq ; Found! 14 | (run-list (+ cur-freq (car items)) 15 | (set-adjoin! seen-freqs cur-freq) 16 | (cdr items))))) 17 | (run-list 0 (set =) change-list)) 18 | 19 | 20 | (display (find-calibration-frequency 21 | (port->list read (current-input-port)))) 22 | (newline) 23 | -------------------------------------------------------------------------------- /aoc/rect.scm: -------------------------------------------------------------------------------- 1 | ; vim:ft=scheme: 2 | 3 | (define-record-type Rect 4 | (rect x y w h) 5 | rect? 6 | (x rect-x) 7 | (y rect-y) 8 | (w rect-w) 9 | (h rect-h)) 10 | 11 | ; Convenience (left, right, top, bottom) accessors. 12 | ; 13 | (define (rect-r r) 14 | (assume '(rect? r)) 15 | (+ (rect-x r) (rect-w r))) 16 | 17 | (define (rect-b r) 18 | (assume (rect? r)) 19 | (+ (rect-y r) (rect-h r))) 20 | 21 | (define (rect-l r) 22 | (assume (rect? r)) 23 | (+ 1 (rect-x r))) 24 | 25 | (define (rect-t r) 26 | (assume (rect? r)) 27 | (+ 1 (rect-y r))) 28 | 29 | ; Calculate area of a rectangle. 30 | ; 31 | (define (rect-area r) 32 | (assume (rect? r)) 33 | (* (rect-w r) (rect-h r))) 34 | 35 | ; Do two rectangles intersect? 36 | ; 37 | (define (rect-intersect? r o) 38 | (assume (rect? r)) 39 | (assume (rect? o)) 40 | (not (or (> (rect-l o) (rect-r r)) 41 | (< (rect-r o) (rect-l r)) 42 | (> (rect-t o) (rect-b r)) 43 | (< (rect-b o) (rect-t r))))) 44 | 45 | ; Find the intersection rectangle. 46 | ; 47 | (define (rect-intersection r o) 48 | (assume (rect? r)) 49 | (assume (rect? o)) 50 | (let ((h (sort! (list (rect-l r) (rect-r r) (rect-l o) (rect-r o)) <)) 51 | (v (sort! (list (rect-t r) (rect-b r) (rect-t o) (rect-b o)) <))) 52 | (rect (car h) 53 | (car v) 54 | (- (cadr h) (car h)) 55 | (- (cadr v) (car v))))) 56 | -------------------------------------------------------------------------------- /day02a: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env -S chibi-scheme -q 2 | ; vim:set ft=scheme: 3 | 4 | (import (chibi io) 5 | (scheme hash-table) 6 | (scheme list)) 7 | 8 | 9 | ; Takes an identified (string), and analyzes whether: 10 | ; 11 | ; - a = It contains any letter twice. 12 | ; - b = It contains any letter thrice. 13 | ; 14 | ; Then it returns a pair (bool . bool) with (a . b). 15 | ; 16 | (define (analyze-id id) 17 | (let* ((char-counts (make-hash-table eq?)) 18 | (visit-char (lambda (char) 19 | (hash-table-update!/default char-counts 20 | char 21 | (lambda (v) (+ v 1)) 22 | 0)))) 23 | (for-each visit-char (string->list id)) 24 | (hash-table-fold char-counts 25 | (lambda (char count result) 26 | (cons (or (car result) 27 | (= count 2)) 28 | (or (cdr result) 29 | (= count 3)))) 30 | (cons #f #f)))) 31 | 32 | 33 | ; This applies "analyze-id" to each element in the input using 34 | ; "port-map" to obtain a list of (bool . bool) items, and then 35 | ; "fold" over than to turn the list into a pair (num . num) with 36 | ; the count of items which have the same letter twice and thrice. 37 | ; 38 | (define counts (fold (lambda (pair result) 39 | (cons (if (car pair) (+ (car result) 1) (car result)) 40 | (if (cdr pair) (+ (cdr result) 1) (cdr result)))) 41 | (cons 0 0) 42 | (port-map (lambda (sym) (analyze-id (symbol->string sym))) 43 | read))) 44 | 45 | 46 | ; Finally, the checksum is just the multiplication of the counts. 47 | ; 48 | (display (* (car counts) (cdr counts))) 49 | (newline) 50 | -------------------------------------------------------------------------------- /day02b: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env -S chibi-scheme -q 2 | ; vim:set ft=scheme: 3 | 4 | (import (chibi io) 5 | (scheme list) 6 | (scheme set)) 7 | 8 | 9 | ; Given two identifiers "a" and "b", determine whether they are 10 | ; similar: their lengths must match, and they must differ only 11 | ; in one character at the same position. To figure out the second, 12 | ; iterate elements of both lists of characters at the same time 13 | ; (with "zip") and "count" those items for which both characters 14 | ; are the same; if both are similar, the count of different chars 15 | ; must be exactly one. 16 | ; 17 | (define (similar-ids? a b) 18 | (and (= (string-length a) (string-length b)) 19 | (= 1 (count (lambda (pair) (not (eq? (car pair) (cadr pair)))) 20 | (zip (string->list a) (string->list b)))))) 21 | 22 | 23 | ; Extract common letters of two strings, removing the characters 24 | ; which are not equal for a given position of both strings. 25 | ; 26 | (define (common-chars a b) 27 | (define pairs (zip (string->list a) (string->list b))) 28 | (list->string 29 | (map! car 30 | (filter! (lambda (pair) (eq? (car pair) (cadr pair))) 31 | pairs)))) 32 | 33 | 34 | ; This is used below with "port-fold"; it visits each identifier, 35 | ; and keeps either a string or a set as the "seen" state: 36 | ; 37 | ; - If the matching IDs have been found already, the state 38 | ; is the result string, as calculated by "common-chars". 39 | ; 40 | ; - Otherwise, the state is the set of IDs seen so far, and 41 | ; if updated with either the set with the new current ID 42 | ; added; or updated to be the result string if the current 43 | ; ID "matches" (that is: is close enough, as determined by 44 | ; "similar-ids?" above). 45 | ; 46 | (define (visit-id id seen) 47 | (if (string? seen) 48 | seen ; Already found 49 | (let ((item (set-find (lambda (v) (similar-ids? v id)) 50 | seen 51 | (lambda () '())))) 52 | (if (null? item) 53 | (set-adjoin! seen id) 54 | (common-chars item id))))) 55 | 56 | 57 | ; Go over all the symbols read from the input, initially with 58 | ; an empty set as the state, converting each symbol to a string 59 | ; before calling "visit-id" for each one of them. 60 | ; 61 | (display 62 | (port-fold (lambda (sym seen) (visit-id (symbol->string sym) seen)) 63 | (set eq?) 64 | read)) 65 | (newline) 66 | -------------------------------------------------------------------------------- /day03: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env -S chibi-scheme -q 2 | ; vim:set ft=scheme: 3 | 4 | (import (aoc rect) 5 | (chibi iset) 6 | (chibi loop) 7 | (chibi match) 8 | (chibi parse) 9 | (scheme charset) 10 | (scheme hash-table)) 11 | 12 | 13 | (define-grammar claim-grammar 14 | (space ((* ,char-set:whitespace))) 15 | (number ((=> n (+ ,char-set:digit)) 16 | (string->number (list->string n)))) 17 | (*claim ((: "#" ,space (=> c ,number) ,space 18 | "@" ,space (=> x ,number) ,space 19 | "," ,space (=> y ,number) ,space 20 | ":" ,space (=> w ,number) ,space 21 | "x" ,space (=> h ,number) ,space) 22 | (cons c (rect x y w h))))) 23 | 24 | 25 | (define (visit-claim pair cloth) 26 | (let ((id (car pair)) 27 | (rr (cdr pair))) 28 | (loop ((for y (up-from (rect-t rr) (to (+ 1 (rect-b rr)))))) 29 | (loop ((for x (up-from (rect-l rr) (to (+ 1 (rect-r rr)))))) 30 | (hash-table-update! cloth 31 | (cons x y) 32 | (lambda (idset) (iset-adjoin! idset id)) 33 | (lambda () (iset-adjoin! (make-iset) id)))))) 34 | cloth) 35 | 36 | ; Maps (x, y) locations to the set IDs which claims the location. 37 | ; 38 | (define cloth (parse-fold *claim 39 | visit-claim 40 | (make-hash-table equal?) 41 | (make-parse-stream "" (current-input-port)))) 42 | 43 | 44 | (match (hash-table-fold cloth 45 | (lambda (_ idset state) 46 | (match state (#(count allids overlapids) 47 | (if (> (iset-size idset) 1) 48 | (vector (+ count 1) 49 | (iset-union! allids idset) 50 | (iset-union! overlapids idset)) 51 | (vector count 52 | (iset-union! allids idset) 53 | overlapids))))) 54 | (vector 0 (make-iset) (make-iset))) 55 | (#(count allids overlapids) (begin 56 | (display "Overlapped inches: ") 57 | (display count) 58 | (newline) 59 | (display "Non-overlapping IDs: ") 60 | (display (iset->list (iset-difference allids overlapids))) 61 | (newline)))) 62 | -------------------------------------------------------------------------------- /day08: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env -S chibi-scheme -q 2 | ; vim:set ft=scheme: 3 | 4 | (import (chibi io) 5 | (chibi match) 6 | (scheme list) 7 | (srfi 9)) 8 | 9 | (define-record-type Node 10 | (node children metadata) 11 | node? 12 | (children node-children) 13 | (metadata node-metadata)) 14 | 15 | ; 16 | ; Obtains the value for a node. This follows the definition directly: 17 | ; 18 | ; - For nodes with zero children, the sum of the metadata values. 19 | ; - For nodes with children, take the metadata values as node indices, 20 | ; and sum the values of the nodes references by the indices. 21 | ; 22 | ; When metadata values are used as indices, they are 1-based, and invalid 23 | ; indexes are skipped (no value is added for them). 24 | ; 25 | (define (node-value node) 26 | (define (valid-index? idx) 27 | (and (>= idx 1) 28 | (<= idx (length (node-children node))))) 29 | (if (null? (node-children node)) 30 | (fold + 0 (node-metadata node)) 31 | (fold + 0 (map (lambda (idx) 32 | (if (valid-index? idx) 33 | (node-value (list-ref (node-children node) (- idx 1))) 34 | 0)) 35 | (node-metadata node))))) 36 | 37 | ; 38 | ; Sum all the metadata values of the node and its subnodes. 39 | ; 40 | (define (node-sum-metadata node) 41 | (+ (fold + 0 (node-metadata node)) 42 | (fold + 0 (map node-sum-metadata (node-children node))))) 43 | 44 | ; 45 | ; list[num] -> node 46 | ; 47 | (define (node-parse input) 48 | ; 49 | ; Auxiliar function to parse a single node, returns (node . rest) 50 | ; 51 | (define (node-parse-one in) 52 | ; 53 | ; Auxiliar function to parse N nodes, returns (node-list . rest) 54 | ; 55 | ; - "n" keeps the count of nodes pending to parse. 56 | ; - "rest" keeps the list of remaining input values. 57 | ; - "result" accumulates the N nodes as a list, in reverse. 58 | ; 59 | ; Without nodes pending to parse: The result list has been accumulated 60 | ; in reverse order, therefore we need to reverse it before returning. 61 | ; 62 | ; Otherwise, parse a single node to obtain the list of remaining input 63 | ; and call recursively decreasing N, passing remaining input and the 64 | ; the result with the just parsed node prepended. 65 | ; 66 | (define (node-parse-childn n rest result) 67 | (if (zero? n) 68 | (cons (reverse! result) rest) 69 | (match (node-parse-one rest) 70 | ((c . r) (node-parse-childn (- n 1) r (cons c result)))))) 71 | 72 | ; 73 | ; Items in the input list are: (nchild nmeta . rest) 74 | ; ^^^^^^ ^^^^^ ^^^^ 75 | ; car cadr cddr 76 | ; 77 | (let ((nchild (car in)) 78 | (nmeta (cadr in)) 79 | (rest (cddr in))) 80 | (match (node-parse-childn nchild rest '()) 81 | ((c . r) (cons (node c (take r nmeta)) 82 | (drop r nmeta)))))) 83 | 84 | ; 85 | ; Parse one node, and take the node from the (node . rest) result. 86 | ; 87 | (car (node-parse-one input))) 88 | 89 | 90 | (define INPUT (node-parse (port->list read (current-input-port)))) 91 | 92 | (display "metadata sum: ") 93 | (display (node-sum-metadata INPUT)) 94 | (newline) 95 | 96 | (display "node value: ") 97 | (display (node-value INPUT)) 98 | (newline) 99 | --------------------------------------------------------------------------------