Solving N-Queens in Clojure. The N-Queens Problem The classic 8-queens problem is that of placing 8...
-
Upload
madlyn-mathews -
Category
Documents
-
view
213 -
download
1
Transcript of Solving N-Queens in Clojure. The N-Queens Problem The classic 8-queens problem is that of placing 8...
![Page 1: 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.](https://reader035.fdocuments.in/reader035/viewer/2022072015/56649ed35503460f94be3440/html5/thumbnails/1.jpg)
Solving N-Queens in Clojure
![Page 2: 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.](https://reader035.fdocuments.in/reader035/viewer/2022072015/56649ed35503460f94be3440/html5/thumbnails/2.jpg)
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.
• Edsger Dijkstra used this problem in 1972 to illustrate the power of what he called structured programming.
![Page 3: 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.](https://reader035.fdocuments.in/reader035/viewer/2022072015/56649ed35503460f94be3440/html5/thumbnails/3.jpg)
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.
![Page 4: 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.](https://reader035.fdocuments.in/reader035/viewer/2022072015/56649ed35503460f94be3440/html5/thumbnails/4.jpg)
Pattern for n-queens coming from allchains solution
(defn allchains [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))))
![Page 5: 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.](https://reader035.fdocuments.in/reader035/viewer/2022072015/56649ed35503460f94be3440/html5/thumbnails/5.jpg)
Recall conjall for generating collectionsconj 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.(defn conjall [lst vec] (cond (empty? lst) '() :else (conj (conj vec (first lst))
(conjall (rest lst1) vec)));(conjall '(4 5 6) [ 1 2 ]); => ([1 2 4] [1 2 5] [1 2 6])
![Page 6: 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.](https://reader035.fdocuments.in/reader035/viewer/2022072015/56649ed35503460f94be3440/html5/thumbnails/6.jpg)
List Comprehension using for List comprehension uses for for 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)
![Page 7: 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.](https://reader035.fdocuments.in/reader035/viewer/2022072015/56649ed35503460f94be3440/html5/thumbnails/7.jpg)
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 (psol i)]] (or ;check if pi and x share col or diagonal (= pi x) (= (- (count psol) i) (Math/abs (- x pi)))) )) ]
x))
![Page 8: 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.](https://reader035.fdocuments.in/reader035/viewer/2022072015/56649ed35503460f94be3440/html5/thumbnails/8.jpg)
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))92user=> (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])
![Page 9: 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.](https://reader035.fdocuments.in/reader035/viewer/2022072015/56649ed35503460f94be3440/html5/thumbnails/9.jpg)
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
![Page 10: 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.](https://reader035.fdocuments.in/reader035/viewer/2022072015/56649ed35503460f94be3440/html5/thumbnails/10.jpg)
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))
![Page 11: 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.](https://reader035.fdocuments.in/reader035/viewer/2022072015/56649ed35503460f94be3440/html5/thumbnails/11.jpg)
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]
![Page 12: 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.](https://reader035.fdocuments.in/reader035/viewer/2022072015/56649ed35503460f94be3440/html5/thumbnails/12.jpg)
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"
![Page 13: 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.](https://reader035.fdocuments.in/reader035/viewer/2022072015/56649ed35503460f94be3440/html5/thumbnails/13.jpg)
Here is a potential solution
• (defn non-iso [n] (filter canonical-pred? (n-queens n n))
![Page 14: 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.](https://reader035.fdocuments.in/reader035/viewer/2022072015/56649ed35503460f94be3440/html5/thumbnails/14.jpg)
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.