aoc2019/3.rkt

161 lines
5.1 KiB
Racket

#lang racket
(define (parse-wire s)
(map parse-seg (string-split (string-trim s) ",")))
(define wire-defs
(string-split (string-trim (file->string "input.3.txt")) "\n"))
(define-struct seg (dir len))
(define-struct aseg (x1 y1 x2 y2))
(define-struct pt (x y))
(define (pa a) (list (aseg-x1 a) (aseg-y1 a) (aseg-x2 a) (aseg-y2 a)))
(define (pp p) (list (pt-x p) (pt-y p)))
(define (parse-seg str)
(make-seg
(string->symbol (substring str 0 1))
(string->number (substring str 1))))
(define wires (map parse-wire wire-defs))
(define (make-norm-aseg x1 y1 x2 y2)
(let ([nx1 (min x1 x2)]
[nx2 (max x1 x2)]
[ny1 (min y1 y2)]
[ny2 (max y1 y2)])
(make-aseg nx1 ny1 nx2 ny2)))
(define (seg->aseg seg x y)
(let ([dx (* (seg-len seg)
(match (seg-dir seg)
['R 1]
['L -1]
[_ 0]))]
[dy (* (seg-len seg)
(match (seg-dir seg)
['U 1]
['D -1]
[_ 0]))])
(values (make-norm-aseg x y (+ x dx) (+ y dy)) (+ x dx) (+ y dy))))
(define (wire->asegwire wire)
(define (wire->asegwire+ wire x y)
(cond
[(empty? wire) '()]
[else (let-values ([(aseg newx newy) (seg->aseg (first wire) x y)])
(cons aseg (wire->asegwire+ (rest wire) newx newy)))]))
(wire->asegwire+ wire 0 0))
(define aseg-wires (map wire->asegwire wires))
(define (horiz? aseg)
(= (aseg-y1 aseg) (aseg-y2 aseg)))
(define (vert? aseg)
(= (aseg-x1 aseg) (aseg-x2 aseg)))
(define (cross aseg1 aseg2)
(cond
;; both horizontal
[(and (horiz? aseg1) (horiz? aseg2) (= (aseg-y1 aseg1) (aseg-y1 aseg2))
(>= (aseg-x2 aseg2) (aseg-x1 aseg1))
(<= (aseg-x1 aseg2) (aseg-x2 aseg1)))
(list (make-pt (max (aseg-x1 aseg1) (aseg-x1 aseg2)) (aseg-y1 aseg1))
(make-pt (min (aseg-x2 aseg1) (aseg-x2 aseg2)) (aseg-y1 aseg1)))]
;; both vertical
[(and (vert? aseg1) (vert? aseg2) (= (aseg-x1 aseg1) (aseg-x1 aseg2))
(>= (aseg-y2 aseg2) (aseg-y1 aseg1))
(<= (aseg-y1 aseg2) (aseg-y2 aseg1)))
(list (make-pt (aseg-x1 aseg1) (max (aseg-y1 aseg1) (aseg-y1 aseg2)))
(make-pt (aseg-x1 aseg1) (min (aseg-y2 aseg1) (aseg-y2 aseg2))))]
;; h/v
[(and (horiz? aseg1) (vert? aseg2)
(>= (aseg-x1 aseg2) (aseg-x1 aseg1))
(<= (aseg-x1 aseg2) (aseg-x2 aseg1))
(>= (aseg-y1 aseg1) (aseg-y1 aseg2))
(<= (aseg-y1 aseg1) (aseg-y2 aseg2)))
(list (make-pt (aseg-x1 aseg2) (aseg-y1 aseg1)))]
;; v/h
[(and (vert? aseg1) (horiz? aseg2)
(>= (aseg-x1 aseg1) (aseg-x1 aseg2))
(<= (aseg-x1 aseg1) (aseg-x2 aseg2))
(>= (aseg-y1 aseg2) (aseg-y1 aseg1))
(<= (aseg-y1 aseg2) (aseg-y2 aseg1)))
(list (make-pt (aseg-x1 aseg1) (aseg-y1 aseg2)))]
[else '()]))
(define (aseg-cross aseg wire)
(cond
[(empty? wire) '()]
[else
(append (cross aseg (first wire)) (aseg-cross aseg (rest wire)))]))
(define (get-crossings+ wire1 wire2)
(cond
[(empty? wire1) '()]
[else (append (aseg-cross (first wire1) wire2) (get-crossings (rest wire1) wire2))]))
(define (get-crossings wire1 wire2)
(filter (lambda (p) (not (and (zero? (pt-x p)) (zero? (pt-y p)))))
(get-crossings+ wire1 wire2)))
(define crossings (get-crossings (first aseg-wires) (second aseg-wires)))
(define (manhattan pt)
(+ (abs (pt-x pt)) (abs (pt-y pt))))
(define (min-crossing crs)
(cond
[(empty? crs) +inf.0]
[else (min (manhattan (first crs)) (min-crossing (rest crs)))]))
;; Part 1
;; Holy SHIT i cannot believe this was actually the right answer WTF
;; i assumed i made some sort of typo in cross lol
;; UPDATE:
;; i had a bug where i forgot to have make-norm-aseg actually work
;; and THEN i also forgot to filter crossing '(0 0)
;; BUT this somehow didn't affect the answer for part 1
;; i just got screwed on part 2
;; anyway now both work
(displayln (min-crossing crossings))
(define (aseg-on-pt aseg pt)
(or
(and (= (pt-x pt) (aseg-x1 aseg) (aseg-x2 aseg))
;; yeah so i remembered that <= can take more than 2 args here
;; way before writing (cross)
;; huge oof
(<= (aseg-y1 aseg) (pt-y pt) (aseg-y2 aseg)))
(and (= (pt-y pt) (aseg-y1 aseg) (aseg-y2 aseg))
(<= (aseg-x1 aseg) (pt-x pt) (aseg-x2 aseg)))))
(define (aseg-pt-dist aseg pt)
(cond
[(horiz? aseg) (- (pt-x pt) (aseg-x1 aseg))]
[(vert? aseg) (- (pt-y pt) (aseg-y1 aseg))]))
(define (aseg-len aseg)
(+
(- (aseg-x2 aseg) (aseg-x1 aseg))
(- (aseg-y2 aseg) (aseg-y1 aseg))))
(define (get-steps wire pt)
(cond
[(empty? wire) (error "thinking")]
[else
(cond
[(aseg-on-pt (first wire) pt)
(aseg-pt-dist (first wire) pt)]
[else
(+ (aseg-len (first wire)) (get-steps (rest wire) pt))])]))
(define (min-len-crossing crs wire1 wire2)
(cond
[(empty? crs) +inf.0]
[else (min (+ (get-steps wire1 (first crs)) (get-steps wire2 (first crs)))
(min-len-crossing (rest crs) wire1 wire2))]))
;; Part 2
(displayln (min-len-crossing crossings (first aseg-wires) (second aseg-wires)))