CS 227 Lecture -*- Outline -*-
Bring: pennies for the 8 queens problem.
* Two Famous Problems (6.5)
** The Tower of Hanoi
read description on page 178 and show picture
Our problem is two-fold
-- how to move the disks
-- how to show the moves
--- either return a list or
--- print them out as they "happen"
*** The recursion
To move n disks from source to dest. using help post.
e.g., from L to R using C as a help.
Base: for moving one disk, just do it
Recursion: (Suppose we know how to move
n-1 disks, for n > 1)
1. Move top n-1 disks to help post (C)
(using dest (R) as helper)
2. Move top largest disk to dest post
(L to R)
3. Move n-1 disks from help post (C) to dest,
using source (L) as helper.
*** Showing the moves
**** Lists
Use "pairs" (source destination), i.e., 2 element lists
e.g., (L C) moves L post to C.
Use list of "pairs" for a sequence of moves
( (L C) (L R) (C R) ) to move from L to C,
then L to C, then L to R, then C to R,
each of these being the top disk.
----------------
;; Program 6.9
<>=
(define tower-of-hanoi
; TYPE: (-> (integer) (list moves))
(lambda (n)
; REQUIRES: n > 0
(letrec (<>)
(move n 'L 'R 'C))))
<>=
(move
; TYPE: (-> (number symbol symbol symbol)
; (list moves))
(lambda (n source destination helper)
(if (= n 1)
(list (list source destination))
(append
(move (sub1 n)
source helper destination)
(cons
(list source destination)
(move (sub1 n)
helper destination source))
))))
@ ----------------
try this with n = 3, etc.
trace this on the board as follows
(tower-of-hanoi 2)
= (move 2 'L 'R 'C)
= (append (move 1 'L 'C 'R)
(cons (list 'L 'R)
(move 1 'C 'R 'L)))
= (append (move 1 'L 'C 'R)
(cons (list 'L 'R)
(list 'C 'R)))
= (append (list 'L 'C)
(cons (list 'L 'R)
(list 'C 'R)))
try Scheme trace for 3
**** Printing moves as generated
----------------
;; Program 6.10
<>=
(define display-tower-of-hanoi
; TYPE: (-> (number) void)
(let (<>)
(lambda (n)
(letrec
(<>)
(move n 'L 'R 'C)))))
<>=
(show-move ;TYPE:(-> (symbol symbol) void)
(lambda (s d)
(display s)
(display " -> ")
(display d)))
<>=
(move
; TYPE: (-> (number symbol symbol symbol)
; void)
(lambda (n source destination helper)
(if (= n 1)
(begin
(show-move source destination)
(newline))
(begin
(move (sub1 n)
source helper destination)
(show-move source destination)
(display ", ")
(move (sub1 n)
helper destination source)
))))
@ ----------------
try this with n = 3, 4, etc.
Point out the two places where the printing happens.
Point out where the newline happens.
They should think about why the moves are printed out in
the same order and what happens for n=2 or n=4.
trace as follows
(tower-of-hanoi 2)
= (move 2 'L 'R 'C)
= (begin
(move 1 'L 'C 'R)
(show-move 'L 'C)
(display ", ")
(move 1 'C 'R 'L))
= (begin
(begin
(show-move 'L 'C)
(newline))
(show-move 'L 'C)
(display ", ")
(move 1 'C 'R 'L))
= (begin
(begin
(show-move 'L 'C)
(newline))
(show-move 'L 'C)
(display ", ")
(begin
(show-move 'C 'R)
(newline)))
** Eight Queens
The problem is to place 8 queens on a chessboard
so that none attacks the other.
Show (or draw) Figure 6.11.
-- A queen attacks another on horizontal, vertical, or
diagonal lines.
*** Data Structures
Could produce graphical output, but easier to
use numbers.
Number rows and columns from lower left, 1--8.
**** So could represent positions of queens as pairs:
(row column)
and board as a list of such pairs.
**** Can compress this
since no 2 queens can be in the same column,
can use position in the list to represent
the columns, as in how it looks, and
thus only need numbers for rows.
(5 7 2 6 3 1 4 8)
(reading from right):
represents queen in column 8, row 8,
column 7, row 4, etc.
**** Sub-solutions (position lists)
The exact column numbers do not matter,
since positions in a list are relative.
Think of the last position in a list as for
column 8 (or last column on smaller board).
So (1 4 8) is a position list.
**** Legal position
Def: a position list is legal iff
no queen attacks another in the list.
Q: Is a one-element list legal?
Def: a solution is a legal position list
with the same size as the board (8).
*** Backtracking
Now how to solve the problem?
No obvious recursive solution.
So like square root, guess, and improve the guess.
**** How?
Can put queen in column 8, row 8
Where to put column 7 queen?
8 does not work, 7 does not work.
6 is ok.
So partial solution is (6 8).
Where to put column 6 queen?
Not 8,7,6,5, but 4 is ok.
Column 5? Not 8, but 7 works. (easy, eh?)
Column 4? Not 8,7,6, but 5 works.
Column 3? Not 8,7,6,5,4,3,2, or 1 !!
**** Now what?
-- We have a guess for queens in the columns.
8, 7, 6, 5 and 4
but it is wrong.
-- We need to improve it.
-- We can revise the last thing we did and
try again, that is *backtracking*
Similar to what people do:
e.g., trying to find a major
Decide to go to college, ISU,
Engineering, Computer Engineering.
May switch to EE, then out of
engineering, etc.
**** Backtracking
Def: Revise last decision, but do not revisit
already failed ideas.
-- So column 4 queen, do not retry 8,7,6 again.
(Keep track by always decreasing number).
try rows: 4,3,2, 1 works.
-- Now try column 3 queen again.
8,7,6,5,4,3,2,1 all rows fail.
-- So backtrack again.
Now no place left for column 4.
-- So column 4 fails, backtrack to queen in
column 5 --- that must not be right.
-- Reconsider that one if they want it.
*** Code
Very subtle, read it several times with the text.
3 procedures: build-solution, forward and backtrack.
Will discuss whatever we do not cover here in
recitations.
**** Build solution
argument is a legal position list
(starts at length 0)
returns solution if done,
otherwise,
calls forward, to try next column.
;; Program 6.13
----------------
(define build-solution
; TYPE: (-> (pos-list) pos-list)
(lambda (legal-pl)
; REQUIRES: legal-pl is legal
(cond
((solution? legal-pl) legal-pl)
(else (forward fresh-try legal-pl)))
))
----------------
**** forward
Backtracks when the row number (try) is zero.
When the row number is a legal spot for the queen
uses build-solution to work on the next
column to the left.
otherwise, tries the next row.
(so basically a loop from 8 to zero).
;; Program 6.14
----------------
(define forward
; TYPE: (-> (number pos-list) pos-list)
(lambda (try legal-pl)
; REQUIRES: try >= 0
; and legal-pl is legal
(cond
((zero? try) (backtrack legal-pl))
((legal? try legal-pl)
(build-solution
(cons try legal-pl)))
(else
(forward (sub1 try) legal-pl)))))
----------------
**** backtrack
We use this when the solution failed,
so the idea is to try again with
the previous column.
That is go forward with the queen in the
car of the list.
If there is no car, nothing else can be
done, so really fail.
;; Program 6.15
----------------
(define backtrack
; TYPE: (-> (pos-list) pos-list)
(lambda (legal-pl)
; REQUIRES: legal-pl is legal
(cond
((null? legal-pl) '())
(else
(forward (sub1 (car legal-pl))
(cdr legal-pl))))))
----------------
*** getting more solutions
think of a solution as a failure, and
backtrack over it (try another row for column 1).
*** tracing it
play with copy edited as in pages 187--188.