master-blaster
Matthew Butterick 8 years ago
parent 9e9f30b27c
commit 3569b6bccb

@ -5,20 +5,24 @@
@author[(author+email "Matthew Butterick" "mb@mbtype.com")]
@defmodule[aoc-racket]
@defmodule[aoc-racket]
@italic{Dedicated to curious characters everywhere, especially those learning Racket.}
@local-table-of-contents[]
@include-section[(submod "day1.scrbl" doc)]
@include-section[(submod "day2.scrbl" doc)]
@include-section[(submod "day3.scrbl" doc)]
@include-section[(submod "day4.scrbl" doc)]
@include-section[(submod "day5.scrbl" doc)]
@include-section[(submod "day6.scrbl" doc)]
@include-section[(submod "day7.scrbl" doc)]
@include-section[(submod "day8.scrbl" doc)]
@include-section[(submod "day9.scrbl" doc)]
@include-section[(submod "day10.scrbl" doc)]
@include-section[(submod "day11.scrbl" doc)]
@include-section[(submod "day12.scrbl" doc)]
@include-section[(submod "day13.scrbl" doc)]
@include-section[(submod "day1.rkt" doc)]
@include-section[(submod "day2.rkt" doc)]
@include-section[(submod "day3.rkt" doc)]
@include-section[(submod "day4.rkt" doc)]
@include-section[(submod "day5.rkt" doc)]
@include-section[(submod "day6.rkt" doc)]
@include-section[(submod "day7.rkt" doc)]
@include-section[(submod "day8.rkt" doc)]
@include-section[(submod "day9.rkt" doc)]
@include-section[(submod "day10.rkt" doc)]
@include-section[(submod "day11.rkt" doc)]
@include-section[(submod "day12.rkt" doc)]
@include-section[(submod "day13.rkt" doc)]
@index-section[]

@ -3,6 +3,8 @@
@aoc-title[1]
@defmodule[aoc-racket/day1]
@link["http://adventofcode.com/day/1"]{The puzzle}. Our @link-rp["day1-input.txt"]{input} is a string of parentheses that controls an elevator. A left parenthesis @litchar{(} means go up one floor, and a right parenthesis @litchar{)} means go down.
@chunk[<day1>
@ -22,6 +24,7 @@ The building has an indefinite number of floors in both directions. So the ultim
@chunk[<day1-setup>
(require racket rackunit)
(provide (all-defined-out))
(define up-char #\()
(define down-char #\))
@ -35,11 +38,7 @@ The building has an indefinite number of floors in both directions. So the ultim
@chunk[<day1-q1>
(define (q1 str)
(displayln (format "ups = ~a" (get-ups str)))
(displayln (format "downs = ~a" (get-downs str)))
(define destination (get-destination str))
(displayln (format "destination = ~a" destination))
destination)]
(get-destination str))]
@subsection{Alternate approach: numerical conversion}
@ -53,9 +52,7 @@ Rather than counting matches with @racket[regexp-match*], we could also convert
-1)))
(define (q1-alt str)
(define destination (apply + (elevator-string->ints str)))
(displayln (format "destination = ~a" destination))
destination)]
(apply + (elevator-string->ints str)))]
@section[#:tag "q2"]{At what point does the elevator enter the basement?}
@ -77,15 +74,13 @@ We could characterize this as a problem of tracking @italic{cumulative values} o
#:break (in-basement? movements-so-far))
(cons (get-destination (~a c)) movements-so-far)))
(define basement-position (length relative-movements))
(displayln (format "basement entered at position = ~a" basement-position))
basement-position)]
(length relative-movements))]
@subsection{Alternate approaches: @tt{for/first} or @tt{for/or}}
When you need to stop a loop the first time a condition occurs, you can also consider @racket[for/first] or @racket[for/or]. The difference is that @racket[for/first] ends after the first evaluation of the body, but @racket[for/or] evaluates the body every time, and ends the first time the body is not @racket[#f].
The two are similar. The choice comes down to readability and efficiency  meaning, if each iteration of the loop is expensive, you probably will want to cache intermediate values, which means you might as well use @racket[for/fold].
The two are similar. The choice comes down to readability and efficiency  meaning, if each iteration of the loop is expensive, you'll probably want to cache intermediate values, which means you might as well use @racket[for/fold].
@chunk[<day1-q2-alt>
(define (q2-for/first str)
@ -94,7 +89,6 @@ The two are similar. The choice comes down to readability and efficiency — me
(for/first ([idx (in-range (length ints))]
#:when (negative? (apply + (take ints idx))))
idx)))
(displayln (format "basement entered at position = ~a" basement-position))
basement-position)
(define (q2-for/or str)
@ -102,7 +96,6 @@ The two are similar. The choice comes down to readability and efficiency — me
(let ([ints (elevator-string->ints str)])
(for/or ([idx (in-range (length ints))])
(and (negative? (apply + (take ints idx))) idx))))
(displayln (format "basement entered at position = ~a" basement-position))
basement-position)]

