Reputation: 33
I'm trying to get a 3x3 chess board for the Four Knights problem. Here's the code in the racket language
#lang racket
(define N 3)
(define nexts ; construct the graph
(let ([ds (for*/list ([x 2] [x* '(+1 -1)] [y* '(+1 -1)])
(cons (* x* (+ 1 x)) (* y* (- 2 x))))])
(for*/vector ([i N] [j N])
(filter values (for/list ([d ds])
(let ([i (+ i (car d))] [j (+ j (cdr d))])
(and (< -1 i N) (< -1 j N) (+ j (* N i)))))))))
(define (tour x y)
(define xy (+ x (* N y)))
(let loop ([seen (list xy)] [ns (vector-ref nexts xy)] [n (sub1 (* N N))])
(if (zero? n) (reverse seen)
(for/or ([next (sort (map (λ(n) (cons n (remq* seen (vector-ref nexts n)))) ns)
< #:key length #:cache-keys? #t)])
(loop (cons (car next) seen) (cdr next) (sub1 n))))))
(define (draw tour)
(define v (make-vector (* N N)))
(for ([n tour] [i (in-naturals 1)]) (vector-set! v n i))
(for ([i N])
(displayln (string-join (for/list ([j (in-range i (* N N) N)])
(~a (vector-ref v j) #:width 2 #:align 'right))
" "))))
(draw (tour (random N) (random N)))
And it gives me this error for: expected a sequence for n, got something else: #f
and highlights this section of my code:
(define (draw tour)
(define v (make-vector (* N N)))
(for ([n tour] [i (in-naturals 1)]) (vector-set! v n i))
(for ([i N])
(displayln (string-join (for/list ([j (in-range i (* N N) N)])
(~a (vector-ref v j) #:width 2 #:align 'right))
" "))))
And I'm not sure what the problem is. This is for class and I'm not experienced with the racket language. Any help would be appreciated. Thanks
Upvotes: 0
Views: 187
Reputation: 48745
The error states that it expected the for clause n
to be iterating over a sequence (list, string, vecor, range, lazy sequence) and not #f
which is passed as a result from the tour
procedure when there are no solutions.
The result of tour
is the result of a for/or
which will be #f
(false) if none of the iterations ended with a result with the given start position. For 3x3
and 4x4
there are no solutions no matter the starting position and for 5x5
there are solutions, but not for all starting positions. Eg. Eg. if your random numbers pick (1,2)
there are no solutions to that either. To fix this check if you found a solution and only draw when you have a solution:
(let* ((x (random N)) (y (random N)) (result (tour x y)))
(if result
(draw result) ; only draw when result is not #f
(displayln (format "No results for initial position (~a,~a)" x y))))
My previous though was that for
didn't take numbers was wrong. It will interpret it as range
would and iterate [0,N>
. The reason for my assumption is that this feature is nowhere to be found in the for documentation.
(for/list ([n 10]) n) ; ==> (0 2 3 4 5 6 7 8 9)
Upvotes: 1