From 83be0e883b1c00c4f6e521b1db77adc9480d3e67 Mon Sep 17 00:00:00 2001 From: Jonathan Chan Date: Sun, 20 Dec 2020 12:02:02 -0800 Subject: [PATCH] Day 20, Part 2. --- input/20-image.txt | 96 ++++++++++++++++++++++++ src/20.rkt | 178 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 252 insertions(+), 22 deletions(-) create mode 100644 input/20-image.txt diff --git a/input/20-image.txt b/input/20-image.txt new file mode 100644 index 0000000..41691b4 --- /dev/null +++ b/input/20-image.txt @@ -0,0 +1,96 @@ +..........##.#..##..........#............#...#.....#..#......#.##...#.....#...#.....#..#....#.## +#.....#.###...#..#......#...##..#......#.......#.#.#.#...#.#.....#......#...#................#.. +..###.#....#..#........###.....#.#............#.......#..##......#..#...#.#.......#....#.#...#.. +..#............#.........##.##.......#....##......###.#.......................##.....#.......... +........#.....##..#..............#........#.#..###...#....#..#.....#.......##...#..#.......#.... +....##......#..####.#.###..............#..#.#....##..#...#..#.#.....#........##................. +#......#..##.#.........#O#.#.............#........#.............#.........#........#.....#...... +....#.O....OO..##OO....OOO....###..........#..................#.......#..#..#.....#........#...# +..#....O..O.#O..O.#O..O..#......................#..##.......................##.....##.....#..... +.#.....###.....#......#..##....#.#............#.....#...#.#......#...#..#.....#..##.##........#. +#.#..#.##.........#.#..................##..#....#........#...##........#.......#.#...##.......## +....#..#.#.......#..#........#..#......#.....#.#...#.......O.#............#...#...#.#........... +..........#.#..###.....##...O.#......#...O.#..OO#...OO..#.OOO##....##..........##..##........... +......#...O##..OO.#.#OO#...OOO.....#.#....O..O#.O.#O..O..O....#.#..............................# +........#..O#.O.#O..O..O.#O.#.......#...#.#..#.......##...............#..#...................... +#..##.......#.....#.##....#..#..##.....#..#..............................#.........#...#....#.#. +#................#.......#.#....##..........#....#.#.#..........#.......#.#.....###....#....##.. +..#..#.#...#...#....#......##..#....#..........#............#.........#..#..#........#.......#.. +.#.......#..#....##.#.......##.##..#.###.....#.#...##..................#..O....#..#.........#.#. +#.......##.....#....#.#.#...#.....#...........#.....#...O...#OO..#.OO....OOO.........####....#.# +.#......#.....#............#.....#.........#..#......##..O..O.#O..O#.O..O#...#...#.##.......#..# +....#.......#........#..........................##....................#...#............#........ +......#...#........#......#O.#.....................#.........#....#..##...#........##..#.....#.. +.##....#.O..#.OO.#..OO....OOO#.......#.......#...#...#..#......#.......#.#..............#.....## +....#.....O.#O..O..O.#O..O..#.##...#........#.......................#...........#....#.......#.. +#..#....#.....##.....#........#..#.....#.#.........#..#.......##.............#.......#..##...... +......#..#..........#.#.....##.#..#.........#..............#...##...#...#.......#..###......#.#. +........#........#.#..................................#.##.....#..#.#.#...........#.#........... +.......##.#..#......#.#........##O.#.#..................#..O......#.....#.....##......#......... +.........#..#..O..##OO..##OO....OOO.#....O....OO...#OO....OOO............#...#...##..#.........# +.....#.....#....O##O..O..O..O..O....#..#..O..O..O..O..O..O...................#...##....#.....#.. +....###....#..#.#....#.....##..........#.#..##..........##.........#...#.........#..#........... +..........#....#.......#.#..#.#......#......#.#......#.#.#.......#...#.......###..............#. +.#.....#.##.....#....#................#............#...O#............#.........#....#.......#... +...##........#..#...................#O.#..OO#..#OO#...OOO..........##..#.###......#.....#.#..... +..#....#...#...........##..#.#....#...O..O..O..O..O..O#...#....#.......###..#....#.#......#..... +......#........#.#.#....##..#......#........##...#.#...................#..#.#....#..........#... +.......#.........#....#...##.##....#....#.#......#...#..........#.#....#....#...............##.. +..........#.....#.........#..........#.#......#...#....##.............#...#.##.#......#......... +.....##.##......##..#.....#.....#....#.......#.#.....##.......##.....#....#.##.#..#.#O.....#..#. +..#.#....#...#..................#.#.............##........#........O....OO....OO#...OOO......... +...#.#...##.......#.........#...O.................#...#....#.#O....#O..O..O..O#.O.#O............ +.#..#....#.#.#O....OO..#.OO....OOO.#........O....OO....OO..#.OOO.#....................#......#.. +...#.#....#...#O..O.#O.#O..O..O..........#...O..O..O..O#.O..O..#.......#....#...#........#...... +....................#............#...#.........###.......#.#.......#..#..#.#..#.#.#.O..#........ +#........#...#..#.....................O.........#.......#..#.##...O..#.OO#...OO....OOO....#..... +..###.#...#.#.#..#.#O.#.#OO....OO....OOO#.#.#.....#.#....#.....#...O..O..O..O#.O..O#.....#...### +#..........#....####.O..O#.O..O..O#.O....#......#.#..#...##...#...#.#......##..........#..#..... +#.......#...##.#...............#..................#...#......#.....#.......#.................... +........#...#.#......#..#.................#.#.#.............#....##.#.#.#.....#....#........#..# +..#..###..........#........#.#.#...#...#.....#...#..........#..#..#...##...........#............ +..#.......#...#....#.............#.......#..........#..........#..#.#..##.#.#..#.......#.###.... +........##.......#...#....#.........#..............#.....O#....#.##.#..#.#....#..#.#..#...#.O.#. +..#...#.......#....#.............#...##O#.##OO....OO....OOO......##......#O....OO....OO....OOO.. +....................#...#.#.....##......O..O..O..O..O..O..................#O#.O..O#.O..O..O..... +...#.......#.#..........O....#......###....#.#.....#.#.##...........##............#.#........... +#.....O....OO....OO##..OOO..........#.................................##...#...#..##..#....###.. +..##...O..O#.O..O..O..O###..#....##..#.....#.##...#..#.#...#..##......#.....#...##........#..... +....#.....#.....#.............##.............#.........#..#....#......O.......#.............#.#. +..#.......#........#.........#...#.#.......#....#...O.##.OO....OO....OOO......##...........#.... +..#..#..#.......#..#...#.#......##...#.....#...##..#.O..O..O..O#.O..O..#......#.....#.#.......#. +......#..........#............#....#.#....#.................#.....#...#.....#.##........#..#...# +...##...........#............#..........#.......#.#...##..#...........................#......... +...#.#..............##..#.#.................#.#...........#..#...#.....................#.##..#.. +....#...#......................#...##........##..#..#.........#........O........................ +...#.#.#..#..............#........#.##...#...........O.#..OO.#..OO...#OOO...............#.#.#... +...#..#....#.........##......##................##.#...O.#O##O..O..O.#O.........#.......#..#..#.. +...........#..#.#..........#.............####.##...#........#.#.......#..............#..#....... +....#..#.#....#.....#..#.......#..#.....O..#.....#.....#.#...#.........#.#..#....#........#.#..# +...#..............#...O..#.OO.##.OO....OOO......#...#......###..#...................###......#.. +.#.........#.#.........O..O.#O..O#.O..O#........#.#.........#...#...........#......#..#.#..#.... +##.#.........................#......##.......#.#.#.#.#......#..#....##......#......#......#..... +...##.#............##....##..##.#...#..............#..#.#......#..#........#........#......##..# +..#..#......#.............O#.#.#........................#.....#......#.....#.#.......#......#... +...#.#..O....OO..#.OO....OOO....#.....#......#....#.......#.#...............#.......O....#..#... +#.#...#..O.#O#.O#.O#.O#.O.......#...#....#.....##....#............O..#.OO#...OO....OOO.###...... +..#.....#...#....#..#..#...#.#......#.....#.....#........#......#..O#.O.#O..O.#O..O..#.#...#..## +.#...#.....###...........................#..#..#....##.............#...#....#..#.....#...#...... +##.#......#............#....#....#..#.#.#......#.....#..#...#.....##..#..#...................... +..##......#...........O...........#..#.##...#O..........#.......#.#...........................#. +..#.O....OO...#OO....OOO...O..#.OO....OO.#.#OOO..#..#....#...##.....#.#.#..##.....#...#......... +.....O..O#.O..O..O..O.......O..O.#O.#O.#O..O##.##..##..........#...#.......#..#.#....#.......#.. +#...#.........................#.............#..#....##.....#.#.............#....#.........#..... +.....................#.........#..#....#...#.#..#..#.....##......#..#..##....#..............##.. +..#..#.#.......................##.....#......#.....##...........###.......#O.................... +....#....#....................#..#..#.......O.##.........O....OO#...OO#..#OOO.#.##.....#....#... +..#...#.......#......##..#O...#OO....OO..#.OOO....#.....#.O..O..O..O..O..O...#...#.............. +.#........#.......#........O..O.#O..O..O..O...#.#.......#..............#...#.......#..........#. +..#...#...........#...#..#..#.##.#..#..#..##..............#........#....#.#.............#.#..... +....#......#.....#......#....#...#...#....#.........#.....#..#.......#.####.#....#.........#.... +.....#.#...#.#.#....#..##.....#......#.#....#.#.###..#....#.........#........##....#.......#.... +#.............#....#....#........#.......#......O.........#..##........................#.....#.. +............#..#..........#...O....OO....OO....OOO..#....#..##...#....#..........#.............. +.#..........#.#.##.#...........O..O..O..O..O#.O........#.##.....#..#...#..#.......#......#....#. +.............#.....#.....#................###.#....#.......#...##.....#..#......###....#.....#.. +.....#...............#....##......#.........#..............#............#....#..#.#......#.#.... diff --git a/src/20.rkt b/src/20.rkt index 33ee1c5..b1a6b64 100644 --- a/src/20.rkt +++ b/src/20.rkt @@ -4,37 +4,171 @@ (define input (map string-lines (problem-input-grouped 20))) +;; name: number? +;; image: image? = (listof (listof char?)) +(struct tile (name image) #:transparent) + (define (parse-tile tile-strings) (match-let ([`(,name ,rows ...) tile-strings]) - (list (string->number (second (regexp-match #px"Tile (\\d+):" name))) + (tile (string->number (second (regexp-match #px"Tile (\\d+):" name))) (map string->list rows)))) -(define tiles - (map parse-tile input)) +(define tiles (map parse-tile input)) +(define dim (sqrt (length tiles))) +(define size (length (tile-image (first tiles)))) -(define (tile-edges tile) - (match-let ([(list name rows) tile]) - (list name (list (first rows) - (map last rows) - (reverse (last rows)) - (reverse (map first rows)))))) +;; Orientations (rotated and flipped) +(define (o1 image) image) +(define (o2 image) (reverse image)) +(define (o3 image) (map reverse image)) +(define (o4 image) (reverse (map reverse image))) +(define (o5 image) (map #{map (λ~> (list-ref %)) image} (range (length image)))) +(define (o6 image) (map #{map (λ~> (list-ref %)) (reverse image)} (range (length image)))) +(define (o7 image) (map #{map (λ~> (list-ref %)) image} (reverse (range (length image))))) +(define (o8 image) (map #{map (λ~> (list-ref %)) (reverse image)} (reverse (range (length image))))) -(define tiles-edges - (map tile-edges tiles)) +;; Image fits top and left when not false, respectively +;; fit-image: image? (or/c (listof char?) #f) (or/c (listof char?) #f) -> (or/c image? #f) +(define (fit-image image t l) + (define (left image) (map first image)) + (or (let ([i (o1 image)]) (and (or (not t) (equal? (first i) t)) (or (not l) (equal? (left i) l)) i)) + (let ([i (o2 image)]) (and (or (not t) (equal? (first i) t)) (or (not l) (equal? (left i) l)) i)) + (let ([i (o3 image)]) (and (or (not t) (equal? (first i) t)) (or (not l) (equal? (left i) l)) i)) + (let ([i (o4 image)]) (and (or (not t) (equal? (first i) t)) (or (not l) (equal? (left i) l)) i)) + (let ([i (o5 image)]) (and (or (not t) (equal? (first i) t)) (or (not l) (equal? (left i) l)) i)) + (let ([i (o6 image)]) (and (or (not t) (equal? (first i) t)) (or (not l) (equal? (left i) l)) i)) + (let ([i (o7 image)]) (and (or (not t) (equal? (first i) t)) (or (not l) (equal? (left i) l)) i)) + (let ([i (o8 image)]) (and (or (not t) (equal? (first i) t)) (or (not l) (equal? (left i) l)) i)))) -(define (corner? edges tiles) - (let ([tiles (map second tiles)]) - (= 2 (count #{for/or ([target tiles]) - (or (member % target) - (member (reverse %) target))} - edges)))) +;; Tile's image fits top and left when not false, respectively +;; fit-tile: tile? (or/c (listof char?) #f) (or/c (listof char?) #f) -> (or/c tile? #f) +(define (fit-tile t top left) + (let ([image (fit-image (tile-image t) top left)]) + (and image (struct-copy tile t [image image])))) + +;; Given the 0th to (i-1)th tiles, counting left-to-right then top-to-bottom, +;; find the remaining ith to last tiles that fit in the dim x dim grid +;; build-image: (hashof (list number? number?) tile?) number? -> (hashof (list number? number?) tile?) +(define (build-image image tiles i) + (let* ([r (quotient i dim)] + [c (remainder i dim)] + [top-tile (and (> r 0) (hash-ref image (list (sub1 r) c)))] + [left-tile (and (> c 0) (hash-ref image (list r (sub1 c))))] + [top (and top-tile (last (tile-image top-tile)))] + [left (and left-tile (map last (tile-image left-tile)))]) + (for/or ([tile tiles]) + (let* ([tile* (fit-tile tile top left)] + [image (hash-set image (list r c) tile*)]) + (and tile* (or (and (= (add1 i) (* dim dim)) image) + (build-image image (remove tile tiles) (add1 i)))))))) + +;; corner?: tile? -> boolean? +(define (corner? tile) + (define (edges tile) + (let ([image (tile-image tile)]) + (list (first image) (last image) + (map first image) (map last image)))) + (let ([tile-edges (edges tile)]) + (= 2 (count #{for/or ([other (remove tile tiles)]) + (let ([other-edges (edges other)]) + (or (member % other-edges) + (member (reverse %) other-edges)))} + tile-edges)))) + +;; Find a corner piece +;; corner: tile? +(define corner + (for/first ([tile tiles] + #:when (corner? tile)) + tile)) + +;; A mapping from positions in the layout to the correctly-oriented tile +;; (hashof (list number? number?) tile?) +(define image-hash + (let ([corner (λ (o) (struct-copy tile corner [image (o (tile-image corner))]))] + [tiles (remove corner tiles)]) + (or (build-image (hash (list 0 0) (corner o1)) tiles 1) + (build-image (hash (list 0 0) (corner o2)) tiles 1) + (build-image (hash (list 0 0) (corner o3)) tiles 1) + (build-image (hash (list 0 0) (corner o4)) tiles 1)))) + +;; The full image with borders removed +;; image: (listof (listof char?)) +(define image + (for/fold ([image '()] + #:result (o4 image)) + ([r dim]) + (append image + (for/fold ([rows (make-list (- size 2) '())]) + ([c dim]) + (let* ([image (tile-image (hash-ref image-hash (list r c)))] + [image (map #{drop-right (drop % 1) 1} (drop-right (drop image 1) 1))]) + (map append rows image)))))) + +(define dimsize (length image)) +(define image-vectors (lists->vectors image)) +(define (vector-pos r c) (vector-ref (vector-ref image-vectors r) c)) + +#| (r, c) = O + # +# ## ## O## <--- friend + # # # # # # +|# +(define (sea-monster-coords r c) + (list `(,(- r 1) ,(+ c 1)) + `(,r ,c) + `(,r ,(+ c 1)) + `(,r ,(+ c 2)) + `(,r ,(- c 5)) + `(,r ,(- c 6)) + `(,r ,(- c 11)) + `(,r ,(- c 12)) + `(,r ,(- c 17)) + `(,(+ r 1) ,(- c 1)) + `(,(+ r 1) ,(- c 4)) + `(,(+ r 1) ,(- c 7)) + `(,(+ r 1) ,(- c 10)) + `(,(+ r 1) ,(- c 13)) + `(,(+ r 1) ,(- c 16)))) + +;; sea-monster?: number? number? -> boolean? +(define (sea-monster? r c) + (define (pound? c) (char=? c #\#)) + (andmap #{pound? (vector-pos (first %) (second %))} + (sea-monster-coords r c))) + +;; A list of the neck coordinates of sea monsters +;; sea-monsters: (listof (list number? number?)) +(define sea-monsters + (for*/list ([r (range 1 (sub1 dimsize))] + [c (range 17 (- dimsize 2))] + #:when (and (andmap #{char=? (vector-pos r %)} + (range c (+ c 3))) + (sea-monster? r c))) + (list r c))) + +;; Replace the # of a sea monster with O in image-vectors +(define (reveal-sea-monster! r c) + (for-each #{vector-set! (vector-ref image-vectors (first %)) (second %) #\O} + (sea-monster-coords r c))) + +;; Reveal the sea monsters in image-vectors, then write to file +(define (draw-sea-monsters!) + (for-each #{reveal-sea-monster! (first %) (second %)} sea-monsters) + (display-lines-to-file + (map (λ~> vector->list list->string) + (vector->list image-vectors)) + "../input/20-image.txt" + #:exists 'replace)) (define part1 - (for/product ([tile tiles-edges] - #:when (corner? (second tile) - (remove tile tiles-edges))) - (first tile))) + (* (tile-name (hash-ref image-hash (list 0 0))) + (tile-name (hash-ref image-hash (list 0 (sub1 dim)))) + (tile-name (hash-ref image-hash (list (sub1 dim) 0))) + (tile-name (hash-ref image-hash (list (sub1 dim) (sub1 dim)))))) -(define part2 #f) +(define part2 + (- (count #{char=? % #\#} (apply append image)) + (* (length sea-monsters) 15))) (show-solution part1 part2)