Skip to content

Instantly share code, notes, and snippets.

@msgodf
Created December 11, 2012 08:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save msgodf/4256920 to your computer and use it in GitHub Desktop.
Save msgodf/4256920 to your computer and use it in GitHub Desktop.
Clojure solution to to "Radiation Search" problem on check.io
(ns cluster.core)
; Begin by creating 'clusters' for all the squares of a particular number
; Then repeatedly check for adjacent clusters and merge them
(defn random-grid
"A grid composed of random values in range [1,n]"
[size n]
(vec (map vec
(partition size
(repeatedly (* size size)
#(int (+ 1.5 (rand (dec n)))))))))
(def grid1to5
(random-grid 10 5))
(defn grid-clusters
"The coordinates of the n's within the grid"
[grid size n]
(apply vector
(map vector
(remove nil?
(for [x (range size)
y (range size)]
(when (= n (get-in grid [y x]))
[x y]))))))
(defn max-value-in-grid
[grid]
(apply max
(map #(apply max %)
grid)))
(defn max-with-index
[coll]
(apply max-key
val
(zipmap (range (count coll))
coll)))
(defn inc-index
[[a b]]
[(inc a) b])
(defn int-pairs
"Generate all sets of integers pairs in [0,n), excluding those of the form [a a]"
[n]
(mapcat #(map vector
(repeat %)
(range (inc %) n))
(range n)))
(defn adjacent?
"Given two pairs of (x,y) coordinates, checks whether they are adjacent to each other"
[[x1 y1] [x2 y2]]
(or (and (= y1 y2)
(or (= x1 (inc x2))
(= x1 (dec x2))))
(and (= x1 x2)
(or (= y1 (inc y2))
(= y1 (dec y2))))))
(defn clusters-adjacent?
"Check whether at least one point in the first cluster is adjacent to another in the other cluster"
[a b]
(some true?
(for [first-point a
second-point b]
(adjacent? first-point second-point))))
(defn remove-nth
"Removes the item specified by the index"
[coll index]
(mapcat vec [(take index coll)
(drop (inc index) coll)]))
(defn merge-clusters
"Replaces the first cluster by it merged with the second cluster, then removes the second cluster"
[clusters first-index second-index]
(vec (remove-nth (assoc clusters
first-index
(apply merge
(clusters first-index)
(clusters second-index)))
second-index)))
(defn first-adjacent-clusters
"Check all pairs of clusters, and returns the first pair that are adjacent, or nil if none are adjacent"
[clusters]
(first (remove nil?
(for [[a b] (int-pairs (count clusters))]
(when (clusters-adjacent? (clusters a)
(clusters b))
[a b])))))
(defn check-and-merge
"The core of the program, checks for adjacent clusters and merges them"
[c]
(loop [clusters c]
(if-let [[a b] (first-adjacent-clusters clusters)]
(recur (merge-clusters clusters a b))
clusters)))
(defn biggest-cluster
"Find the number that has the biggest cluster within the grid"
[grid]
(let [n (max-value-in-grid grid)
size (count (grid 0))]
(inc-index
(max-with-index
(map #(apply max
(map count
(check-and-merge (grid-clusters grid size %))))
(range 1 (inc n)))))))
(defn -main
"Create a random grid and output the biggest cluster"
[& args]
(let [grid (random-grid (Integer/parseInt (nth args 0))
(Integer/parseInt (nth args 1)))]
(do
(println (map #(clojure.string/join (concat (map str %) "\n")) grid))
(biggest-cluster grid))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment