From 31a9f73acb1cfac1356cbbdc48696dd32e7211b8 Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Fri, 1 Jan 2016 22:07:51 -0800 Subject: [PATCH] day9 --- aoc-racket.scrbl | 4 ++- day8.scrbl | 2 +- day9-input.txt | 28 ++++++++++++++++++ day9.scrbl | 77 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 day9-input.txt create mode 100644 day9.scrbl diff --git a/aoc-racket.scrbl b/aoc-racket.scrbl index 6cc6e13..3e52d63 100644 --- a/aoc-racket.scrbl +++ b/aoc-racket.scrbl @@ -15,4 +15,6 @@ @include-section[(submod "day4.scrbl" doc)] @include-section[(submod "day5.scrbl" doc)] @include-section[(submod "day6.scrbl" doc)] -@include-section[(submod "day7.scrbl" doc)] \ No newline at end of file +@include-section[(submod "day7.scrbl" doc)] +@include-section[(submod "day8.scrbl" doc)] +@include-section[(submod "day9.scrbl" doc)] \ No newline at end of file diff --git a/day8.scrbl b/day8.scrbl index 5c56aea..a9c40b0 100644 --- a/day8.scrbl +++ b/day8.scrbl @@ -29,7 +29,7 @@ The literal length of the string is trivial — use @racket[string-length]. The -@section{What is the difference between the re-encoded length of the literal string, and the original length?} +@section{What's the difference between the re-encoded length of the literal string, and the original length?} This question simply comes down to — do you know how to use the string-formatting functions in your programming language? diff --git a/day9-input.txt b/day9-input.txt new file mode 100644 index 0000000..34175b9 --- /dev/null +++ b/day9-input.txt @@ -0,0 +1,28 @@ +Tristram to AlphaCentauri = 34 +Tristram to Snowdin = 100 +Tristram to Tambi = 63 +Tristram to Faerun = 108 +Tristram to Norrath = 111 +Tristram to Straylight = 89 +Tristram to Arbre = 132 +AlphaCentauri to Snowdin = 4 +AlphaCentauri to Tambi = 79 +AlphaCentauri to Faerun = 44 +AlphaCentauri to Norrath = 147 +AlphaCentauri to Straylight = 133 +AlphaCentauri to Arbre = 74 +Snowdin to Tambi = 105 +Snowdin to Faerun = 95 +Snowdin to Norrath = 48 +Snowdin to Straylight = 88 +Snowdin to Arbre = 7 +Tambi to Faerun = 68 +Tambi to Norrath = 134 +Tambi to Straylight = 107 +Tambi to Arbre = 40 +Faerun to Norrath = 11 +Faerun to Straylight = 66 +Faerun to Arbre = 144 +Norrath to Straylight = 115 +Norrath to Arbre = 135 +Straylight to Arbre = 127 \ No newline at end of file diff --git a/day9.scrbl b/day9.scrbl new file mode 100644 index 0000000..09e1a71 --- /dev/null +++ b/day9.scrbl @@ -0,0 +1,77 @@ +#lang scribble/lp2 +@(require scribble/manual aoc-racket/helper) + +@aoc-title[9] + +@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[ + + + + ] + +@section{What's the shortest route that visits all the cities?} + +This puzzle is a version of the famous @link["https://simple.wikipedia.org/wiki/Travelling_salesman_problem"]{traveling-salesman problem}. The problem is famous because there's no reasonable algorithm to solve it for arbitrarily large sets of cities. This version, however, has only eight cities. So it is possible (and easiest) to simply try all the options and see which is shortest. + +The solution has two parts. First, we'll parse our input data and put the distances into a mutable hash table. One small wrinkle — the distance between city A and city B is the same whether our path takes us from A to B or B to A. So the keys for our hash will be of the form @racket[(list city-a city-b)], with the cities always in alphabetical order. + +In the second part, we'll loop through every possible path between the cities with @racket[in-permutations]. We'll split each path into pairs of cities, look up each distance between pairs, and sum them. This will give us a list of distances, and we can find the smallest with @racket[apply min]. + +@margin-note{The reason the traveling-saleman problem is generally difficult is that the number of permutations of @racket[_n] cities is @racket[(factorial (sub1 _n))], which gets very large, very quickly.} + +@chunk[ + (require racket rackunit) + + (define distances (make-hash)) + + (define (str->hash ln) + (match-define (list _ here there dist) + (regexp-match #px"^(\\w+) to (\\w+) = (\\d+)" ln)) + (define key (places->key here there)) + (hash-set! distances key (string->number dist))) + + (define (places->key here there) + (sort (list (string-downcase here) (string-downcase there)) stringkey here there) +inf.0)) + + (define cities (remove-duplicates (append* (hash-keys distances)))) + (for/list ([route (in-permutations cities)]) + (for/sum ([pair (in-list (pairify route))]) + (apply distance pair)))) + ] + +@chunk[ + + + (define (q1 strs) + (for-each str->hash strs) + (apply min (calculate-route-distances)))] + + + +@section{What's the longest route?} + +Exactly the same, except we look for the @racket[max] value among the distances rather than the @racket[min]. + +@chunk[ + + (define (q2 strs) + (apply max (calculate-route-distances))) ] + + +@section{Testing Day 9} + +@chunk[ + (module+ test + (define input-strs (file->lines "day9-input.txt")) + (check-equal? (q1 input-strs) 251) + (check-equal? (q2 input-strs) 898))] + +