diff options
Diffstat (limited to '02')
| -rw-r--r-- | 02/input.txt | 16 | ||||
| -rw-r--r-- | 02/lib.scm | 74 | ||||
| -rw-r--r-- | 02/main.scm | 20 | ||||
| -rw-r--r-- | 02/test.scm | 38 | 
4 files changed, 148 insertions, 0 deletions
| diff --git a/02/input.txt b/02/input.txt new file mode 100644 index 0000000..315a416 --- /dev/null +++ b/02/input.txt @@ -0,0 +1,16 @@ +62	1649	1731	76	51	1295	349	719	52	1984	2015	2171	981	1809	181	1715 +161	99	1506	1658	84	78	533	242	1685	86	107	1548	670	960	1641	610 +95	2420	2404	2293	542	2107	2198	121	109	209	2759	1373	1446	905	1837	111 +552	186	751	527	696	164	114	530	558	307	252	200	481	142	205	479 +581	1344	994	1413	120	112	656	1315	1249	193	1411	1280	110	103	74	1007 +2536	5252	159	179	4701	1264	1400	2313	4237	161	142	4336	1061	3987	2268	4669 +3270	1026	381	185	293	3520	1705	1610	3302	628	3420	524	3172	244	295	39 +4142	1835	4137	3821	3730	2094	468	141	150	3982	147	4271	1741	2039	4410	179 +1796	83	2039	1252	84	1641	2165	1218	1936	335	1807	2268	66	102	1977	2445 +96	65	201	275	257	282	233	60	57	200	216	134	72	105	81	212 +3218	5576	5616	5253	178	3317	6147	5973	2424	274	4878	234	200	4781	5372	276 +4171	2436	134	3705	3831	3952	2603	115	660	125	610	152	4517	587	1554	619 +2970	128	2877	1565	1001	167	254	2672	59	473	2086	181	1305	162	1663	2918 +271	348	229	278	981	1785	2290	516	473	2037	737	2291	2521	1494	1121	244 +2208	2236	1451	621	1937	1952	865	61	1934	49	1510	50	1767	59	194	1344 +94	2312	2397	333	1192	106	2713	2351	2650	2663	703	157	89	510	1824	125 diff --git a/02/lib.scm b/02/lib.scm new file mode 100644 index 0000000..0274dad --- /dev/null +++ b/02/lib.scm @@ -0,0 +1,74 @@ +(library (lib) +  (export solve-part1 solve-part2) +  (import (chezscheme)) + +  ; Split list at first delimiter into `prefix' and `suffix' +  ; Return value is a pair like `((p r e f i x) s u f f i x)' +  (define (list-split-left delimiter? xs) +    (let loop ((prefix '()) +               (suffix xs)) +      (if (null? suffix) +        (cons prefix suffix) +        (let ((x (car suffix))) +          (if (delimiter? x) +              ; Found first delimiter, so return immediately +              (cons prefix (cdr suffix)) +              ; `x' isn't a delimiter, so append it to `prefix' +              (loop (append prefix (list x)) (cdr suffix))))))) + +  ; Split list at given delimiter into list of sublists +  (define (list-split delimiter? xs) +    (let loop ((pieces '()) +               (rest xs)) +      (if (null? rest) +          ; Fix order and remove all empty sublists from output +          ; (which are caused by consecutive delimiters in `xs') +          (reverse (remp null? pieces)) +          ; Extract next piece from `rest' and prepend it to `pieces' +          (let ((next (list-split-left delimiter? rest))) +            (loop (cons (car next) pieces) (cdr next)))))) + +  ; Split string at whitespace into list of words +  (define (string-split str) +    (map list->string (list-split char-whitespace? (string->list str)))) + +  ; Partially applied divisibility check +  (define (check-divisor? x) +    (lambda (y) +      (and (not (= y 0)) ; Don't try dividing by zero +           (not (= x y)) ; Disallow trivial solution +           (= (mod x y) 0)))) + +  ; Find minimum and maximum in row, return difference +  (define (find-range row) +    (- (apply max row) (apply min row))) + +  ; Find `x' and `y' where `y' is divisor of `x', return quotient +  (define (find-quotient row) +    ; Note: we don't check if we've reached the end of `xs', +    ; because we're guaranteed success before that happens. +    ; We're also guaranteed only one non-trivial solution. +    (let loop ((xs row)) +      (let* ((x (car xs)) +             (y (find (check-divisor? x) row))) +        ; Is this the (`x',`y') combination we're looking for, +        ; i.e. have we found a valid divisor `y' for this `x'? +        (if y +            (div x y) +            (loop (cdr xs)))))) + +  ; Add up result of `proc' for each `row' of numbers in `lines' +  (define (solve-puzzle proc lines) +    (fold-left +      (lambda (accum row) +        (+ accum (proc (map string->number row)))) +      0 +      (map string-split lines))) + +  (define (solve-part1 lines) +    (solve-puzzle find-range lines)) + +  (define (solve-part2 lines) +    (solve-puzzle find-quotient lines)) + +) diff --git a/02/main.scm b/02/main.scm new file mode 100644 index 0000000..746fa01 --- /dev/null +++ b/02/main.scm @@ -0,0 +1,20 @@ +(import (chezscheme)) + +; Where the magic happens +(import (lib)) + +; Read my personal puzzle input +(define input +  (call-with-input-file "input.txt" +    (lambda (port) +      (let loop ((line (get-line port)) +                 (result '())) +        (if (eof-object? line) +            (reverse result) +            (loop (get-line port) (cons line result))))))) + +; Part 1 gives 44216 for me +(printf "Part 1 solution: ~a\n" (solve-part1 input)) + +; Part 2 gives 320 for me +(printf "Part 2 solution: ~a\n" (solve-part2 input)) diff --git a/02/test.scm b/02/test.scm new file mode 100644 index 0000000..10ee751 --- /dev/null +++ b/02/test.scm @@ -0,0 +1,38 @@ +(import (chezscheme)) + +; Where the magic happens +(import (lib)) + +; My quick-and-dirty unit testing framework (copied for each day) +(define (run-test name proc input expected) +  (let ((result (proc input))) +    (if (= result expected) +      (printf "\x1b;[32;1mPASS\x1b;[0m: ~a\n" +              name) +      (printf "\x1b;[31;1mFAIL\x1b;[0m: ~a: got ~a, expected ~a\n" +              name result expected)))) + +(printf "Part 1 tests:\n") + +(define (test-part1 name input expected) +  (run-test name solve-part1 input expected)) + +(define part1-example1 +  '("5 1 9 5" +    "7 5 3" +    "2 4 6 8")) +(test-part1 "part 1 example 1" +            part1-example1 18) + +(printf "Part 2 tests:\n") + +(define (test-part2 name input expected) +  (run-test name solve-part2 input expected)) + +(define part2-example1 +  '("5 9 2 8" +    "9 4 7 3" +    "3 8 6 5")) +(test-part2 "part 2 example 1" +            part2-example1 9) + | 
