diff src/find_words.clj @ 0:307a81e46071 tip

initial committ
author Robert McIntyre <rlm@mit.edu>
date Tue, 18 Oct 2011 01:17:49 -0700
parents
children
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/find_words.clj	Tue Oct 18 01:17:49 2011 -0700
     1.3 @@ -0,0 +1,174 @@
     1.4 +(ns coderloop.find-words
     1.5 +  (:use [clojure.contrib def
     1.6 +	 [seq :only [indexed]]
     1.7 +	 [duck-streams :only [read-lines file-str]]]
     1.8 +	[clojure.java io]
     1.9 +	[rlm shell-inspect]))
    1.10 +
    1.11 +
    1.12 +
    1.13 +"I'm going to solve this using convolution because I like how the kernel
    1.14 + looks for this problem.  For each word, we build up an asterisk kernel
    1.15 + like so:
    1.16 +
    1.17 + {:word \"Robert\"}
    1.18 + kernel:
    1.19 +
    1.20 +              t    t    t
    1.21 +               r   r   r
    1.22 +                e  e  e
    1.23 +                 b b b
    1.24 +                  ooo 
    1.25 +              treboRobert       
    1.26 +                  ooo           
    1.27 +                 b b b          
    1.28 +                e  e  e         
    1.29 +               r   r   r   
    1.30 +              t    t    t
    1.31 +
    1.32 +isn't it really cute-looking?
    1.33 +
    1.34 +Anyways,  I'll drag these asterisks along the word-matrix via convolution
    1.35 +and use them to build up a transient structure that contains only the matches.
    1.36 +
    1.37 +Then, I'll use that transitnt structure to remove all matches from the original
    1.38 +grid.
    1.39 +
    1.40 +I need stuff to do convolutions, to make kernels given a word, to create the
    1.41 +transient structure, and to remove the entries in the transient structure
    1.42 +from the original word-grid.  I also need a way to represent a word grid."
    1.43 +
    1.44 +(defvar strcat (partial apply str)
    1.45 +  "flattens a list by glomming everything together in a string.")
    1.46 +
    1.47 +(defn word-grid
    1.48 +  "create a mapping from elements in R^2 to chars"
    1.49 +  [words]
    1.50 +  (reduce
    1.51 +   merge
    1.52 +   (map (fn [[idx s]]
    1.53 +	  (zipmap 
    1.54 +	   (map #(vector (first %) idx) (indexed s))
    1.55 +	   (seq s)))
    1.56 +	(indexed words))))
    1.57 +
    1.58 +
    1.59 +(defn bounding-square
    1.60 +  "finds the minimal square it takes to bound the grid. works for all
    1.61 +   geometries."
    1.62 +  [grid]
    1.63 +  (let [coords (keys grid)
    1.64 +	xs (sort (map first coords))
    1.65 +	ys (sort (map second coords))]
    1.66 +    [(first xs) (last xs) (first ys) (last ys)]))
    1.67 +
    1.68 +;;I have no compunctinos with using mutable state in printing
    1.69 +(defn print-grid* [grid]
    1.70 +  (let [[x-min x-max y-min y-max] (bounding-square grid)
    1.71 +	canvas (atom
    1.72 +		(vec  (for [y  (range  (inc (- y-max y-min)))]
    1.73 +			(vec  (repeat (inc (- x-max x-min))  ".")))))]
    1.74 +    (dorun (map (fn [[[x y] c]]
    1.75 +		  (swap! canvas #(assoc-in % [ (- y y-min) (- x x-min)] c))) grid))
    1.76 +    @canvas))
    1.77 +	
    1.78 +(defn print-grid
    1.79 +  "nice for debugging but irrelevant for the rest of the problem"
    1.80 +  [grid]
    1.81 +  (dorun
    1.82 +   (for [line (print-grid* grid)]
    1.83 +     (do (dorun (map print line))
    1.84 +	 (println)))))
    1.85 +
    1.86 +(defn asterisk-kernel [word]
    1.87 +  (let [span (range (inc (count word)))]
    1.88 +    (vector
    1.89 +     (zipmap (map #(vector 0 %)     span) word)
    1.90 +     (zipmap (map #(vector 0 (- %)) span) word)
    1.91 +     (zipmap (map #(vector % %)     span) word)
    1.92 +     (zipmap (map #(vector % (- %)) span) word)
    1.93 +     (zipmap (map #(vector % 0)     span) word)
    1.94 +     (zipmap (map #(vector (- %) 0) span) word)
    1.95 +     (zipmap (map #(vector (- %) %)     span) word)
    1.96 +     (zipmap (map #(vector (- %)  (- %))     span) word))))
    1.97 +
    1.98 +;;this is not lazy :(
    1.99 +(defn search-grid-at-point [kernel grid [point-x point-y]]
   1.100 +  (let [shift-kernel
   1.101 +	(zipmap 
   1.102 +	 (map (fn [[x y]]
   1.103 +		[(+ x point-x)
   1.104 +		 (+ y point-y)])
   1.105 +	      (keys kernel))
   1.106 +	 (vals kernel))]
   1.107 +    (if (= (select-keys grid (keys shift-kernel))
   1.108 +	   shift-kernel)
   1.109 +      shift-kernel nil)))
   1.110 +    
   1.111 +(defn search-word-kernel
   1.112 +  "search the grid for a particular kernel and store the reusult in the
   1.113 +   atom (matches)"
   1.114 +  [grid kernel]
   1.115 +  (reduce merge (map (fn [point]
   1.116 +		       (search-grid-at-point kernel grid point))
   1.117 +		     (keys grid))))
   1.118 +
   1.119 +(defn search-word [grid word]
   1.120 +  (let [kernels (asterisk-kernel word)]
   1.121 +    (reduce merge (map #(search-word-kernel grid %) kernels))))
   1.122 +
   1.123 +(defn search-words [grid words]
   1.124 +  (reduce merge (map #(search-word grid %) words)))
   1.125 +
   1.126 +(defn remove-matches [grid matches]
   1.127 +  (apply (partial dissoc grid) (keys matches)))
   1.128 +
   1.129 +(defn grid->str [grid]
   1.130 +  (strcat (vals (apply sorted-map
   1.131 +		       (interleave (map (comp vec reverse) (keys grid)) (vals grid))))))
   1.132 +
   1.133 +(defn read-wordsearch [#^java.io.File input]
   1.134 +  (let [[crossword words] (split-with (comp not (partial = "")) (read-lines input)) 
   1.135 +	words (rest words)]
   1.136 +    [crossword words]))
   1.137 +
   1.138 +(defn process-wordsearch [[crossword words]]
   1.139 +  (let [grid (word-grid crossword)]
   1.140 +    (grid->str (remove-matches grid (search-words grid words)))))
   1.141 +
   1.142 +(defn doit [args]
   1.143 +  (println
   1.144 +   (process-wordsearch
   1.145 +    (read-wordsearch
   1.146 +     (file-str (first args))))))
   1.147 +
   1.148 +;;********************************************************************************
   1.149 +(if (command-line?)
   1.150 +  (doit *command-line-args*))
   1.151 +
   1.152 +
   1.153 +(def input (file-str "/home/r/coderloop-test/input.txt"))
   1.154 +(def a (file-str "/home/r/coderloop-test/findwords-a.in"))
   1.155 +(def d (file-str "/home/r/coderloop-test/findwords-d.in"))
   1.156 +(def c (file-str "/home/r/coderloop-test/findwords-c.in"))
   1.157 +(def e (file-str "/home/r/coderloop-test/findwords-e.in"))
   1.158 +
   1.159 +(def test-grid
   1.160 +      ["ELGOOGWWW"
   1.161 +       "TIRXMAHIR"
   1.162 +       "BATMANZNC"
   1.163 +       "CMRVLTOLD"])
   1.164 +
   1.165 +(def test-words
   1.166 +     ["MAIL"
   1.167 +      "WIN"
   1.168 +      "GOOGLE"
   1.169 +      "TAR"
   1.170 +      "BATMAN"
   1.171 +      "CAR"
   1.172 +      "WWW"
   1.173 +      "TOLD"
   1.174 +      "CD"])
   1.175 +
   1.176 +
   1.177 +