]> localhost Git - adventofcode2019.git/blob - src/adventofcode2019/day13.clj
03aa4fd8840a4080d681ead102eb085d6030e963
[adventofcode2019.git] / src / adventofcode2019 / day13.clj
1 (ns adventofcode2019.day13
2 [:require [adventofcode2019.lib :refer :all]
3 [adventofcode2019.intcode :as i]
4 [clojure.string :as str]
5 [clojure.core.match :refer [match]]
6 [lanterna.terminal :as ts]])
7
8 (defn find-bounds [tiles]
9 (let [x-list (map first (keys tiles))
10 y-list (map second (keys tiles))
11 min-x (reduce min x-list)
12 max-x (reduce max x-list)
13 min-y (reduce min y-list)
14 max-y (reduce max y-list)]
15 [[min-x max-x] [min-y max-y]]))
16
17 (defn make-field [[dx dy]]
18 (let [line (vec (repeat dx \space))]
19 (mapv (constantly line) (range dy))))
20
21 (defn draw-tiles [tiles term]
22 (let [to-text #(case %
23 0 \space
24 1 \|
25 2 \-
26 3 \_
27 4 \O)
28 paint-tile (fn [[[x y] tile]]
29 (ts/move-cursor term x y)
30 (ts/put-character term (to-text tile)))]
31 (doall (map paint-tile tiles))))
32
33 (defn print-field [field score]
34 (run! (comp println str/join) field)
35 (println score)
36 (flush))
37
38 (defn find-next-paddle-contact [screen prev-ball ball paddle]
39 (let [db (map - ball prev-ball)
40 [dx dy] db
41 futr (take 50 (iterate (partial map + db) ball))
42 rdtn (fn [screen [bx by]]
43 (if (or (= by paddle) (= dx 0))
44 (reduced bx)
45 (reduced bx)
46 #_(case (screen [bx by])
47 1 (find-next-paddle-contact screen [bx by] [(- bx dx) by] paddle)
48 2 (find-next-paddle-contact screen [bx by] [(+ bx dx) (dec by)] paddle)
49 screen)))
50 px (reduce rdtn screen futr)]
51 (if (= px screen) 0 px)))
52
53 (defn run-game [game [[min-x max-x] [min-y max-y]]]
54 (let [wait-for-output #(= (count (:output %)) 3)
55 get-next-ic-output (partial i/intcode-until wait-for-output)
56 new-game (assoc game :input [0])
57 field (ts/get-terminal :swing)]
58 #_(ts/start field)
59 (loop [program-state (get-next-ic-output new-game)
60 screen {}
61 score 0
62 framerate 0
63 ctr 0
64 prev-ball nil
65 ball nil
66 paddle nil
67 joyst 1]
68 #_(Thread/sleep framerate)
69 (if (:exit program-state)
70 (do #_(ts/stop field)
71 score)
72 (let [[x y t] (:output program-state)
73 [new-score new-screen] (if (and (= x -1) (= y 0))
74 (do #_(ts/move-cursor field x y)
75 #_(ts/put-string field (str t))
76 [t {}])
77 [score {[x y] t}])
78 screen (merge screen new-screen)
79 #_(case (ts/get-key-blocking field {:interval framerate
80 :timeout framerate})
81 \a -1
82 \d 1
83 0)
84 paddle (if (= t 3) [x y] paddle)
85 prev-ball (if (= t 4) ball prev-ball)
86 ball (if (= t 4) [x y] ball)
87 joyst (if (and prev-ball ball paddle)
88 (compare (find-next-paddle-contact screen prev-ball ball (second paddle)) (first paddle)))]
89 #_(draw-tiles new-screen field)
90 (recur (get-next-ic-output (assoc program-state
91 :output []
92 :input [joyst]))
93 screen new-score 0 #_(if (> ctr 814) 0 0) (inc ctr)
94 prev-ball ball paddle joyst))))))
95
96 (defn day13 []
97 (let [input (i/get-program (input-file))
98 output (:output (i/intcode (i/build-state input)))
99 draw-tiles (fn [screen [x y t]] (assoc screen [x y] t))
100 screen (reduce draw-tiles {} (partition 3 output))
101 game (assoc-in (i/build-state input {:step true}) [:memory 0] 2)]
102 (part1 (count (filter #(= % 2) (vals screen))))
103 (part2 (run-game game (find-bounds screen)))))