| 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 | [clojure.math.combinatorics :as combo] |
| 7 | [lanterna.terminal :as ts]]) |
| 8 | |
| 9 | (def term (ts/get-terminal :text)) |
| 10 | |
| 11 | (defn find-bounds [tiles] |
| 12 | (let [x-list (map first (keys tiles)) |
| 13 | y-list (map second (keys tiles)) |
| 14 | min-x (reduce min x-list) |
| 15 | max-x (reduce max x-list) |
| 16 | min-y (reduce min y-list) |
| 17 | max-y (reduce max y-list)] |
| 18 | [[min-x max-x] [min-y max-y]])) |
| 19 | |
| 20 | (defn make-field [[dx dy]] |
| 21 | (let [line (vec (repeat dx \space))] |
| 22 | (mapv (constantly line) (range dy)))) |
| 23 | |
| 24 | (defn draw-tiles [tiles term] |
| 25 | (let [to-text #(case % |
| 26 | 0 \space |
| 27 | 1 \| |
| 28 | 2 \- |
| 29 | 3 \_ |
| 30 | 4 \O) |
| 31 | paint-tile (fn [[[x y] tile]] |
| 32 | (ts/move-cursor term x y) |
| 33 | (ts/put-character term (to-text tile)))] |
| 34 | (doall (map paint-tile tiles)))) |
| 35 | |
| 36 | (defn print-field [field score] |
| 37 | (run! (comp println str/join) field) |
| 38 | (println score) |
| 39 | (flush)) |
| 40 | |
| 41 | (defn run-game [game [[min-x max-x] [min-y max-y]]] |
| 42 | (let [wait-for-output #(= (count (:output %)) 3) |
| 43 | get-next-ic-output (partial i/intcode-until wait-for-output) |
| 44 | new-game (assoc game :input [0]) |
| 45 | field (ts/get-terminal :swing)] |
| 46 | (ts/start field) |
| 47 | (ts/put-character field \a) |
| 48 | (loop [program-state (get-next-ic-output new-game) |
| 49 | score 0 |
| 50 | framerate 0 |
| 51 | ctr 0] |
| 52 | (Thread/sleep framerate) |
| 53 | (if (:exit program-state) |
| 54 | (do (ts/stop field) |
| 55 | score) |
| 56 | (let [[x y t] (:output program-state) |
| 57 | [new-score new-screen] (if (and (= x -1) (= y 0)) |
| 58 | [t {}] |
| 59 | [score {[x y] t}]) |
| 60 | input (case (ts/get-key-blocking field {:interval 1 :timeout framerate}) |
| 61 | \a -1 |
| 62 | \d 1 |
| 63 | 0)] |
| 64 | (draw-tiles new-screen field) |
| 65 | (recur (get-next-ic-output (assoc program-state |
| 66 | :output [] |
| 67 | :input [input])) |
| 68 | new-score (if (> ctr 814) 100 0) (inc ctr))))))) |
| 69 | |
| 70 | (defn day13 [] |
| 71 | (let [input (i/get-program (input-file)) |
| 72 | output (:output (i/intcode (i/build-state input))) |
| 73 | draw-tiles (fn [screen [x y t]] (assoc screen [x y] t)) |
| 74 | screen (reduce draw-tiles {} (partition 3 output)) |
| 75 | game (assoc-in (i/build-state input {:step true}) [:memory 0] 2)] |
| 76 | (part1 (count (filter #(= % 2) (vals screen)))) |
| 77 | (part2 (run-game game (find-bounds screen))))) |