@ -3,6 +3,8 @@
@aoc-title[10]
@defmodule[aoc-racket/day10]
@link["http://adventofcode.com/day/10"]{The puzzle}. Our @link-rp["day10-input.txt"]{input} is a short numeric key.
@chunk[<day10>
@ -21,6 +23,7 @@ The second part of the puzzle is just going to change the number of iterations.
@chunk[<day10-setup>
(require racket rackunit)
(provide (all-defined-out))
(define (look-and-say iterations input-key)
(for/fold ([start input-key])

@ -3,6 +3,8 @@
@aoc-title[11]
@defmodule[aoc-racket/day11]
@link["http://adventofcode.com/day/11"]{The puzzle}. Our @link-rp["day11-input.txt"]{input} is a short alphabetic key that represents a password.
@chunk[<day11>
@ -34,6 +36,7 @@ The @racket[three-consecutive-letters?] test works by converting the letters to
@chunk[<day11-setup>
(require racket rackunit)
(provide (all-defined-out))
(define (increment-password password)
(define (increment-letter c)

@ -3,6 +3,8 @@
@aoc-title[12]
@defmodule[aoc-racket/day12]
@link["http://adventofcode.com/day/12"]{The puzzle}. Our @link-rp["day12-input.txt"]{input} is, unfortunately, a @link["http://json.org/"]{JSON} file.
@chunk[<day12>
@ -24,6 +26,7 @@ If you're new to Racket, notice the @italic{recursive descent} pattern used in @
@chunk[<day12-setup>
(require racket rackunit json)
(provide (all-defined-out))
(define (string->jsexpr str)
(read-json (open-input-string str)))

@ -3,6 +3,8 @@
@aoc-title[13]
@defmodule[aoc-racket/day13]
@link["http://adventofcode.com/day/13"]{The puzzle}. Our @link-rp["day13-input.txt"]{input} is a list of descriptions of ``happiness units'' that would be gained or lost among eight people sitting next to each other at a dinner table.
@chunk[<day13>
@ -23,6 +25,7 @@ Those wrinkles noted, we'll proceed as we did in @secref{Day_9}. We'll parse the
@chunk[<day13-setup>
(require racket rackunit)
(provide (all-defined-out))
(define happiness-scores (make-hash))

@ -3,6 +3,8 @@
@aoc-title[2]
@defmodule[aoc-racket/day2]
@link["http://adventofcode.com/day/2"]{The puzzle}. Our @link-rp["day2-input.txt"]{input} is a list of strings that represent dimensions of rectangular boxes.
@chunk[<day2>
@ -22,6 +24,7 @@ Then we have a traditional setup for the devastating one-two punch of @racket[ma
@chunk[<day2-setup>
(require racket rackunit)
(provide (all-defined-out))
(define (string->boxes str)
(for/list ([ln (in-list (string-split str "\n"))])
(map string->number (string-split ln "x"))))]

@ -3,6 +3,8 @@
@aoc-title[3]
@defmodule[aoc-racket/day3]
@link["http://adventofcode.com/day/3"]{The puzzle}. Our @link-rp["day3-input.txt"]{input} is a string made of the characters @litchar{^v<>} that represent north, south, west, and east. Taken together, the string represents a path through an indefinitely large grid.
In essence, this a two-dimensional version of the elevator problem in @secref{Day_1}.
@ -25,6 +27,7 @@ Once the whole cell path is computed, the answer is found by removing duplicate
@chunk[<day3-setup>
(require racket rackunit)
(provide (all-defined-out))
]
@chunk[<day3-q1>

@ -4,6 +4,8 @@
@aoc-title[4]
@defmodule[aoc-racket/day4]
@link["http://adventofcode.com/day/4"]{The puzzle}. Our @link-rp["day4-input.txt"]{input} is a string of eight characters that represents part of a key for making an MD5 hash.
@chunk[<day4>
@ -21,6 +23,7 @@ Whether or not you already know what an MD5 hash is, you can search the Racket d
@chunk[<day4-setup>
(require racket rackunit openssl/md5)
(provide (all-defined-out))
]
@chunk[<day4-q1>

@ -3,6 +3,8 @@
@aoc-title[5]
@defmodule[aoc-racket/day5]
@link["http://adventofcode.com/day/5"]{The puzzle}. Our @link-rp["day5-input.txt"]{input} is a list of random-looking but not really random text strings.
@chunk[<day5>
@ -26,6 +28,7 @@ This is a job for @racket[regexp-match]. There's nothing tricky here (except for
@chunk[<day5-setup>
(require racket rackunit)
(provide (all-defined-out))
]
@chunk[<day5-q1>

@ -3,6 +3,8 @@
@aoc-title[6]
@defmodule[aoc-racket/day6]
@link["http://adventofcode.com/day/6"]{The puzzle}. Our @link-rp["day6-input.txt"]{input} is a list of instructions for turning on (or off) the bulbs in a @racket[(* 1000 1000)] grid of lights.
@chunk[<day6>
@ -47,6 +49,7 @@ We'll define our functions for setting and counting the lights separately, since
@chunk[<day6-setup>
(require racket rackunit)
(provide (all-defined-out))
(define (set-lights lights arglist)
(match-define (list bulb-func x1 y1 x2 y2) arglist)

@ -3,6 +3,8 @@
@aoc-title[7]
@defmodule[aoc-racket/day7]
@link["http://adventofcode.com/day/7"]{The puzzle}. Our @link-rp["day7-input.txt"]{input} describes an electrical circuit, with each line of the file describing the signal provided to a particular wire.
@chunk[<day7>
@ -45,6 +47,7 @@ One gotcha when using syntax transformers is that identifiers introduced by a tr
@chunk[<day7-setup>
(require racket rackunit
(for-syntax racket/base racket/file racket/string))
(provide (all-defined-out))
(define-syntax (convert-input-to-wire-functions stx)
(syntax-case stx ()

@ -3,6 +3,8 @@
@aoc-title[8]
@defmodule[aoc-racket/day8]
@link["http://adventofcode.com/day/8"]{The puzzle}. Our @link-rp["day8-input.txt"]{input} consists of a list of seemingly random strings within quotation marks.
@chunk[<day8>
@ -19,6 +21,7 @@ The literal length of the string is trivial — use @racket[string-length]. The
@chunk[<day8-setup>
(require racket rackunit)
(provide (all-defined-out))
]
@chunk[<day8-q1>

@ -3,6 +3,8 @@
@aoc-title[9]
@defmodule[aoc-racket/day9]
@link["http://adventofcode.com/day/9"]{The puzzle}. Our @link-rp["day9-input.txt"]{input} consists of a list of distances between fictional cities, e.g., @italic{AlphaCentauri to Straylight = 133}.
@chunk[<day9>
@ -23,6 +25,7 @@ In the second part, we'll loop through every possible path between the cities wi
@chunk[<day9-setup>
(require racket rackunit)
(provide (all-defined-out))
(define distances (make-hash))

@ -0,0 +1,3 @@
#lang racket/base
;; nothing at the top level