wk3.ss 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. ; testing for validity of solution BOOLEAN
  2. (define (attack? state)
  3. (or (horizontal? state)
  4. (diagonal? state)))
  5. ; are there horizontal attacks?
  6. (define (horizontal? state)
  7. (let ((lst (vector->list state)))
  8. (dup? lst)))
  9. ; does the list contain duplicates?
  10. (define (dup? lst)
  11. (if
  12. (null? lst)
  13. #f
  14. (if (and (<= 0 (car lst)) ; -1 doesn't matter
  15. (member (car lst) (cdr lst)))
  16. #t
  17. (dup? (cdr lst)))))
  18. ; are there diagonal attacks? pt 1
  19. (define (diagonal? state)
  20. (let ((lst (vector->list state)) (n (vector-length state)))
  21. (if (null? lst)
  22. #f
  23. (or
  24. (diagonal2? lst (- n 1))
  25. (diagonal? (list->vector (cdr lst)))))))
  26. ; diagonal? pt 2
  27. (define (diagonal2? lst n)
  28. (if (= n 0)
  29. #f
  30. (let* ((elem (list-ref lst n)) (nonneg (not (or (= -1 (car lst)) (= -1 elem)))))
  31. (or
  32. (and (eqv? (car lst) (+ elem n)) nonneg)
  33. (and (eqv? (car lst) (- elem n)) nonneg)
  34. (diagonal2? lst (- n 1))))))
  35. ; testing for validity of solution NUMBER OF ATTACKS
  36. (define (attacks state col)
  37. (+ (horizontals state col)
  38. (diagonals state col)))
  39. ; Horizontal attacks
  40. (define (horizontals state col)
  41. (let ((lst (vector->list state)))
  42. (dups lst col)))
  43. ; Diagonal attacks wrapper
  44. (define (diagonals state col)
  45. (let ((lst (vector->list state)) (n (vector-length state)))
  46. (if (null? lst)
  47. 0
  48. (let* ((elem (list-ref lst col)) ; current value of the column I'm working with
  49. (newlst (list-mute lst col -1))) ; unassign the column I'm working with
  50. (diagonals2 newlst elem (- (- n 1) col) col))))) ; (n-1)-col = max distance a diagonal attack can be
  51. ; Diagonal attacks recursive core
  52. (define (diagonals2 lst elem dist col)
  53. (if (= 0 dist)
  54. 0
  55. (if (> (- col dist) 0) ; if there are two possible diagonals
  56. (let ((elem1 (list-ref lst (+ col dist))) ; the element n ahead - check for being n more or n less
  57. (elem2 (list-ref lst (- col dist)))) ; the element n behind - check for being n more or n less
  58. (if (and
  59. (or (= elem1 (+ elem dist)) (= elem1 (- elem dist)))
  60. (or (= elem2 (+ elem dist)) (= elem2 (- elem dist))))
  61. (+ 2 (diagonals2 lst elem (- dist 1) col)) ; if both, add 2 and recurse
  62. (if (or
  63. (or (= elem1 (+ elem dist)) (= elem1 (- elem dist)))
  64. (or (= elem2 (+ elem dist)) (= elem2 (- elem dist))))
  65. (+ 1 (diagonals2 lst elem (- dist 1) col)) ; if one, add 1 and recurse
  66. (diagonals2 lst elem (- dist 1) col)))) ; else, recurse
  67. (let ((elem1 (list-ref lst (+ col dist)))) ; only one possible diagonal from here
  68. (if (or (= elem1 (+ elem dist)) (= elem1 (- elem dist))) ; check for being n more or n less
  69. (+ 1 (diagonals2 lst elem (- dist 1) col)) ; if so, add 1 and recurse
  70. (diagonals2 lst elem (- dist 1) col))))))
  71. ; Number of duplicates wrapper
  72. (define (dups lst col)
  73. (let ((elem (list-ref lst col))
  74. (newlst (list-mute lst col -1)))
  75. (if (null? lst)
  76. 0
  77. (appears elem newlst))))
  78. ; Number of duplicates recursive core
  79. (define (appears elem lst)
  80. (if (null? lst)
  81. 0
  82. (if (eqv? (car lst) elem)
  83. (+ 1 (appears elem (cdr lst)))
  84. (appears elem (cdr lst)))))
  85. ; are there no attacks and are there any -1 (unassigned) columns?
  86. (define (valid? state)
  87. (and
  88. state
  89. (not (attack? state))
  90. (not (member -1 (vector->list state)))))
  91. ; select new column as equal to the search level
  92. ; mode 1 = in order
  93. ; mode 2 = inside out
  94. ; mode 3 = outside in
  95. (define (select-new-column level length mode)
  96. (if (= mode 1)
  97. level
  98. (if (= mode 2)
  99. (inside-out level length)
  100. (outside-in level length))))
  101. ; select columns from the inside out
  102. (define (inside-out level length)
  103. (if (= level length)
  104. (- level 1)
  105. (if (even? level)
  106. (+ (floor (/ length 2)) (/ level 2))
  107. (- (floor (/ length 2)) (/ (+ level 1) 2)))))
  108. ; select columns from the outside in
  109. (define (outside-in level length)
  110. (if (= level length)
  111. (floor (/ level 2))
  112. (if (odd? level)
  113. (- length (/ (+ 1 level) 2))
  114. (- length (- length (/ level 2))))))
  115. ; Backtracking!
  116. ; initialize steps & level as 0
  117. ; state should be initialized all -1 (queengen does this)
  118. ; colmode: 1 is 0 to N, 2 is inside out (doesn't work), 3 is outside in
  119. (define (backtrack state steps level colmode)
  120. ;(print (list state steps)) ; diagnostic
  121. (if (valid? state)
  122. (list state steps)
  123. (let* ((len (vector-length state))
  124. (col (select-new-column level len colmode)))
  125. (if (= level len) ; if past the last column
  126. (if (valid? state) ; if success, return - else fail
  127. (list state steps)
  128. (list #f steps))
  129. (let* ((newcol (select-new-column (+ level 1) len colmode)) ; if not past the last column, get new column
  130. (queen (recur-row state newcol -1)))
  131. (if (= queen -1)
  132. (list #f steps)
  133. (let* ((nextstate (vector-mute state newcol queen)) ; try the next column
  134. (result (backtrack nextstate (+ 1 steps) (+ level 1) colmode)))
  135. (if (car result) ; if state successful, return
  136. result
  137. (let ((elem (+ 1 (vector-ref state col))) ; else find next queen
  138. ; number of steps is extra since result + current
  139. (newsteps (+ (abs (- (cadr result) steps)) steps)))
  140. (if (>= elem (- len 1)) ; if new queen is off the board, fail
  141. (list #f newsteps)
  142. (let ((newstate (vector-mute state col elem))) ; else try this column again
  143. (backtrack newstate (+ newsteps 1) level colmode))))))))))))
  144. ; make a board state where all = -1
  145. ; except the first, which = 0
  146. (define (queengen n)
  147. (let ((vec (make-vector n -1)))
  148. (vector-mute vec 0 0)))
  149. ; test the validity of putting a queen in each row of a column
  150. ; picks the first row that generates no attacks
  151. ; used in backtracking
  152. ; intial call should have row == -1
  153. (define (recur-row state col row)
  154. (if (< row 0) ; if we're just starting
  155. (let ((newstate (vector-mute state col 0))) ; set the row value of col to 0
  156. (recur-row newstate col 0))
  157. (if (>= row (vector-length state)) ; if we're past the end then I can't put a queen anywhere
  158. -1 ; and should unassign the column
  159. (if (not (attack? state))
  160. row
  161. (let ((newstate (vector-mute state col (+ 1 row))))
  162. (recur-row newstate col (+ 1 row))))))) ; try the next row in this column
  163. ; utility function - returns a new list of same length as input
  164. ; element in <col> will be <val>, all the rest will be the same as original
  165. (define (list-mute lst col val)
  166. (if (= 0 col)
  167. (cons val (cdr lst)) ; if I want the first element in the list
  168. (cons (car lst) (list-mute (cdr lst) (- col 1) val)))) ; if I want a later element
  169. ; apply list-mute to a vector - simple wrapper
  170. (define (vector-mute vec col val)
  171. (if (= col (vector-length vec))
  172. vec
  173. (list->vector (list-mute (vector->list vec) col val))))
  174. ; ~~~~~ Min-Conflicts! ~~~~~
  175. ; initialize lastcol to -1 and steps to 0
  176. (define (min-conflicts state lastcol steps maxsteps)
  177. ;(print (list state steps)) ; diagnostic
  178. (if (= maxsteps 0) ; if we're out of steps
  179. (list #f steps) ; failz0rz
  180. (if (valid? state)
  181. (list steps) ; you are a winnar!
  182. ; you are not a winnar - please try again
  183. (let* ((col (select-conflicting-column state lastcol 0)) ; pick a column with conflicts
  184. (row (least-conflicts state col)) ; and the row in it with fewest conflicts
  185. (newstate (vector-mute state col row))) ; and make a new state
  186. (min-conflicts newstate col (+ steps 1) (- maxsteps 1)))))) ; and iterate!
  187. ; ~~~~~ Randomly initialize board states ~~~~~
  188. ; initialize a board state greedily (has element of randomnity)
  189. ; wrapper
  190. (define (initialize-g n)
  191. (let ((state (make-vector n 0)))
  192. (init-greedy state 0)))
  193. ; recursive core
  194. (define (init-greedy state col)
  195. (if (= col (vector-length state))
  196. state
  197. (let* ((row (least-conflicts state col))
  198. (newstate (vector-mute state col row)))
  199. (init-greedy newstate (+ 1 col)))))
  200. ; initialize a board state randomly - wrapper
  201. (define (initialize-r n)
  202. (let ((state (make-vector n 0)))
  203. (init-random state 0)))
  204. ; recursive core
  205. (define (init-random state col)
  206. (if (= col (vector-length state))
  207. state
  208. (let* ((row (random (vector-length state)))
  209. (newstate (vector-mute state col row)))
  210. (init-random newstate (+ 1 col)))))
  211. ; select random conflicting column
  212. (define (select-conflicting-column state lastcol level)
  213. (let ((col (random (vector-length state))))
  214. (if (or (and (< 0 (attacks state col)) (not (= col lastcol))) (= level 10))
  215. col
  216. (select-conflicting-column state lastcol (+ level 1)))))
  217. ; select column with most conflicts - no good
  218. (define (select-conflictingest-column state col)
  219. (if (= col (- (vector-length state) 1))
  220. (attacks state col)
  221. (let* ((current (attacks state col))
  222. (futurecol (select-conflictingest-column state (+ 1 col)))
  223. (future (attacks state futurecol)))
  224. (if (> current future)
  225. col
  226. futurecol))))
  227. ; choose the row in col that generates the fewest conflicts
  228. (define (least-conflicts state col)
  229. (let ((base (vector-mute state col 0)))
  230. (least-cons base 0 col)))
  231. (define (least-cons state row col)
  232. (if (= row (vector-length state))
  233. (attacks state col)
  234. (let* ((newstate (vector-mute state col (+ 1 row)))
  235. (current (attacks state col))
  236. (futurerow (least-cons newstate (+ 1 row) col))
  237. (futurestate (vector-mute state col futurerow))
  238. (future (attacks futurestate col)))
  239. (if (< future current)
  240. futurerow
  241. (coinflip futurerow row)))))
  242. ; choose randomly between two objects
  243. (define (coinflip obj1 obj2)
  244. (let ((coin (random)))
  245. (if (< 0.5 coin)
  246. obj1
  247. obj2)))
  248. ; Program wrapper
  249. ; mode b = backtracking
  250. ; mode mg = min-conflicts with greedy initialization
  251. ; else = min-conflicts with random initialization
  252. (define (n-queens n mode maxsteps)
  253. (if (eqv? mode "b")
  254. (backtrack (queengen n) 0 0 1) ; 0 to N
  255. (if (eqv? mode "mg")
  256. (min-conflicts (initialize-g n) -1 0 maxsteps)
  257. (min-conflicts (initialize-r n) -1 0 maxsteps))))
  258. ; data-collection helper functions
  259. (define (collect-me-some-data-mg maxn minn maxsteps)
  260. (do ((n maxn (- n 1))) ((< n minn))
  261. (printf "~a: ~s \n" n (min-conflicts (initialize-g n) -1 0 maxsteps))))
  262. (define (collect-me-some-data-mr maxn minn maxsteps)
  263. (do ((n maxn (- n 1))) ((< n minn))
  264. (printf "~a: ~s \n" n (min-conflicts (initialize-r n) -1 0 maxsteps))))
  265. (define (collect-me-some-data-b maxn minn colmode)
  266. (do ((n maxn (- n 1))) ((< n minn))
  267. (printf "~a: ~s \n" n (backtrack (queengen n) 0 0 colmode))))