2016
Matthew Butterick 8 years ago
parent 16f101de88
commit 167b8dd85b

@ -1,9 +1,8 @@
#lang br/quicklang #lang br/quicklang
(require racket/file)
(module+ reader (module+ reader
(provide read-syntax) (provide read-syntax)
(define (read-syntax path port) (define (read-syntax path port)
(define turn-strings (string-split (port->string port) ", ")) (define turn-strings (string-split (port->string port) ","))
(define turn-pattern #px"^([LR])(\\d+)$") (define turn-pattern #px"^([LR])(\\d+)$")
(define turn-datums (define turn-datums
(for*/list ([tstr (in-list turn-strings)]) (for*/list ([tstr (in-list turn-strings)])
@ -21,48 +20,36 @@
(define (loc-dist loc) (define (loc-dist loc)
(+ (abs (imag-part loc)) (abs (real-part loc)))) (+ (abs (imag-part loc)) (abs (real-part loc))))
(define (locs-between loca locb) (struct $turn (rot dist) #:transparent)
(define real-steps (abs (- (real-part loca) (real-part locb)))) (define rotate-left +i)
(define imag-steps (abs (- (imag-part loca) (imag-part locb)))) (define rotate-right -i)
(define diff (- locb loca)) (define same-dir 1)
(let loop ([locs (list loca)])
(if (equal? (car locs) locb)
(reverse locs)
(cons (+ (real-part loca)
(* +i (imag-part loca))) locs))))
(module+ test
(require rackunit)
(check-equal? (locs-between 0 3) '(0 1 2 3))
(check-equal? (locs-between 3 0) (reverse (locs-between 0 3)))
(check-equal? (locs-between +0i +3i) '(+0i +1i +2i +3i))
(check-equal? (locs-between +3i +0i) (reverse (locs-between +0i +3i))))
(define (solve . turns) (define (solve . turns)
(define first-loc-visited-twice #f) (define found-twice-visited-loc #f)
(define north 0+1i) (define north 0+1i)
(let loop ([locs (list 0+0i)] [dir north] [turns turns]) (define starting-loc 0+0i)
(if (empty? turns) (let loop ([locs (list starting-loc)] [dir north] [turns turns])
(displayln (format "part 1 (dist of final location): ~a" (loc-dist (car locs)))) (cond
(let* ([turn (car turns)] [(empty? turns)
[rotation (car turn)] (displayln (format "part 1 (dist of final location): ~a" (loc-dist (car locs))))]
[new-dir (* dir rotation)] [(zero? ($turn-dist (car turns))) (loop locs dir (cdr turns))]
[dist (cdr turn)] [else
[loc (car locs)] (define new-dir (* dir ($turn-rot (car turns))))
[new-loc (+ loc (* new-dir dist))]) (define one-step 1)
(define new-loc (+ (car locs) (* new-dir one-step)))
(when (and (when (and (not found-twice-visited-loc) (member new-loc locs))
(not first-loc-visited-twice) (set! found-twice-visited-loc new-loc)
(report* locs loc new-loc (member new-loc locs))) (displayln (format "part 2 (dist of first twice-visited location): ~a"
(set! first-loc-visited-twice new-loc) (loc-dist new-loc))))
(displayln (format "part 2 (dist of first twice-visited location): ~a" (loc-dist new-loc)))) (define decremented-turn ($turn same-dir (sub1 ($turn-dist (car turns)))))
(loop (report (append (locs-between new-loc loc) (cdr locs))) new-dir (cdr turns)))))) (loop (cons new-loc locs) new-dir (cons decremented-turn (cdr turns)))])))
(define-macro-cases turn (define-macro-cases turn
[(_ DIR DIST) [(_ DIR DIST)
(with-pattern ([NEW-DIR (syntax-case #'DIR () (with-pattern ([ENCODED-DIR (syntax-case #'DIR ()
["L" #'+i] ["L" #'rotate-left]
["R" #'-i])]) ["R" #'rotate-right])])
#'(cons NEW-DIR (string->number DIST)))] #'($turn ENCODED-DIR (string->number DIST)))]
[else #'(void)]) [else #'(void)])
(provide turn) (provide turn)