diff --git a/aoc-racket.scrbl b/aoc-racket.scrbl index 3f040d3..b46609d 100644 --- a/aoc-racket.scrbl +++ b/aoc-racket.scrbl @@ -39,4 +39,5 @@ You can install this package (if you haven't already) with @include-section[(submod "day16.rkt" doc)] @include-section[(submod "day17.rkt" doc)] @include-section[(submod "day18.rkt" doc)] -@include-section[(submod "day19.rkt" doc)] \ No newline at end of file +@include-section[(submod "day19.rkt" doc)] +@include-section[(submod "day20.rkt" doc)] \ No newline at end of file diff --git a/day20-input.txt b/day20-input.txt new file mode 100644 index 0000000..d0d42b1 --- /dev/null +++ b/day20-input.txt @@ -0,0 +1 @@ +36000000 \ No newline at end of file diff --git a/day20.rkt b/day20.rkt new file mode 100644 index 0000000..67fbfe3 --- /dev/null +++ b/day20.rkt @@ -0,0 +1,72 @@ +#lang scribble/lp2 +@(require scribble/manual aoc-racket/helper) + +@aoc-title[20] + +@defmodule[aoc-racket/day20] + +@link["http://adventofcode.com/day/20"]{The puzzle}. Our @link-rp["day20-input.txt"]{input} is a target number of presents, in this case @racket[36000000]. + + +@chunk[ + + + + ] + +@section{What's the first house that gets the target number of presents?} + +The puzzle imagines infinite elves delivering presents to an infinite sequence of houses. (Already @link["http://practicaltypography.com/the-infinite-pixel-screen.html"]{I like} this puzzle.) The first elf delivers a present to every house equal to 10 times his number (= 10); the second elf, 20 gifts to every second house; the @italic{n}th elf, 10@italic{n} gifts to every @italic{n}th house. + +Math jocks will notice that the elf behavior roughly describes a @link["https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes"]{Sieve of Eratosthenes}. Each house is visited by elf @italic{n} only if @italic{n} is a divisor of the house number. (Houses that are primes are therefore only visited by the first elf.) Might there be a Racket function that finds the divisors of a number? Why, yes — it's called @racket[divisors]. We can use it to find the numbers of the elves that visit a house, and loop through house numbers till we reach the target. (The 10-gift multiplier is arbitrary.) + +@chunk[ + (require racket rackunit (only-in math divisors)) + (provide (all-defined-out)) + ] + +@chunk[ + + (define (q1 input-str) + (define target-gifts (read (open-input-string input-str))) + (define gifts-per-elf 10) + (for/first ([house-number (in-naturals)] + #:when (let* ([elves (divisors house-number)] + [elf-gifts + (apply + (map (curry * gifts-per-elf) elves))]) + (>= elf-gifts target-gifts))) + house-number))] + + + +@section{What's the first house that gets the target number of presents, if each elf delivers 11 gifts to 50 houses?} + +Going with the math-jock vibe, what this condition means is that the highest-numbered house the @italic{n}th elf will visit is 50@italic{n}. So the answer for this question is like the first, but we'll @racket[filter] the list of elves using this condition. + +@chunk[ + + (define (q2 input-str) + (define target-gifts (read (open-input-string input-str))) + (define gifts-per-elf 11) + (for/first ([house-number (in-naturals)] + #:when (let* ([elves (divisors house-number)] + [elves (filter + (λ(e) (<= house-number (* 50 e))) elves)] + [elf-gifts + (apply + (map (curry * gifts-per-elf) elves))]) + (>= elf-gifts target-gifts))) + house-number)) + + ] + + + +@section{Testing Day 18} + +@chunk[ + (module+ test + (define input-str (file->string "day20-input.txt")) + (check-equal? (q1 input-str) 831600) + (check-equal? (q2 input-str) 884520))] + +