1 / 14

Solving N-Queens in Clojure

Solving N-Queens in Clojure. The N-Queens Problem. The classic 8-queens problem is that of placing 8 queens on a chessboard so that no pair is attacking. Franz Nauck in 1850 extended the chess problem to n-queens problem on an n×n board.

quynh
Download Presentation

Solving N-Queens in Clojure

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Solving N-Queens in Clojure

  2. The N-Queens Problem • The classic 8-queens problem is that of placing 8 queens on a chessboard so that no pair is attacking. • Franz Nauck in 1850 extended the chess problem to n-queens problem on an n×n board. • S. Günther proposed a method of finding solutions by using matrix determinants. • EdsgerDijkstra used this problem in 1972 to illustrate the power of what he called structured programming.

  3. Solution Design • Let us represent solution using vectors of column locations. • [5 3 6 0 7 1 4 2] is the solution above • We can write a generator that adds a queen to a new row as long as it is non-attacking. • A simple recursive generator function n-queens will • Take each solution to n-1 queens problem and apply map • which-queen is function to computes list of possible additions (we’ll use list comprehensions/for simplicity) • map the conjall using which queen to add to each partial solution • So n_queens() will take 2 parameters, the number of queens n (same as # rows) and m (or number of cols) of the board.

  4. Pattern for n-queens coming from allchains solution (defnallchains [n m] (cond (= n 0) '(()) :else (apply concat (map (fn [it] (conjall (range 1 (inc m)) it)) (allchains (dec n) m))))) (defn n-queens [n m] (cond (= n 0) '([]) :else (apply concat (map (fn [it] (conjall (which-queens it m) it)) (n-queens (dec n) m))))

  5. Recall conjall for generating collections conj is the standard op for building collections in Clojure. conj returns a new collection with the new item 'added'. The 'addition' may happen at different 'places' depending on the concrete type. user=> (conj [1 2 3] 4) => [1 2 3 4] user=> (conj '(1 2 3) 4) => (4 1 2 3) We write conjall with input a vector vec and a list lst… and returns a collection of all conj’s of lst elements onto the vec. (defnconjall [lstvec] (cond (empty? lst) '() :else (conj (conjvec (first lst)) (conjall (rest lst1) vec))) ;(conjall '(4 5 6) [ 1 2 ]) ; => ([1 2 4] [1 2 5] [1 2 6])

  6. List Comprehension using for List comprehension uses forfor generating lists. Takes a vector of one or more binding-form/collection-expr pairs, each followed by zero or more modifiers, and yields a lazy sequence of evaluations of expr. (for [x (range 6) y (range 5) :let [z (* x y)] :when (odd? z)] (list x y)) ;=> ((1 1) (1 3) (3 1) (3 3) (5 1) (5 3)) :when iterates over the bindings, but only evaluates the body of the loop when the condition is true. :while iterates over the bindings and evaluates the body until the condition is false: (for [x (range 20) :when (not= x 10)] x) ; =>(0 1 2 3 4 5 6 7 8 9 11 12 13 14 15 16 17 18 19) (for [x (range 20) :while (not= x 10)] x) ; => (0 1 2 3 4 5 6 7 8 9)

  7. Which-queens to add? ; for each possible col x return x ; if all other queens in partial sol psol are non-attacking (defn which-queens [psol m] (for [x (range m) :when (not-any? true? (for [i (range (count psol)) :let [pi (psoli)]] (or ;check if pi and x share color diagonal (= pi x) (= (- (count psol) i) (Math/abs (- x pi)))) )) ] x))

  8. That all! 92 solutions (defn n-queens [n m] (cond (= n 0) '([]) :else (apply concat (map (fn [it] (conjall (which-queens it m) it)) (n-queens (dec n) m)))) user=> (count (n-queens 8 8)) 92 user=> (n-queens 8 8) ([0 4 7 5 2 6 1 3] [0 5 7 2 6 3 1 4] [0 6 3 5 7 1 4 2] [0 6 4 7 1 3 5 2] [1 3 5 7 2 0 6 4] [1 4 6 0 2 7 5 3] [1 4 6 3 0 7 5 2] [1 5 0 6 3 7 2 4] [1 5 7 2 0 3 6 4] [1 6 2 5 7 4 0 3] [1 6 4 7 0 3 5 2] [1 7 5 0 2 4 6 3] [2 0 6 4 7 1 3 5] [2 4 1 7 0 6 3 5] [2 4 1 7 5 3 6 0] [2 4 6 0 3 1 7 5] [2 4 7 3 0 6 1 5] [2 5 1 4 7 0 6 3] [2 5 1 6 0 3 7 4] [2 5 1 6 4 0 7 3] [2 5 3 0 7 4 6 1] [2 5 3 1 7 4 6 0] [2 5 7 0 3 6 4 1] [2 5 7 0 4 6 1 3] [2 5 7 1 3 0 6 4] [2 6 1 7 4 0 3 5] [2 6 1 7 5 3 0 4] [2 7 3 6 0 5 1 4] [3 0 4 7 1 6 2 5] [3 0 4 7 5 2 6 1] [3 1 4 7 5 0 2 6] [3 1 6 2 5 7 0 4] [3 1 6 2 5 7 4 0] [3 1 6 4 0 7 5 2] [3 1 7 4 6 0 2 5] [3 1 7 5 0 2 4 6] [3 5 0 4 1 7 2 6] [3 5 7 1 6 0 2 4] [3 5 7 2 0 6 4 1] [3 6 0 7 4 1 5 2] [3 6 2 7 1 4 0 5] [3 6 4 1 5 0 2 7] [3 6 4 2 0 5 7 1] [3 7 0 2 5 1 6 4] [3 7 0 4 6 1 5 2] [3 7 4 2 0 6 1 5] [4 0 3 5 7 1 6 2] [4 0 7 3 1 6 2 5] [4 0 7 5 2 6 1 3] [4 1 3 5 7 2 0 6] [4 1 3 6 2 7 5 0] [4 1 5 0 6 3 7 2] [4 1 7 0 3 6 2 5] [4 2 0 5 7 1 3 6] [4 2 0 6 1 7 5 3] [4 2 7 3 6 0 5 1] [4 6 0 2 7 5 3 1] [4 6 0 3 1 7 5 2] [4 6 1 3 7 0 2 5] [4 6 1 5 2 0 3 7] [4 6 1 5 2 0 7 3] [4 6 3 0 2 7 5 1] [4 7 3 0 2 5 1 6] [4 7 3 0 6 1 5 2] [5 0 4 1 7 2 6 3] [5 1 6 0 2 4 7 3] [5 1 6 0 3 7 4 2] [5 2 0 6 4 7 1 3] [5 2 0 7 3 1 6 4] [5 2 0 7 4 1 3 6] [5 2 4 6 0 3 1 7] [5 2 4 7 0 3 1 6] [5 2 6 1 3 7 0 4] [5 2 6 1 7 4 0 3] [5 2 6 3 0 7 1 4] [5 3 0 4 7 1 6 2] [5 3 1 7 4 6 0 2] [5 3 6 0 2 4 1 7] [5 3 6 0 7 1 4 2] [5 7 1 3 0 6 4 2] [6 0 2 7 5 3 1 4] [6 1 3 0 7 4 2 5] [6 1 5 2 0 3 7 4] [6 2 0 5 7 4 1 3] [6 2 7 1 4 0 5 3] [6 3 1 4 7 0 2 5] [6 3 1 7 5 0 2 4] [6 4 2 0 5 7 1 3] [7 1 3 0 6 4 2 5] [7 1 4 2 0 6 3 5] [7 2 0 5 1 4 6 3] [7 3 0 2 5 1 6 4])

  9. Isomorph Rejection Problem • Not all of the 92 solutions found can be considered unique, in the sense that rotating or flipping the board around can result in another solution found in the set. • 8 transformations that map the chess-board to itself; 4 rotations of 90 degrees, and 4 reflections --the so-called dihedral group D8 of automorphisms of the square. • A solution (based on perfect hashing) is to consider each solution of N-Queens as a base N+1 number. We can generate solutions in numeric order, and test if a solution is isomorphic to a previously found solution if and only if one of the 8 transformations produces a solution, which is numerically (or, more generally, lexicographically) less than the original We can lexicographically compare solutions as follows… user=> (compare [0 4 7 5 2 6 1 3] [7 1 3 0 6 4 2 5]) -1

  10. Working with immutability is sometimes difficult (This may not be best work around) To work in an immutable fashion we will expand and collapse each vector using a list of [row-index col-index] pairs as intermediate solution. ; (def a (first (n-queens 8 8)) (defn expand [sol] (map vector (range 8) sol) ) ;(expand a) ;=>([0 7] [1 3] [2 0] [3 2] [4 5] [5 1] [6 6] [7 4]) If [i j] is a queen in sol, then [j 7-i] is a queen in (rotate sol) If [i j] is a queen in sol, then [i 7-j] is a queen in (reflect sol) (defn rotate [sol] ( map (fn[x] (let [[ i j] x] (vector j (- 7 i)))) sol)) (defn reflect [sol] ( map (fn[x] (let [[ i j] x] (vector i (- 7 j)))) sol))

  11. Expand and Collapse Transformed Solutions (reflect (expand a)) ;=> ([0 7] [1 3] [2 0] [3 2] [4 5] [5 1] [6 6] [7 4]) ; (sort (rotate (expand a))) ;=> ([0 7] [1 1] [2 3] [3 0] [4 6] [5 4] [6 2] [7 5]) (defn collapse [p] (into [] (map (fn[ij] (last ij)) p))) ;(collapse '([0 7] [1 1] [2 3] [3 0] [4 6] [5 4] [6 2] [7 5])) ;=> [7 1 3 0 6 4 2 5]

  12. into lets you take anything seq'able • Take a list, vector, map, set, sorted-map and an empty container you want filled. • (into [] '(1 2 3 4)) ==> [1 2 3 4] "have a lazy list and want a vector" • into #{} [1 2 3 4]) ==> #{1 2 3 4} "have a vector and want a set" • > (into {} #{[1 2] [3 4]}) ==> {3 4, 1 2} "have a set of vectors want a map" • > (into #{} [{1 2} {3 4}]) ==> #{{1 2} {3 4}} "have a vector of maps want a set of maps"

  13. Here is a potential solution • (defn non-iso [n] (filter canonical-pred? (n-queens n n))

  14. Homework #3 • How many orbits/non-iso solutions? • How many are full (size 8) and degenerate? • Catalog the fixed configurations of 8 symmetries. • Write clojure program to produce list of all canonical (non-isomorphic) solution vectors.

More Related