[2015-02-02] Challenge #200 [Easy] Flood-FillThe challenge is to flood-fill an ASCII image. | (ns daily.easy-200 (:require [dommy.core :refer-macros [sel1]] [reagent.core :as reagent :refer [atom]] [clojure.string :as str])) |
Solution | |
Read in the input string and divide it into dimensions, the array, and fill arguments. | (defn read-input [input-text] (let [all-lines (str/split-lines input-text) data-lines (butlast (drop 1 all-lines)) fill-args (str/split (last all-lines) #" ")] [(vec (map vec data-lines)) (vec (reverse (map js/parseInt (take 2 fill-args)))) (last fill-args)])) |
Find all of the neighbors of a cell that would be filled from that cell. Neighbors must be inside of the bounds of the array and have the same contents. | (defn matching-neighbors [array point] (for [[dx dy] [[1 0] [0 1] [-1 0] [0 -1]] :let [char (get-in array point) [x y] point x' (+ x dx) y' (+ y dy)] :when (and (>= x' 0) (>= y' 0) (< y' (count array)) (< x' (count (get array y'))) (= char (get-in array [x' y'])))] [x' y'])) |
Perform one step of the flood fill.
| (defn flood-fill-step [[array fill-points fill-char]] [(reduce #(assoc-in %1 %2 fill-char) array fill-points) (set (mapcat #(matching-neighbors array %) fill-points)) fill-char]) |
Repeatedly call | (defn flood-fill [array fill-point fill-char] (->> (iterate flood-fill-step [array [fill-point] fill-char]) (drop-while #(not (empty? (get % 1)))) first)) |
Take just the data array and format it nicely. | (defn write-output [array] (->> array first (map str/join) (str/join \newline))) |
Put it all together and print a helpful message when there is a problem.
| (defn process-input [input-text] (try (write-output (apply flood-fill (read-input input-text))) (catch :default e (str "Problem with processing input: " e)))) |
Result | |
(defonce input-text (atom "9 9 aaaaaaaaa aaadefaaa abcdafgha abcdafgha abcdafgha abcdafgha aacdafgaa aaadafaaa aaaaaaaaa 8 3 ,")) | |
Input | (defn input-component [] (fn [] [:textarea {:cols 37 :rows 24 :on-change #(reset! input-text (-> % .-target .-value)) :value @input-text}])) (reagent/render-component [input-component] (sel1 :#input)) |
Output | (defn output-component [] (fn [] [:textarea {:cols 37 :rows 24 :read-only true :value (process-input @input-text)}])) (reagent/render-component [output-component] (sel1 :#output)) |