(ns adventofcode2019.day13 [:require [adventofcode2019.lib :refer :all] [adventofcode2019.intcode :as i] [clojure.string :as str] [clojure.core.match :refer [match]] [lanterna.terminal :as ts]]) (defn find-bounds [tiles] (let [x-list (map first (keys tiles)) y-list (map second (keys tiles)) min-x (reduce min x-list) max-x (reduce max x-list) min-y (reduce min y-list) max-y (reduce max y-list)] [[min-x max-x] [min-y max-y]])) (defn make-field [[dx dy]] (let [line (vec (repeat dx \space))] (mapv (constantly line) (range dy)))) (defn draw-tiles [tiles term] (let [to-text #(case % 0 \space 1 \| 2 \- 3 \_ 4 \O) paint-tile (fn [[[x y] tile]] (ts/move-cursor term x y) (ts/put-character term (to-text tile)))] (doall (map paint-tile tiles)))) (defn print-field [field score] (run! (comp println str/join) field) (println score) (flush)) (defn find-next-paddle-contact [screen prev-ball ball paddle] (let [db (map - ball prev-ball) [dx dy] db futr (take 50 (iterate (partial map + db) ball)) rdtn (fn [screen [bx by]] (if (or (= by paddle) (= dx 0)) (reduced bx) (reduced bx) #_(case (screen [bx by]) 1 (find-next-paddle-contact screen [bx by] [(- bx dx) by] paddle) 2 (find-next-paddle-contact screen [bx by] [(+ bx dx) (dec by)] paddle) screen))) px (reduce rdtn screen futr)] (if (= px screen) 0 px))) (defn run-game [game [[min-x max-x] [min-y max-y]]] (let [wait-for-output #(= (count (:output %)) 3) get-next-ic-output (partial i/intcode-until wait-for-output) new-game (assoc game :input [0]) field (ts/get-terminal :swing)] #_(ts/start field) (loop [program-state (get-next-ic-output new-game) screen {} score 0 framerate 0 ctr 0 prev-ball nil ball nil paddle nil joyst 1] #_(Thread/sleep framerate) (if (:exit program-state) (do #_(ts/stop field) score) (let [[x y t] (:output program-state) [new-score new-screen] (if (and (= x -1) (= y 0)) (do #_(ts/move-cursor field x y) #_(ts/put-string field (str t)) [t {}]) [score {[x y] t}]) screen (merge screen new-screen) #_(case (ts/get-key-blocking field {:interval framerate :timeout framerate}) \a -1 \d 1 0) paddle (if (= t 3) [x y] paddle) prev-ball (if (= t 4) ball prev-ball) ball (if (= t 4) [x y] ball) joyst (if (and prev-ball ball paddle) (compare (find-next-paddle-contact screen prev-ball ball (second paddle)) (first paddle)))] #_(draw-tiles new-screen field) (recur (get-next-ic-output (assoc program-state :output [] :input [joyst])) screen new-score 0 #_(if (> ctr 814) 0 0) (inc ctr) prev-ball ball paddle joyst)))))) (defn day13 [] (let [input (i/get-program (input-file)) output (:output (i/intcode (i/build-state input))) draw-tiles (fn [screen [x y t]] (assoc screen [x y] t)) screen (reduce draw-tiles {} (partition 3 output)) game (assoc-in (i/build-state input {:step true}) [:memory 0] 2)] (part1 (count (filter #(= % 2) (vals screen)))) (part2 (run-game game (find-bounds screen)))))