Merge remote-tracking branch 'csp/master'
commit
93a682a158
@ -0,0 +1,20 @@
|
||||
*.pyc
|
||||
|
||||
# for Racket
|
||||
compiled/
|
||||
|
||||
# for Mac OS X
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
Icon
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear on external disk
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
csp/scribblings/*.html
|
||||
csp/scribblings/*.css
|
||||
csp/scribblings/*.js
|
@ -0,0 +1,9 @@
|
||||
MIT License for CSP
|
||||
|
||||
© 2014-2019 Matthew Butterick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@ -0,0 +1,33 @@
|
||||
This software includes open-source software components that require the following legal notices.
|
||||
|
||||
===============================================================================
|
||||
|
||||
python-constraint http://labix.org/python-constraint
|
||||
|
||||
===============================================================================
|
||||
|
||||
Copyright (c) 2005-2014 - Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
===============================================================================
|
@ -0,0 +1,25 @@
|
||||
#lang br
|
||||
(require "aima.rkt" sugar/debug)
|
||||
|
||||
|
||||
;; queens problem
|
||||
;; place queens on chessboard so they do not intersect
|
||||
(define qs (for/list ([q 8]) (string->symbol (format "q~a" q))))
|
||||
(define rows (range (length qs)))
|
||||
(define vds (for/list ([q qs])
|
||||
($vd q (range (length qs)))))
|
||||
(define (q-col q) (string->number (string-trim (symbol->string q) "q")))
|
||||
(define cs (for*/list ([qs (in-combinations qs 2)])
|
||||
(match-define (list qa qb) qs)
|
||||
(match-define (list qa-col qb-col) (map q-col qs))
|
||||
($constraint
|
||||
(list qa qb)
|
||||
(λ (qa-row qb-row)
|
||||
(and
|
||||
(not (= (abs (- qa-row qb-row)) (abs (- qa-col qb-col)))) ; same diagonal?
|
||||
(not (= qa-row qb-row)))))))
|
||||
|
||||
(define queens (make-csp vds cs))
|
||||
|
||||
(current-solver min-conflicts)
|
||||
(time-named (solve queens))
|
@ -0,0 +1,45 @@
|
||||
#lang br
|
||||
(require "aima.rkt")
|
||||
|
||||
; SEND
|
||||
;+ MORE
|
||||
;------
|
||||
; MONEY
|
||||
|
||||
|
||||
(define (word-value . xs)
|
||||
(for/sum ([(x idx) (in-indexed (reverse xs))])
|
||||
(* x (expt 10 idx))))
|
||||
|
||||
(define vs '(s e n d m o r y))
|
||||
(define vds (for/list ([k vs])
|
||||
($vd k (range 10))))
|
||||
|
||||
(define (not= x y) (not (= x y)))
|
||||
|
||||
(define alldiffs
|
||||
(for/list ([pr (in-combinations vs 2)])
|
||||
($constraint pr not=)))
|
||||
|
||||
(define smm (make-csp vds (append
|
||||
alldiffs
|
||||
(list
|
||||
($constraint '(s) positive?)
|
||||
($constraint '(m) positive?)
|
||||
($constraint '(d e y) (λ (d e y) (= (modulo (+ d e) 10) y)))
|
||||
($constraint '(n d r e y) (λ (n d r e y)
|
||||
(= (modulo (+ (word-value n d) (word-value r e)) 100)
|
||||
(word-value e y))))
|
||||
($constraint '(e n d o r y) (λ (e n d o r y)
|
||||
(= (modulo (+ (word-value e n d) (word-value o r e)) 1000) (word-value n e y))))
|
||||
($constraint '(s e n d m o r y) (λ (s e n d m o r y)
|
||||
(= (+ (word-value s e n d) (word-value m o r e))
|
||||
(word-value m o n e y))))))))
|
||||
|
||||
(parameterize ([current-select-variable mrv]
|
||||
[current-order-values lcv]
|
||||
[current-inference mac])
|
||||
(time (solve smm)))
|
||||
(nassigns smm)
|
||||
(nchecks smm)
|
||||
(reset! smm)
|
@ -0,0 +1,12 @@
|
||||
#lang br
|
||||
(require "aima.rkt")
|
||||
(define vs '(a b c))
|
||||
|
||||
(define ds (for/hash ([k vs])
|
||||
(values k (range 10))))
|
||||
(define ns (for*/hash ([v (in-list vs)])
|
||||
(values v (remove v vs))))
|
||||
(define csp (make-csp vs ds ns (λ (A a B b) (not (eq? a b)))))
|
||||
(solve csp)
|
||||
(nassigns csp)
|
||||
(nchecks csp)
|
@ -0,0 +1,24 @@
|
||||
#lang at-exp racket
|
||||
(require "csp.rkt" racket/port rackunit)
|
||||
|
||||
(use-mrv? #f)
|
||||
(use-reduce-arity? #f)
|
||||
(use-mac? #f)
|
||||
(use-remove-constraints? #f)
|
||||
(use-validate-assignments? #t)
|
||||
|
||||
(define (neq? x y) (not (eq? x y)))
|
||||
|
||||
(define c (make-csp))
|
||||
(add-vars! c '(wa nsw t q nt v sa) '(red green blue))
|
||||
(add-constraint! c neq? '(wa nt))
|
||||
(add-constraint! c neq? '(nt q))
|
||||
(add-constraint! c neq? '(q nsw))
|
||||
(add-constraint! c neq? '(nsw v))
|
||||
(add-constraint! c neq? '(sa wa))
|
||||
(add-constraint! c neq? '(sa nt))
|
||||
(add-constraint! c neq? '(sa q))
|
||||
(add-constraint! c neq? '(sa nsw))
|
||||
(add-constraint! c neq? '(sa v))
|
||||
|
||||
(solve c)
|
@ -0,0 +1,173 @@
|
||||
#lang at-exp racket
|
||||
(require "csp.rkt" rackunit)
|
||||
|
||||
(use-mrv? #t)
|
||||
(use-reduce-arity? #t)
|
||||
(use-mac? #t)
|
||||
(use-remove-constraints? #t)
|
||||
(use-validate-assignments? #t)
|
||||
|
||||
(define demo (make-csp))
|
||||
(add-vars! demo '(t w) (range 7))
|
||||
(add-var! demo 'o '(2 6 7))
|
||||
|
||||
(define (sum-three t w o) (= 3 (+ t w o)))
|
||||
(add-constraint! demo sum-three '(t w o))
|
||||
(add-pairwise-constraint! demo alldiff= '(t w o))
|
||||
(add-pairwise-constraint! demo < '(t w o))
|
||||
|
||||
(check-equal? (time (solve demo)) ($csp (list ($var 't '(0)) ($var 'w '(1)) ($var 'o '(2))) '()))
|
||||
|
||||
|
||||
;; TWO + TWO = FOUR
|
||||
|
||||
(define (word-value . xs)
|
||||
(for/sum ([(x idx) (in-indexed (reverse xs))])
|
||||
(* x (expt 10 idx))))
|
||||
|
||||
(define ttf (make-csp))
|
||||
(add-vars! ttf '(t w o f u r) (reverse (range 10)))
|
||||
(add-pairwise-constraint! ttf alldiff= '(t w o f u r))
|
||||
(add-constraint! ttf (λ (o r) (= (modulo (+ o o) 10) r)) '(o r))
|
||||
(add-constraint! ttf (λ (t w o f u r) (= (+ (word-value t w o) (word-value t w o))
|
||||
(word-value f o u r))) '(t w o f u r))
|
||||
(add-constraint! ttf positive? '(t))
|
||||
(add-constraint! ttf positive? '(f))
|
||||
|
||||
(define ttf-solution (time (solve ttf)))
|
||||
(check-equal? ttf-solution
|
||||
($csp
|
||||
(list
|
||||
($var 't '(7))
|
||||
($var 'w '(3))
|
||||
($var 'o '(4))
|
||||
($var 'f '(1))
|
||||
($var 'u '(6))
|
||||
($var 'r '(8)))
|
||||
'()))
|
||||
|
||||
(define (ttf-print csp)
|
||||
(format "~a~a~a + ~a~a~a = ~a~a~a~a" ($csp-ref csp 't) ($csp-ref csp 'w) ($csp-ref csp 'o) ($csp-ref csp 't) ($csp-ref csp 'w) ($csp-ref csp 'o) ($csp-ref csp 'f) ($csp-ref csp 'o) ($csp-ref csp 'u) ($csp-ref csp 'r)))
|
||||
|
||||
(check-equal? (time (solve ttf-solution ttf-print)) "734 + 734 = 1468")
|
||||
|
||||
|
||||
;; ABC problem:
|
||||
;; what is the minimum value of
|
||||
;; ABC
|
||||
;; -------
|
||||
;; A+B+C
|
||||
|
||||
(define abc (make-csp))
|
||||
(add-vars! abc '(a b c) (range 1 10))
|
||||
(define (solution-score sol)
|
||||
(let ([a ($csp-ref sol 'a)]
|
||||
[b ($csp-ref sol 'b)]
|
||||
[c ($csp-ref sol 'c)])
|
||||
(/ (+ (* 100 a) (* 10 b) c) (+ a b c))))
|
||||
|
||||
|
||||
(define abc-sols (time (solve* abc)))
|
||||
(check-equal? (* 9 9 9) (length abc-sols))
|
||||
(check-equal?
|
||||
(argmin solution-score abc-sols)
|
||||
($csp (list ($var 'a '(1)) ($var 'b '(9)) ($var 'c '(9))) '()))
|
||||
|
||||
|
||||
;; quarter problem:
|
||||
;; 26 dollars and quarters
|
||||
;; that add up to $17.
|
||||
|
||||
(define quarters (make-csp))
|
||||
(add-vars! quarters '(dollars quarters) (range 26))
|
||||
(add-constraint! quarters (λ (d q) (= 26 (+ d q))) '(dollars quarters))
|
||||
(add-constraint! quarters (λ (d q) (= 17 (+ d (* 0.25 q)))) '(dollars quarters))
|
||||
(check-equal? (time (solve quarters))
|
||||
($csp (list ($var 'dollars '(14)) ($var 'quarters '(12))) '()))
|
||||
|
||||
|
||||
;; nickel problem
|
||||
#|
|
||||
A collection of 33 coins, consisting of nickels, dimes, and quarters, has a value of $3.30. If there are three times as many nickels as quarters, and one-half as many dimes as nickels, how many coins of each kind are there?
|
||||
|#
|
||||
(define nickels (make-csp))
|
||||
(add-vars! nickels '(n d q) (range 33))
|
||||
(add-constraint! nickels (λ (n d q) (= 33 (+ n d q))) '(n d q) 'count-33)
|
||||
(add-constraint! nickels (λ (n d q) (= 330 (+ (* n 5) (* d 10) (* q 25)))) '(n d q) 'total-3.30)
|
||||
(add-constraint! nickels (λ (n q) (= (* 3 q) n)) '(n q) 'triple-nickel)
|
||||
(add-constraint! nickels (λ (d n) (= (* 2 d) n)) '(d n) 'double-nickel)
|
||||
(check-equal? (time (solve nickels))
|
||||
($csp (list ($var 'n '(18)) ($var 'd '(9)) ($var 'q '(6))) '()))
|
||||
|
||||
|
||||
;; xsum
|
||||
#|
|
||||
# Reorganize the following numbers in a way that each line of
|
||||
# 5 numbers sum to 27.
|
||||
#
|
||||
# 1 6
|
||||
# 2 7
|
||||
# 3
|
||||
# 8 4
|
||||
# 9 5
|
||||
#
|
||||
|#
|
||||
|
||||
(define xsum (make-csp))
|
||||
(add-vars! xsum '(l1 l2 l3 l4 r1 r2 r3 r4 x) (range 1 10))
|
||||
(add-pairwise-constraint! xsum < '(l1 l2 l3 l4))
|
||||
(add-pairwise-constraint! xsum < '(r1 r2 r3 r4))
|
||||
(add-constraint! xsum (λ (l1 l2 l3 l4 x) (= 27 (+ l1 l2 l3 l4 x))) '(l1 l2 l3 l4 x))
|
||||
(add-constraint! xsum (λ (r1 r2 r3 r4 x) (= 27 (+ r1 r2 r3 r4 x))) '(r1 r2 r3 r4 x))
|
||||
(add-pairwise-constraint! xsum alldiff= '(l1 l2 l3 l4 r1 r2 r3 r4 x))
|
||||
|
||||
(check-equal? (length (time (solve* xsum))) 8)
|
||||
|
||||
|
||||
;; send more money problem
|
||||
#|
|
||||
# Assign equal values to equal letters, and different values to
|
||||
# different letters, in a way that satisfies the following sum:
|
||||
#
|
||||
# SEND
|
||||
# + MORE
|
||||
# ------
|
||||
# MONEY
|
||||
|#
|
||||
|
||||
(define smm (make-csp))
|
||||
(add-vars! smm '(s e n d m o r y) (λ () (range 10)))
|
||||
(add-constraint! smm positive? '(s))
|
||||
(add-constraint! smm (curry = 1) '(m))
|
||||
(add-constraint! smm (λ (d e y) (= (modulo (+ d e) 10) y)) '(d e y))
|
||||
(add-constraint! smm (λ (n d r e y)
|
||||
(= (modulo (+ (word-value n d) (word-value r e)) 100)
|
||||
(word-value e y))) '(n d r e y))
|
||||
(add-constraint! smm (λ (e n d o r y)
|
||||
(= (modulo (+ (word-value e n d) (word-value o r e)) 1000) (word-value n e y))) '(e n d o r y))
|
||||
(add-constraint! smm (λ (s e n d m o r y)
|
||||
(= (+ (word-value s e n d) (word-value m o r e))
|
||||
(word-value m o n e y))) '(s e n d m o r y))
|
||||
(add-pairwise-constraint! smm alldiff= '(s e n d m o r y))
|
||||
|
||||
;; todo: too slow
|
||||
;(solve smm)
|
||||
|
||||
;; queens problem
|
||||
;; place queens on chessboard so they do not intersect
|
||||
(define queens (make-csp))
|
||||
(define qs (for/list ([q 8]) (string->symbol (format "q~a" q))))
|
||||
(define rows (range (length qs)))
|
||||
(add-vars! queens qs rows)
|
||||
(define (q-col q) (string->number (string-trim (symbol->string q) "q")))
|
||||
(for* ([qs (in-combinations qs 2)])
|
||||
(match-define (list qa qb) qs)
|
||||
(match-define (list qa-col qb-col) (map q-col qs))
|
||||
(add-constraint! queens
|
||||
(λ (qa-row qb-row)
|
||||
(and
|
||||
(not (= (abs (- qa-row qb-row)) (abs (- qa-col qb-col)))) ; same diagonal?
|
||||
(not (= qa-row qb-row)))) ; same row?
|
||||
(list qa qb)))
|
||||
|
||||
(check-equal? 92 (length (time (solve* queens))))
|
@ -0,0 +1,14 @@
|
||||
#lang at-exp racket
|
||||
(require "csp.rkt" rackunit)
|
||||
|
||||
(define creduce (assign-val ($csp (list ($var 'a '(1 2 3)) ($var 'b '(2 3)) ($var 'c '(1 2 3 4 5))) (list ($constraint '(a b c) (procedure-rename (λ (a b c) (= (+ a b c) 4)) 'summer)))) 'a 1))
|
||||
(check-equal?
|
||||
(make-arcs-consistent (reduce-constraint-arity creduce))
|
||||
($csp (list ($var 'a '(1)) ($var 'b '(2)) ($var 'c '(1))) '()))
|
||||
|
||||
(define f (λ (a b c d) (+ a b c d)))
|
||||
(check-equal? 10 ((reduce-arity f '(1 b c d)) 2 3 4))
|
||||
(check-equal? 10 ((reduce-arity f '(1 2 c d)) 3 4))
|
||||
(check-equal? 10 ((reduce-arity f '(1 2 3 d)) 4))
|
||||
(check-equal? 10 ((reduce-arity f '(1 b 3 d)) 2 4))
|
||||
(check-equal? 10 ((reduce-arity f '(a b 3 d)) 1 2 4))
|
@ -0,0 +1,500 @@
|
||||
Grid 01
|
||||
003020600
|
||||
900305001
|
||||
001806400
|
||||
008102900
|
||||
700000008
|
||||
006708200
|
||||
002609500
|
||||
800203009
|
||||
005010300
|
||||
Grid 02
|
||||
200080300
|
||||
060070084
|
||||
030500209
|
||||
000105408
|
||||
000000000
|
||||
402706000
|
||||
301007040
|
||||
720040060
|
||||
004010003
|
||||
Grid 03
|
||||
000000907
|
||||
000420180
|
||||
000705026
|
||||
100904000
|
||||
050000040
|
||||
000507009
|
||||
920108000
|
||||
034059000
|
||||
507000000
|
||||
Grid 04
|
||||
030050040
|
||||
008010500
|
||||
460000012
|
||||
070502080
|
||||
000603000
|
||||
040109030
|
||||
250000098
|
||||
001020600
|
||||
080060020
|
||||
Grid 05
|
||||
020810740
|
||||
700003100
|
||||
090002805
|
||||
009040087
|
||||
400208003
|
||||
160030200
|
||||
302700060
|
||||
005600008
|
||||
076051090
|
||||
Grid 06
|
||||
100920000
|
||||
524010000
|
||||
000000070
|
||||
050008102
|
||||
000000000
|
||||
402700090
|
||||
060000000
|
||||
000030945
|
||||
000071006
|
||||
Grid 07
|
||||
043080250
|
||||
600000000
|
||||
000001094
|
||||
900004070
|
||||
000608000
|
||||
010200003
|
||||
820500000
|
||||
000000005
|
||||
034090710
|
||||
Grid 08
|
||||
480006902
|
||||
002008001
|
||||
900370060
|
||||
840010200
|
||||
003704100
|
||||
001060049
|
||||
020085007
|
||||
700900600
|
||||
609200018
|
||||
Grid 09
|
||||
000900002
|
||||
050123400
|
||||
030000160
|
||||
908000000
|
||||
070000090
|
||||
000000205
|
||||
091000050
|
||||
007439020
|
||||
400007000
|
||||
Grid 10
|
||||
001900003
|
||||
900700160
|
||||
030005007
|
||||
050000009
|
||||
004302600
|
||||
200000070
|
||||
600100030
|
||||
042007006
|
||||
500006800
|
||||
Grid 11
|
||||
000125400
|
||||
008400000
|
||||
420800000
|
||||
030000095
|
||||
060902010
|
||||
510000060
|
||||
000003049
|
||||
000007200
|
||||
001298000
|
||||
Grid 12
|
||||
062340750
|
||||
100005600
|
||||
570000040
|
||||
000094800
|
||||
400000006
|
||||
005830000
|
||||
030000091
|
||||
006400007
|
||||
059083260
|
||||
Grid 13
|
||||
300000000
|
||||
005009000
|
||||
200504000
|
||||
020000700
|
||||
160000058
|
||||
704310600
|
||||
000890100
|
||||
000067080
|
||||
000005437
|
||||
Grid 14
|
||||
630000000
|
||||
000500008
|
||||
005674000
|
||||
000020000
|
||||
003401020
|
||||
000000345
|
||||
000007004
|
||||
080300902
|
||||
947100080
|
||||
Grid 15
|
||||
000020040
|
||||
008035000
|
||||
000070602
|
||||
031046970
|
||||
200000000
|
||||
000501203
|
||||
049000730
|
||||
000000010
|
||||
800004000
|
||||
Grid 16
|
||||
361025900
|
||||
080960010
|
||||
400000057
|
||||
008000471
|
||||
000603000
|
||||
259000800
|
||||
740000005
|
||||
020018060
|
||||
005470329
|
||||
Grid 17
|
||||
050807020
|
||||
600010090
|
||||
702540006
|
||||
070020301
|
||||
504000908
|
||||
103080070
|
||||
900076205
|
||||
060090003
|
||||
080103040
|
||||
Grid 18
|
||||
080005000
|
||||
000003457
|
||||
000070809
|
||||
060400903
|
||||
007010500
|
||||
408007020
|
||||
901020000
|
||||
842300000
|
||||
000100080
|
||||
Grid 19
|
||||
003502900
|
||||
000040000
|
||||
106000305
|
||||
900251008
|
||||
070408030
|
||||
800763001
|
||||
308000104
|
||||
000020000
|
||||
005104800
|
||||
Grid 20
|
||||
000000000
|
||||
009805100
|
||||
051907420
|
||||
290401065
|
||||
000000000
|
||||
140508093
|
||||
026709580
|
||||
005103600
|
||||
000000000
|
||||
Grid 21
|
||||
020030090
|
||||
000907000
|
||||
900208005
|
||||
004806500
|
||||
607000208
|
||||
003102900
|
||||
800605007
|
||||
000309000
|
||||
030020050
|
||||
Grid 22
|
||||
005000006
|
||||
070009020
|
||||
000500107
|
||||
804150000
|
||||
000803000
|
||||
000092805
|
||||
907006000
|
||||
030400010
|
||||
200000600
|
||||
Grid 23
|
||||
040000050
|
||||
001943600
|
||||
009000300
|
||||
600050002
|
||||
103000506
|
||||
800020007
|
||||
005000200
|
||||
002436700
|
||||
030000040
|
||||
Grid 24
|
||||
004000000
|
||||
000030002
|
||||
390700080
|
||||
400009001
|
||||
209801307
|
||||
600200008
|
||||
010008053
|
||||
900040000
|
||||
000000800
|
||||
Grid 25
|
||||
360020089
|
||||
000361000
|
||||
000000000
|
||||
803000602
|
||||
400603007
|
||||
607000108
|
||||
000000000
|
||||
000418000
|
||||
970030014
|
||||
Grid 26
|
||||
500400060
|
||||
009000800
|
||||
640020000
|
||||
000001008
|
||||
208000501
|
||||
700500000
|
||||
000090084
|
||||
003000600
|
||||
060003002
|
||||
Grid 27
|
||||
007256400
|
||||
400000005
|
||||
010030060
|
||||
000508000
|
||||
008060200
|
||||
000107000
|
||||
030070090
|
||||
200000004
|
||||
006312700
|
||||
Grid 28
|
||||
000000000
|
||||
079050180
|
||||
800000007
|
||||
007306800
|
||||
450708096
|
||||
003502700
|
||||
700000005
|
||||
016030420
|
||||
000000000
|
||||
Grid 29
|
||||
030000080
|
||||
009000500
|
||||
007509200
|
||||
700105008
|
||||
020090030
|
||||
900402001
|
||||
004207100
|
||||
002000800
|
||||
070000090
|
||||
Grid 30
|
||||
200170603
|
||||
050000100
|
||||
000006079
|
||||
000040700
|
||||
000801000
|
||||
009050000
|
||||
310400000
|
||||
005000060
|
||||
906037002
|
||||
Grid 31
|
||||
000000080
|
||||
800701040
|
||||
040020030
|
||||
374000900
|
||||
000030000
|
||||
005000321
|
||||
010060050
|
||||
050802006
|
||||
080000000
|
||||
Grid 32
|
||||
000000085
|
||||
000210009
|
||||
960080100
|
||||
500800016
|
||||
000000000
|
||||
890006007
|
||||
009070052
|
||||
300054000
|
||||
480000000
|
||||
Grid 33
|
||||
608070502
|
||||
050608070
|
||||
002000300
|
||||
500090006
|
||||
040302050
|
||||
800050003
|
||||
005000200
|
||||
010704090
|
||||
409060701
|
||||
Grid 34
|
||||
050010040
|
||||
107000602
|
||||
000905000
|
||||
208030501
|
||||
040070020
|
||||
901080406
|
||||
000401000
|
||||
304000709
|
||||
020060010
|
||||
Grid 35
|
||||
053000790
|
||||
009753400
|
||||
100000002
|
||||
090080010
|
||||
000907000
|
||||
080030070
|
||||
500000003
|
||||
007641200
|
||||
061000940
|
||||
Grid 36
|
||||
006080300
|
||||
049070250
|
||||
000405000
|
||||
600317004
|
||||
007000800
|
||||
100826009
|
||||
000702000
|
||||
075040190
|
||||
003090600
|
||||
Grid 37
|
||||
005080700
|
||||
700204005
|
||||
320000084
|
||||
060105040
|
||||
008000500
|
||||
070803010
|
||||
450000091
|
||||
600508007
|
||||
003010600
|
||||
Grid 38
|
||||
000900800
|
||||
128006400
|
||||
070800060
|
||||
800430007
|
||||
500000009
|
||||
600079008
|
||||
090004010
|
||||
003600284
|
||||
001007000
|
||||
Grid 39
|
||||
000080000
|
||||
270000054
|
||||
095000810
|
||||
009806400
|
||||
020403060
|
||||
006905100
|
||||
017000620
|
||||
460000038
|
||||
000090000
|
||||
Grid 40
|
||||
000602000
|
||||
400050001
|
||||
085010620
|
||||
038206710
|
||||
000000000
|
||||
019407350
|
||||
026040530
|
||||
900020007
|
||||
000809000
|
||||
Grid 41
|
||||
000900002
|
||||
050123400
|
||||
030000160
|
||||
908000000
|
||||
070000090
|
||||
000000205
|
||||
091000050
|
||||
007439020
|
||||
400007000
|
||||
Grid 42
|
||||
380000000
|
||||
000400785
|
||||
009020300
|
||||
060090000
|
||||
800302009
|
||||
000040070
|
||||
001070500
|
||||
495006000
|
||||
000000092
|
||||
Grid 43
|
||||
000158000
|
||||
002060800
|
||||
030000040
|
||||
027030510
|
||||
000000000
|
||||
046080790
|
||||
050000080
|
||||
004070100
|
||||
000325000
|
||||
Grid 44
|
||||
010500200
|
||||
900001000
|
||||
002008030
|
||||
500030007
|
||||
008000500
|
||||
600080004
|
||||
040100700
|
||||
000700006
|
||||
003004050
|
||||
Grid 45
|
||||
080000040
|
||||
000469000
|
||||
400000007
|
||||
005904600
|
||||
070608030
|
||||
008502100
|
||||
900000005
|
||||
000781000
|
||||
060000010
|
||||
Grid 46
|
||||
904200007
|
||||
010000000
|
||||
000706500
|
||||
000800090
|
||||
020904060
|
||||
040002000
|
||||
001607000
|
||||
000000030
|
||||
300005702
|
||||
Grid 47
|
||||
000700800
|
||||
006000031
|
||||
040002000
|
||||
024070000
|
||||
010030080
|
||||
000060290
|
||||
000800070
|
||||
860000500
|
||||
002006000
|
||||
Grid 48
|
||||
001007090
|
||||
590080001
|
||||
030000080
|
||||
000005800
|
||||
050060020
|
||||
004100000
|
||||
080000030
|
||||
100020079
|
||||
020700400
|
||||
Grid 49
|
||||
000003017
|
||||
015009008
|
||||
060000000
|
||||
100007000
|
||||
009000200
|
||||
000500004
|
||||
000000020
|
||||
500600340
|
||||
340200000
|
||||
Grid 50
|
||||
300200000
|
||||
000107000
|
||||
706030500
|
||||
070009080
|
||||
900020004
|
||||
010800050
|
||||
009040301
|
||||
000702000
|
||||
000008006
|
@ -0,0 +1,29 @@
|
||||
#lang br/quicklang
|
||||
(require csp racket/stxparam racket/splicing)
|
||||
(provide (all-defined-out)
|
||||
(except-out (all-from-out br/quicklang) #%module-begin)
|
||||
(rename-out [mb #%module-begin]))
|
||||
|
||||
(define-syntax-parameter PROB (λ (stx) (error 'not-parameterized)))
|
||||
(define-syntax-parameter SOLVE (make-rename-transformer #'solve))
|
||||
|
||||
(define-macro (mb EXPR0 ... #:output ID EXPR ...)
|
||||
(with-syntax ([prob #'ID])
|
||||
#'(#%module-begin
|
||||
(require csp)
|
||||
(provide prob SOLVE)
|
||||
(define prob (make-csp))
|
||||
(println prob)
|
||||
(splicing-syntax-parameterize ([PROB (make-rename-transformer #'ID)])
|
||||
EXPR0 ...
|
||||
EXPR ...))))
|
||||
|
||||
(define-macro (define-variable VID DOMAIN)
|
||||
#'(begin
|
||||
(define VID DOMAIN)
|
||||
(add-var! PROB 'VID DOMAIN)))
|
||||
|
||||
(define-macro (define-constraint CID FUNC VARSYMS)
|
||||
#'(begin
|
||||
(define CID (constraint FUNC VARSYMS))
|
||||
(add-constraint! PROB FUNC VARSYMS)))
|
@ -0,0 +1,40 @@
|
||||
#lang debug racket
|
||||
(require "hacs.rkt" sugar/debug)
|
||||
(module+ test (require rackunit))
|
||||
|
||||
(define (word-value d str)
|
||||
(define xs (for/list ([c (in-string str)])
|
||||
(dict-ref d (string->symbol (string c)))))
|
||||
(for/sum ([(x idx) (in-indexed (reverse xs))])
|
||||
(* x (expt 10 idx))))
|
||||
|
||||
(define (math-csp str)
|
||||
(define input str)
|
||||
(define words (map string-downcase (string-split input)))
|
||||
(match-define (list terms ... sum) words)
|
||||
(define vars (map string->symbol (remove-duplicates (for*/list ([word words]
|
||||
[c word])
|
||||
(string c)))))
|
||||
(unless (<= (length vars) 10)
|
||||
(raise-argument-error 'too-many-letters))
|
||||
|
||||
(define (not= x y) (not (= x y)))
|
||||
|
||||
(define math (make-csp))
|
||||
(add-vars! math vars (range 0 10))
|
||||
;; all letters have different values
|
||||
(add-pairwise-constraint! math not= vars)
|
||||
;; first letters cannot be zero
|
||||
(define firsts (remove-duplicates (map (compose1 string->symbol string car string->list) words) eq?))
|
||||
(for ([first firsts])
|
||||
(add-constraint! math positive? (list first)))
|
||||
(add-constraint! math (λ args
|
||||
(define dict (map cons vars args))
|
||||
(= (apply + (map (λ (w) (word-value dict w)) terms)) (word-value dict sum))) vars)
|
||||
math)
|
||||
|
||||
#;(solve (math-csp "TWO TWO FOUR"))
|
||||
#;(solve (math-csp "DUCK DUCK GOOSE"))
|
||||
#;(solve (math-csp "TICK TICK BOOM"))
|
||||
#;(solve (math-csp "SEND MORE MONEY"))
|
||||
#;(solve (math-csp "THIS THAT OTHER"))
|
@ -0,0 +1,26 @@
|
||||
#lang br
|
||||
(require csp sugar)
|
||||
|
||||
(define triples (make-csp))
|
||||
|
||||
(add-var! triples 'a (range 10 50))
|
||||
(add-var! triples 'b (range 10 50))
|
||||
(add-var! triples 'c (range 10 50))
|
||||
|
||||
(define (valid-triple? x y z)
|
||||
(= (expt z 2) (+ (expt x 2) (expt y 2))))
|
||||
(add-constraint! triples valid-triple? '(a b c))
|
||||
|
||||
(require math/number-theory)
|
||||
(add-constraint! triples coprime? '(a b c))
|
||||
|
||||
(add-constraint! triples <= '(a b))
|
||||
|
||||
(time-avg 10 (solve* triples))
|
||||
|
||||
(for*/list ([a (in-range 10 50)]
|
||||
[b (in-range 10 50)]
|
||||
#:when (<= a b)
|
||||
[c (in-range 10 50)]
|
||||
#:when (and (coprime? a b c) (valid-triple? a b c)))
|
||||
(map cons '(a b c) (list a b c)))
|
@ -0,0 +1,58 @@
|
||||
#lang debug racket
|
||||
(require "hacs.rkt" sugar/debug)
|
||||
(module+ test (require rackunit))
|
||||
|
||||
(define (map-coloring-csp colors neighbors)
|
||||
(define names (remove-duplicates (flatten neighbors) eq?))
|
||||
(define vds (for/list ([name (in-list names)])
|
||||
(var name colors)))
|
||||
(define cs (for*/list ([neighbor neighbors]
|
||||
[target (cdr neighbor)])
|
||||
(constraint (list (car neighbor) target) neq?)))
|
||||
(csp vds cs))
|
||||
|
||||
(define (parse-colors str) (map string->symbol (map string-downcase (regexp-match* "." str))))
|
||||
(define(parse-neighbors str)
|
||||
(define recs (map string-trim (string-split str ";")))
|
||||
(for/list ([rec recs])
|
||||
(match-define (cons head tail) (string-split rec ":"))
|
||||
(map string->symbol (map string-downcase (map string-trim (cons head (string-split (if (pair? tail)
|
||||
(car tail)
|
||||
""))))))))
|
||||
|
||||
(current-inference forward-check)
|
||||
(current-select-variable minimum-remaining-values)
|
||||
(current-order-values shuffle)
|
||||
|
||||
(define aus (map-coloring-csp (parse-colors "RGB")
|
||||
(parse-neighbors "SA: WA NT Q NSW V; NT: WA Q; NSW: Q V; T: ")))
|
||||
|
||||
(module+ test
|
||||
(check-equal? (length (solve* aus)) 18))
|
||||
|
||||
(define usa (map-coloring-csp (parse-colors "RGBY")
|
||||
(parse-neighbors "WA: OR ID; OR: ID NV CA; CA: NV AZ; NV: ID UT AZ; ID: MT WY UT;
|
||||
UT: WY CO AZ; MT: ND SD WY; WY: SD NE CO; CO: NE KA OK NM; NM: OK TX;
|
||||
ND: MN SD; SD: MN IA NE; NE: IA MO KA; KA: MO OK; OK: MO AR TX;
|
||||
TX: AR LA; MN: WI IA; IA: WI IL MO; MO: IL KY TN AR; AR: MS TN LA;
|
||||
LA: MS; WI: MI IL; IL: IN KY; IN: OH KY; MS: TN AL; AL: TN GA FL;
|
||||
MI: OH IN; OH: PA WV KY; KY: WV VA TN; TN: VA NC GA; GA: NC SC FL;
|
||||
PA: NY NJ DE MD WV; WV: MD VA; VA: MD DC NC; NC: SC; NY: VT MA CT NJ;
|
||||
NJ: DE; DE: MD; MD: DC; VT: NH MA; MA: NH RI CT; CT: RI; ME: NH;
|
||||
HI: ; AK:")))
|
||||
|
||||
(module+ test
|
||||
(check-true (pair? (solve usa))))
|
||||
|
||||
(define fr (map-coloring-csp (parse-colors "RGBY")
|
||||
(parse-neighbors "AL: LO FC; AQ: MP LI PC; AU: LI CE BO RA LR MP; BO: CE IF CA FC RA
|
||||
AU; BR: NB PL; CA: IF PI LO FC BO; CE: PL NB NH IF BO AU LI PC; FC: BO
|
||||
CA LO AL RA; IF: NH PI CA BO CE; LI: PC CE AU MP AQ; LO: CA AL FC; LR:
|
||||
MP AU RA PA; MP: AQ LI AU LR; NB: NH CE PL BR; NH: PI IF CE NB; NO:
|
||||
PI; PA: LR RA; PC: PL CE LI AQ; PI: NH NO CA IF; PL: BR NB CE PC; RA:
|
||||
AU BO FC PA LR")))
|
||||
|
||||
(module+ test
|
||||
(check-true (pair? (solve fr))))
|
||||
|
||||
(module+ main)
|
@ -0,0 +1,35 @@
|
||||
#lang debug racket
|
||||
(require sugar/debug "hacs.rkt")
|
||||
|
||||
(current-inference forward-check)
|
||||
(current-select-variable mrv)
|
||||
(current-order-values shuffle)
|
||||
|
||||
;; queens problem
|
||||
;; place queens on chessboard so they do not intersect
|
||||
|
||||
(define board-size 10)
|
||||
|
||||
(define queens (make-csp))
|
||||
(define qs (range board-size))
|
||||
(define rows (range (length qs)))
|
||||
(add-vars! queens qs rows)
|
||||
(for* ([qs (in-combinations qs 2)])
|
||||
(match-define (list qa qb) qs)
|
||||
(add-constraint! queens
|
||||
(λ (qa-row qb-row)
|
||||
(not (= (abs (- qa-row qb-row)) (abs (- qa qb))))) ; same diag?
|
||||
(list qa qb)))
|
||||
(add-all-diff-constraint! queens #:proc eq?)
|
||||
|
||||
(define (sol->string sol)
|
||||
(define assocs (csp->assocs sol))
|
||||
(displayln (string-join (for/list ([q (in-list (sort assocs < #:key car))])
|
||||
(apply string (add-between (for/list ([idx (in-range board-size)])
|
||||
(if (= idx (cdr q)) #\@ #\·)) #\space))) "\n"))
|
||||
assocs)
|
||||
|
||||
(current-thread-count 4)
|
||||
(parameterize ([current-solver min-conflicts-solver])
|
||||
(time (solve queens #:finish-proc sol->string)))
|
||||
|
@ -0,0 +1,118 @@
|
||||
#lang debug br
|
||||
(require sugar/debug "hacs.rkt")
|
||||
|
||||
(define (make-base-sudoku)
|
||||
(define sudoku (make-csp))
|
||||
|
||||
(define cells (range 81))
|
||||
(add-vars! sudoku cells (range 1 10))
|
||||
|
||||
(for ([i 9])
|
||||
(define row-cells (filter (λ (cell) (= (quotient cell 9) i)) cells))
|
||||
(add-all-diff-constraint! sudoku row-cells)
|
||||
|
||||
(define col-cells (filter (λ (cell) (= (remainder cell 9) i)) cells))
|
||||
(add-all-diff-constraint! sudoku col-cells))
|
||||
|
||||
(define box-starts '(0 3 6 27 30 33 54 57 60))
|
||||
(define box-offsets '(0 1 2 9 10 11 18 19 20))
|
||||
(for ([start box-starts])
|
||||
(add-all-diff-constraint! sudoku (map (curry + start) box-offsets)))
|
||||
|
||||
sudoku)
|
||||
|
||||
(define (make-sudoku-board . strs)
|
||||
(define sudoku (make-base-sudoku))
|
||||
(define vals (for*/list ([str (in-list strs)]
|
||||
[c (in-string str)]
|
||||
#:unless (memv c '(#\- #\|)))
|
||||
(string->number (string c))))
|
||||
(for ([(val vidx) (in-indexed vals)]
|
||||
#:when val)
|
||||
(add-constraint! sudoku (curry = val) (list vidx)))
|
||||
sudoku)
|
||||
|
||||
(require racket/sequence)
|
||||
(define (print-grid sol)
|
||||
(displayln (string-join (map ~a (for/list ([row (in-slice 9 (csp->assocs sol))])
|
||||
(map cdr row))) "\n")))
|
||||
|
||||
;; http://jeapostrophe.github.io/2013-10-23-sudoku-post.html
|
||||
|
||||
(define b1
|
||||
(make-sudoku-board
|
||||
"53 | 7 | "
|
||||
"6 |195| "
|
||||
" 98| | 6 "
|
||||
"-----------"
|
||||
"8 | 6 | 3"
|
||||
"4 |8 3| 1"
|
||||
"7 | 2 | 6"
|
||||
"-----------"
|
||||
" 6 | |28 "
|
||||
" |419| 5"
|
||||
" | 8 | 79"))
|
||||
|
||||
;; "Hard" example
|
||||
(define b2
|
||||
(make-sudoku-board
|
||||
" 7 | 2 | 5"
|
||||
" 9| 87| 3"
|
||||
" 6 | | 4 "
|
||||
"-----------"
|
||||
" | 6 | 17"
|
||||
"9 4| |8 6"
|
||||
"71 | 5 | "
|
||||
"-----------"
|
||||
" 9 | | 8 "
|
||||
"5 |21 |4 "
|
||||
"4 | 9 | 6 "))
|
||||
|
||||
;; "Evil" example
|
||||
(define b3
|
||||
(make-sudoku-board
|
||||
" 8| | 45"
|
||||
" | 8 |9 "
|
||||
" 2|4 | "
|
||||
"-----------"
|
||||
"5 | 1|76 "
|
||||
" 1 | 7 | 8 "
|
||||
" 79|5 | 1"
|
||||
"-----------"
|
||||
" | 7|4 "
|
||||
" 7| 6 | "
|
||||
"65 | |3 "))
|
||||
|
||||
(current-inference forward-check)
|
||||
(current-select-variable mrv-degree-hybrid)
|
||||
(current-order-values shuffle)
|
||||
(current-node-consistency #t)
|
||||
(current-arity-reduction #t)
|
||||
(define trials 5)
|
||||
(time-avg trials (void (solve b1)))
|
||||
(print-debug-info)
|
||||
(time-avg trials (void (solve b2)))
|
||||
(print-debug-info)
|
||||
(time-avg trials (void (solve b3)))
|
||||
(print-debug-info)
|
||||
|
||||
|
||||
(define (euler-value sol)
|
||||
(match sol
|
||||
[(list (cons 0 h) (cons 1 t) (cons 2 d) _ ...)
|
||||
(+ (* 100 h) (* 10 t) d)]))
|
||||
|
||||
|
||||
(require rackunit)
|
||||
(check-equal? (euler-value (solve b1)) 534)
|
||||
(check-equal? (euler-value (solve b2)) 378)
|
||||
(check-equal? (euler-value (solve b3)) 938)
|
||||
|
||||
;; https://projecteuler.net/problem=96
|
||||
;; answer 24702
|
||||
(define (do-euler)
|
||||
(define bstrs
|
||||
(for/list ([puz (in-slice 10 (string-split (port->string (open-input-file "euler-sudoku-grids.txt")) "\n"))])
|
||||
(map (λ (str) (string-replace str "0" " ")) (cdr puz))))
|
||||
(for/sum ([bstr bstrs])
|
||||
(euler-value (solve (apply make-sudoku-board bstr)))))
|
@ -0,0 +1,33 @@
|
||||
#lang debug racket
|
||||
(require sugar/debug "hacs.rkt")
|
||||
|
||||
(current-inference forward-check)
|
||||
(current-select-variable mrv)
|
||||
(current-order-values shuffle)
|
||||
|
||||
(define (word-value . xs)
|
||||
(for/sum ([(x idx) (in-indexed (reverse xs))])
|
||||
(* x (expt 10 idx))))
|
||||
|
||||
|
||||
(define smm (make-csp))
|
||||
|
||||
(define vs '(s e n d m o r y))
|
||||
(add-vars! smm vs (λ () (range 10)))
|
||||
|
||||
(add-constraint! smm positive? '(s))
|
||||
(add-constraint! smm positive? '(m))
|
||||
(add-constraint! smm (λ (d e y) (= (modulo (+ d e) 10) y)) '(d e y))
|
||||
(add-constraint! smm (λ (n d r e y)
|
||||
(= (modulo (+ (word-value n d) (word-value r e)) 100)
|
||||
(word-value e y))) '(n d r e y))
|
||||
(add-constraint! smm (λ (e n d o r y)
|
||||
(= (modulo (+ (word-value e n d) (word-value o r e)) 1000) (word-value n e y))) '(e n d o r y))
|
||||
(add-constraint! smm (λ (s e n d m o r y)
|
||||
(= (+ (word-value s e n d) (word-value m o r e))
|
||||
(word-value m o n e y))) '(s e n d m o r y))
|
||||
(add-pairwise-constraint! smm alldiff= '(s e n d m o r y))
|
||||
(parameterize ([current-select-variable mrv-degree-hybrid] ; todo: why is plain mrv bad here?
|
||||
#;[current-node-consistency make-nodes-consistent]) ; todo: why is node consistency bad here?
|
||||
(time-named (solve smm)))
|
||||
(print-debug-info)
|
@ -0,0 +1,313 @@
|
||||
#lang debug racket
|
||||
(require "hacs.rkt" rackunit sugar/list sugar/debug)
|
||||
|
||||
(current-inference forward-check)
|
||||
(current-select-variable mrv-degree-hybrid)
|
||||
(current-order-values shuffle)
|
||||
(current-node-consistency #t)
|
||||
(current-arity-reduction #t)
|
||||
|
||||
(check-equal? (first-unassigned-variable (csp (list (var 'a (range 3)) (var 'b (range 3))) null))
|
||||
(var 'a (range 3)))
|
||||
(check-equal? (first-unassigned-variable (csp (list (avar 'a (range 3)) (var 'b (range 3))) null))
|
||||
(var 'b (range 3)))
|
||||
(check-false (first-unassigned-variable (csp (list (avar 'a (range 3)) (avar 'b (range 3))) null)))
|
||||
|
||||
(check-equal?
|
||||
;; no forward checking when no constraints
|
||||
(csp-vars (forward-check (csp (list (avar 'a '(1)) (var 'b (range 2))) null) 'a))
|
||||
(list (avar 'a '(1)) (var 'b '(0 1))))
|
||||
|
||||
(check-equal?
|
||||
(csp-vars (forward-check (forward-check (csp (list (avar 'a '(1)) (avar 'b '(0)) (var 'c '(0 1 2)))
|
||||
(list (constraint '(a c) (negate =))
|
||||
(constraint '(b c) (negate =)))) 'a) 'b))
|
||||
(list (avar 'a '(1)) (avar 'b '(0)) (cvar 'c (seteq 2) '((b . 0) (a . 1)))))
|
||||
|
||||
(check-equal?
|
||||
;; no inconsistency: b≠c not checked when fc is relative to a, so assignment succeeds
|
||||
(csp-vars (forward-check (csp (list (avar 'a '(1)) (var 'b (range 2)) (var 'c '(0)))
|
||||
(list (constraint '(a b) (negate =))
|
||||
(constraint '(b c) (negate =)))) 'a))
|
||||
(list (avar 'a '(1)) (cvar 'b (seteq 0) '((a . 1))) (var 'c '(0))))
|
||||
|
||||
;; inconsistency: b≠c is checked by AC-3, thus assignment fails
|
||||
(check-exn backtrack?
|
||||
(λ ()
|
||||
(csp-vars (ac-3 (csp (list (avar 'a '(1)) (var 'b (range 2)) (var 'c '(0)))
|
||||
(list (constraint '(a b) (negate =))
|
||||
(constraint '(b c) (negate =)))) 'a))))
|
||||
|
||||
(check-equal?
|
||||
;; no inconsistency: a≠b not checked when fc ignores a, which is already assigned
|
||||
(csp-vars (forward-check (csp (list (avar 'a '(1)) (avar 'b '(1)) (var 'c (range 2)))
|
||||
(list (constraint '(a b) (negate =))
|
||||
(constraint '(b c) (negate =)))) 'b))
|
||||
(list (avar 'a '(1)) (avar 'b '(1)) (cvar 'c (seteq 0) '((b . 1)))))
|
||||
|
||||
(check-equal?
|
||||
;; no inconsistency: a≠b is not checked by AC-3, because it's already assigned
|
||||
;; todo: is this the right result?
|
||||
(csp-vars (ac-3 (csp (list (avar 'a '(1)) (avar 'b '(1)) (var 'c (range 2)))
|
||||
(list (constraint '(a b) (negate =))
|
||||
(constraint '(b c) (negate =)))) 'b))
|
||||
(list (avar 'a '(1)) (avar 'b '(1)) (var 'c (seteq 0))))
|
||||
|
||||
(check-exn backtrack?
|
||||
(λ () (csp-vars (forward-check (csp (list (avar 'a '(1))
|
||||
(var 'b '(1)))
|
||||
(list (constraint '(a b) (negate =)))) 'a))))
|
||||
|
||||
|
||||
(check-equal? (csp-vars (forward-check (csp (list (var 'a '(0))
|
||||
(var 'b (range 3)))
|
||||
(list (constraint '(a b) <))) 'a))
|
||||
(list (var 'a '(0)) (cvar 'b (seteq 1 2) '((a . 0)))))
|
||||
|
||||
(check-equal?
|
||||
(parameterize ([current-inference forward-check])
|
||||
(length (solve* (csp (list (var 'x (range 3))
|
||||
(var 'y (range 3))
|
||||
(var 'z (range 3)))
|
||||
(list (constraint '(x y) <>)
|
||||
(constraint '(x z) <>)
|
||||
(constraint '(y z) <>)))))) 6)
|
||||
|
||||
(parameterize ([current-inference forward-check])
|
||||
(define vds (for/list ([k '(wa nt nsw q t v sa)])
|
||||
(var k '(red green blue))))
|
||||
(define cs (list
|
||||
(constraint '(wa nt) neq?)
|
||||
(constraint '(wa sa) neq?)
|
||||
(constraint '(nt sa) neq?)
|
||||
(constraint '(nt q) neq?)
|
||||
(constraint '(q sa) neq?)
|
||||
(constraint '(q nsw) neq?)
|
||||
(constraint '(nsw sa) neq?)
|
||||
(constraint '(nsw v) neq?)
|
||||
(constraint '(v sa) neq?)))
|
||||
(define aus (csp vds cs))
|
||||
(check-equal? (length (solve* aus)) 18))
|
||||
|
||||
|
||||
(define quarters (make-csp))
|
||||
(add-vars! quarters '(dollars quarters) (range 26))
|
||||
(add-constraint! quarters (λ (d q) (= 26 (+ d q))) '(dollars quarters))
|
||||
(add-constraint! quarters (λ (d q) (= 17 (+ d (* 0.25 q)))) '(dollars quarters))
|
||||
(check-equal? (time-named (solve quarters))
|
||||
'((dollars . 14) (quarters . 12)))
|
||||
(print-debug-info)
|
||||
|
||||
|
||||
;; xsum
|
||||
#|
|
||||
# Reorganize the following numbers in a way that each line of
|
||||
# 5 numbers sum to 27.
|
||||
#
|
||||
# 1 6
|
||||
# 2 7
|
||||
# 3
|
||||
# 8 4
|
||||
# 9 5
|
||||
#
|
||||
|#
|
||||
(define xsum (make-csp))
|
||||
(add-vars! xsum '(1 2 3 4 5 6 7 8 9) '(1 2 3 4 5 6 7 8 9))
|
||||
(add-transitive-constraint! xsum < '(1 2 4 5))
|
||||
(add-transitive-constraint! xsum < '(6 7 8 9))
|
||||
(add-constraints! xsum (λ xs (= 27 (apply + xs))) '((1 2 3 4 5) (6 7 3 8 9)))
|
||||
(add-all-diff-constraint! xsum)
|
||||
|
||||
(check-equal? (length (time-named (solve* xsum))) 8)
|
||||
(print-debug-info)
|
||||
|
||||
|
||||
;; send more money problem
|
||||
#|
|
||||
# Assign equal values to equal letters, and different values to
|
||||
# different letters, in a way that satisfies the following sum:
|
||||
#
|
||||
# SEND
|
||||
# + MORE
|
||||
# ------
|
||||
# MONEY
|
||||
|#
|
||||
|
||||
(define (word-value . xs)
|
||||
(for/sum ([(x idx) (in-indexed (reverse xs))])
|
||||
(* x (expt 10 idx))))
|
||||
|
||||
(define smm (make-csp))
|
||||
(add-vars! smm '(s e n d m o r y) (λ () (range 10)))
|
||||
(add-constraint! smm positive? '(s))
|
||||
(add-constraint! smm positive? '(m))
|
||||
(add-constraint! smm (λ (d e y) (= (modulo (+ d e) 10) y)) '(d e y))
|
||||
(add-constraint! smm (λ (n d r e y)
|
||||
(= (modulo (+ (word-value n d) (word-value r e)) 100)
|
||||
(word-value e y))) '(n d r e y))
|
||||
(add-constraint! smm (λ (e n d o r y)
|
||||
(= (modulo (+ (word-value e n d) (word-value o r e)) 1000) (word-value n e y))) '(e n d o r y))
|
||||
(add-constraint! smm (λ (s e n d m o r y)
|
||||
(= (+ (word-value s e n d) (word-value m o r e))
|
||||
(word-value m o n e y))) '(s e n d m o r y))
|
||||
(add-all-diff-constraint! smm)
|
||||
(check-equal? (parameterize ([current-select-variable mrv-degree-hybrid]) ; todo: why is plain mrv so bad on this problem?
|
||||
(time-named (solve smm))) '((s . 9) (e . 5) (n . 6) (d . 7) (m . 1) (o . 0) (r . 8) (y . 2)))
|
||||
(print-debug-info)
|
||||
|
||||
;; queens problem
|
||||
;; place queens on chessboard so they do not intersect
|
||||
(define queens (make-csp))
|
||||
(define qs (for/list ([q 8]) (string->symbol (format "q~a" q))))
|
||||
(define rows (range (length qs)))
|
||||
(add-vars! queens qs rows)
|
||||
(define (q-col q) (string->number (string-trim (symbol->string q) "q")))
|
||||
(for* ([qs (in-combinations qs 2)])
|
||||
(match-define (list qa qb) qs)
|
||||
(match-define (list qa-col qb-col) (map q-col qs))
|
||||
(add-constraint! queens
|
||||
(λ (qa-row qb-row)
|
||||
(and
|
||||
(not (= (abs (- qa-row qb-row)) (abs (- qa-col qb-col)))) ; same diagonal?
|
||||
(not (= qa-row qb-row)))) ; same row?
|
||||
(list qa qb)))
|
||||
|
||||
(check-equal? 92 (length (time-named (solve* queens))))
|
||||
(print-debug-info)
|
||||
|
||||
#|
|
||||
# There are no tricks, just pure logic, so good luck and don't give up.
|
||||
#
|
||||
# 1. In a street there are five houses, painted five different colours.
|
||||
# 2. In each house lives a person of different nationality
|
||||
# 3. These five homeowners each drink a different kind of beverage, smoke
|
||||
# different brand of cigar and keep a different pet.
|
||||
#
|
||||
# THE QUESTION: WHO OWNS THE zebra?
|
||||
#
|
||||
# HINTS
|
||||
#
|
||||
# 1. The englishman lives in a red house.
|
||||
# 2. The spaniard keeps dogs as pets.
|
||||
# 5. The owner of the Green house drinks coffee.
|
||||
# 3. The ukrainian drinks tea.
|
||||
# 4. The Green house is on the left of the ivory house.
|
||||
# 6. The person who smokes oldgold rears snails.
|
||||
# 7. The owner of the Yellow house smokes kools.
|
||||
# 8. The man living in the centre house drinks milk.
|
||||
# 9. The Norwegian lives in the first house.
|
||||
# 10. The man who smokes chesterfields lives next to the one who keeps foxes.
|
||||
# 11. The man who keeps horses lives next to the man who smokes kools.
|
||||
# 12. The man who smokes luckystrike drinks orangejuice.
|
||||
# 13. The japanese smokes parliaments.
|
||||
# 14. The Norwegian lives next to the blue house.
|
||||
# 15. The man who smokes chesterfields has a neighbour who drinks water.
|
||||
|#
|
||||
|
||||
(define (sym . args) (string->symbol (apply format args)))
|
||||
|
||||
(define zebra (make-csp))
|
||||
|
||||
(define ns (map (curry sym "nationality-~a") (range 5)))
|
||||
(define cs (map (curry sym "color-~a") (range 5)))
|
||||
(define ds (map (curry sym "drink-~a") (range 5)))
|
||||
(define ss (map (curry sym "smoke-~a") (range 5)))
|
||||
(define ps (map (curry sym "pet-~a") (range 5)))
|
||||
|
||||
(add-vars! zebra ns '(englishman spaniard ukrainian norwegian japanese))
|
||||
(add-vars! zebra cs '(red ivory green yellow blue))
|
||||
(add-vars! zebra ds '(tea coffee milk orange-juice water))
|
||||
(add-vars! zebra ss '(oldgold kools chesterfields luckystrike parliaments))
|
||||
(add-vars! zebra ps '(dogs snails foxes horses zebra))
|
||||
|
||||
(for ([vars (list ns cs ds ss ps)])
|
||||
(add-all-diff-constraint! zebra vars #:same eq?))
|
||||
|
||||
(define (xnor lcond rcond)
|
||||
(or (and lcond rcond) (and (not lcond) (not rcond))))
|
||||
(define (paired-with lval left rval right)
|
||||
(add-constraint! zebra (λ (left right) (xnor (eq? left lval) (eq? rval right))) (list left right)))
|
||||
|
||||
(define (paired-with* lval lefts rval rights)
|
||||
(for ([left lefts][right rights])
|
||||
(paired-with lval left rval right)))
|
||||
|
||||
;# 1. The englishman lives in a red house.
|
||||
('englishman ns . paired-with* . 'red cs)
|
||||
|
||||
;# 2. The spaniard keeps dogs as pets.
|
||||
('spaniard ns . paired-with* . 'dogs ps)
|
||||
|
||||
;# 5. The owner of the Green house drinks coffee.
|
||||
('green cs . paired-with* . 'coffee ds)
|
||||
|
||||
;# 3. The ukrainian drinks tea.
|
||||
('ukrainian ns . paired-with* . 'tea ds)
|
||||
|
||||
;# 4. The Green house is on the left of the ivory house.
|
||||
('green (drop-right cs 1) . paired-with* . 'ivory (drop cs 1))
|
||||
(add-constraint! zebra (curry neq? 'ivory) (list 'color-0))
|
||||
(add-constraint! zebra (curry neq? 'green) (list 'color-4))
|
||||
|
||||
;# 6. The person who smokes oldgold rears snails.
|
||||
('oldgold ss . paired-with* . 'snails ps)
|
||||
|
||||
;# 7. The owner of the Yellow house smokes kools.
|
||||
('yellow cs . paired-with* . 'kools ss)
|
||||
|
||||
;# 8. The man living in the centre house drinks milk.
|
||||
(add-constraint! zebra (λ (d) (eq? d 'milk)) (list 'drink-2))
|
||||
|
||||
;# 9. The Norwegian lives in the first house.
|
||||
(add-constraint! zebra (λ (x) (eq? x 'norwegian)) (list 'nationality-0))
|
||||
|
||||
(define (next-to lval lefts rval rights)
|
||||
(for ([righta (drop-right rights 2)]
|
||||
[left (cdr lefts)]
|
||||
[rightb (drop rights 2)])
|
||||
(add-constraint! zebra (λ (left righta rightb)
|
||||
(or (not (eq? left lval)) (eq? righta rval) (eq? rval rightb)))
|
||||
(list left righta rightb)))
|
||||
(for ([left (list (first lefts) (last lefts))]
|
||||
[right (list (second rights) (fourth rights))])
|
||||
(add-constraint! zebra (λ (left right) (xnor (eq? left lval) (eq? rval right)))
|
||||
(list left right))))
|
||||
|
||||
;# 10. The man who smokes chesterfields lives next to the one who keeps foxes.
|
||||
('chesterfields ss . next-to . 'foxes ps)
|
||||
|
||||
;# 11. The man who keeps horses lives next to the man who smokes kools.
|
||||
('horses ps . next-to . 'kools ss)
|
||||
|
||||
;# 12. The man who smokes luckystrike drinks orangejuice.
|
||||
('luckystrike ss . paired-with* . 'orange-juice ds)
|
||||
|
||||
;# 13. The japanese smokes parliaments.
|
||||
('japanese ns . paired-with* . 'parliaments ss)
|
||||
|
||||
;# 14. The Norwegian lives next to the blue house.
|
||||
('norwegian ns . next-to . 'blue cs)
|
||||
|
||||
;# 15. The man who smokes chesterfields has a neighbour who drinks water.
|
||||
('chesterfields ss . next-to . 'water ds)
|
||||
|
||||
(define (finish x)
|
||||
(apply map list (slice-at x 5)))
|
||||
|
||||
(check-equal? (parameterize ([current-select-variable mrv])
|
||||
(finish (time-named (solve zebra))))
|
||||
'(((nationality-0 . norwegian) (color-0 . yellow) (drink-0 . water) (smoke-0 . kools) (pet-0 . foxes))
|
||||
((nationality-1 . ukrainian) (color-1 . blue) (drink-1 . tea) (smoke-1 . chesterfields) (pet-1 . horses))
|
||||
((nationality-2 . englishman) (color-2 . red) (drink-2 . milk) (smoke-2 . oldgold) (pet-2 . snails))
|
||||
((nationality-3 . japanese) (color-3 . green) (drink-3 . coffee) (smoke-3 . parliaments) (pet-3 . zebra))
|
||||
((nationality-4 . spaniard) (color-4 . ivory) (drink-4 . orange-juice) (smoke-4 . luckystrike) (pet-4 . dogs))))
|
||||
(print-debug-info)
|
||||
|
||||
(module+ main
|
||||
(begin
|
||||
(define-syntax n (λ (stx) #'10))
|
||||
(time-avg n (void (solve quarters)))
|
||||
(time-avg n (void (solve* xsum)))
|
||||
(time-avg n (void (solve smm)))
|
||||
(time-avg n (void (solve* queens)))
|
||||
(time-avg n (void (solve zebra)))))
|
@ -0,0 +1,4 @@
|
||||
#lang info
|
||||
|
||||
(define scribblings '(("scribblings/csp.scrbl" ())))
|
||||
(define test-omit-paths 'all)
|
@ -0,0 +1,8 @@
|
||||
#lang racket/base
|
||||
(require "hacs.rkt")
|
||||
|
||||
(module reader syntax/module-reader
|
||||
csp/expander)
|
||||
|
||||
(provide (all-from-out "hacs.rkt"))
|
||||
|
@ -0,0 +1,302 @@
|
||||
#lang debug racket/base
|
||||
(require racket/match
|
||||
racket/list
|
||||
racket/set)
|
||||
|
||||
(define anything (seteq 1 2 3 4 5 6 7 8 9))
|
||||
(struct cell (x y can-be) #:transparent)
|
||||
|
||||
(define (cell-solved? c)
|
||||
(= 1 (set-count (cell-can-be c))))
|
||||
|
||||
(define (floor3 x)
|
||||
(floor (/ x 3)))
|
||||
|
||||
(define (neighbor-of? l r)
|
||||
(or (same-row? l r)
|
||||
(same-col? l r)
|
||||
(same-box? l r)))
|
||||
(define (same-box? l r)
|
||||
(and (= (floor3 (cell-x l)) (floor3 (cell-x r)))
|
||||
(= (floor3 (cell-y l)) (floor3 (cell-y r)))))
|
||||
(define (same-row? l r)
|
||||
(= (cell-x l) (cell-x r)))
|
||||
(define (same-col? l r)
|
||||
(= (cell-y l) (cell-y r)))
|
||||
|
||||
;; a grid is a list of cells
|
||||
;; board : string ... -> grid
|
||||
(define (board . ss)
|
||||
(for*/fold ([cells null]
|
||||
#:result (reverse cells))
|
||||
([str (in-list ss)]
|
||||
[c (in-port read-char (open-input-string str))]
|
||||
#:unless (memv c '(#\- #\|)))
|
||||
(define-values (row col) (quotient/remainder (length cells) 9))
|
||||
(cons (cell col row (cond
|
||||
[(string->number (string c)) => seteq]
|
||||
[else anything])) cells)))
|
||||
|
||||
|
||||
(define (propagate-one top cs)
|
||||
(let/ec return
|
||||
;; If this is solved, then push its constraints to neighbors
|
||||
(when (cell-solved? top)
|
||||
(define-values (changed? ncs)
|
||||
(for/fold ([changed? #f] [ncs empty])
|
||||
([c (in-list cs)])
|
||||
(cond
|
||||
[(neighbor-of? top c)
|
||||
(define before
|
||||
(cell-can-be c))
|
||||
(define after
|
||||
(set-subtract before (cell-can-be top)))
|
||||
(if (= (set-count before)
|
||||
(set-count after))
|
||||
(values changed?
|
||||
(cons c ncs))
|
||||
(values #t
|
||||
(cons (struct-copy cell c
|
||||
[can-be after])
|
||||
ncs)))]
|
||||
[else
|
||||
(values changed? (cons c ncs))])))
|
||||
(return changed? top ncs))
|
||||
|
||||
;; If this is not solved, then look for cliques that force it to
|
||||
;; be one thing
|
||||
(define (try-clique same-x?)
|
||||
(define before (cell-can-be top))
|
||||
(define after
|
||||
(for/fold ([before before])
|
||||
([c (in-list cs)])
|
||||
(if (same-x? top c)
|
||||
(set-subtract before (cell-can-be c))
|
||||
before)))
|
||||
(when (= (set-count after) 1)
|
||||
(return #t
|
||||
(struct-copy cell top
|
||||
[can-be after])
|
||||
cs)))
|
||||
|
||||
(try-clique same-row?)
|
||||
(try-clique same-col?)
|
||||
(try-clique same-box?)
|
||||
|
||||
;; Look for two cells in our clique that have the same can-be sets
|
||||
;; and remove them from everything else
|
||||
(define (only2-clique same-x?)
|
||||
(define before (cell-can-be top))
|
||||
(when (= (set-count before) 2)
|
||||
(define other
|
||||
(for/or ([c (in-list cs)])
|
||||
(and (same-x? top c) (equal? before (cell-can-be c)) c)))
|
||||
(when other
|
||||
(define changed? #f)
|
||||
(define ncs
|
||||
(for/list ([c (in-list cs)])
|
||||
(cond
|
||||
[(and (not (eq? other c)) (same-x? top c))
|
||||
(define cbefore
|
||||
(cell-can-be c))
|
||||
(define cafter
|
||||
(set-subtract cbefore before))
|
||||
(unless (equal? cbefore cafter)
|
||||
(set! changed? #t))
|
||||
(struct-copy cell c
|
||||
[can-be cafter])]
|
||||
[else
|
||||
c])))
|
||||
(return changed? top
|
||||
ncs))))
|
||||
|
||||
(only2-clique same-row?)
|
||||
(only2-clique same-col?)
|
||||
(only2-clique same-box?)
|
||||
|
||||
(values #f
|
||||
top
|
||||
cs)))
|
||||
|
||||
(define (find-pivot f l)
|
||||
(let loop ([tried empty]
|
||||
[to-try l])
|
||||
(match to-try
|
||||
[(list)
|
||||
(values #f l)]
|
||||
[(list-rest top more)
|
||||
(define-values (changed? ntop nmore)
|
||||
(f top (append tried more)))
|
||||
(if changed?
|
||||
(values #t (cons ntop nmore))
|
||||
(loop (cons top tried) more))])))
|
||||
|
||||
(define (propagate g)
|
||||
(find-pivot propagate-one g))
|
||||
|
||||
(define (until-fixed-point f o bad? end-f)
|
||||
(define-values (changed? no) (f o))
|
||||
(if changed?
|
||||
(cons
|
||||
no
|
||||
(if (bad? no)
|
||||
(end-f no)
|
||||
(until-fixed-point f no bad? end-f)))
|
||||
(end-f o)))
|
||||
|
||||
(define (solved? g)
|
||||
(andmap (λ (c) (= (set-count (cell-can-be c)) 1)) g))
|
||||
|
||||
(define (failed-solution? g)
|
||||
(ormap (λ (c) (= (set-count (cell-can-be c)) 0)) g))
|
||||
|
||||
;; solve-it : grid -> (listof grid)
|
||||
(define (solve-it g)
|
||||
(let solve-loop
|
||||
([g g]
|
||||
[backtrack!
|
||||
(λ (i)
|
||||
(error 'solve-it "Failed!"))])
|
||||
(define (done? g)
|
||||
(cond
|
||||
[(solved? g)
|
||||
empty]
|
||||
[(failed-solution? g)
|
||||
(backtrack! #f)]
|
||||
[else
|
||||
(search g)]))
|
||||
(define (search g)
|
||||
(define sg (sort g < #:key (λ (c) (set-count (cell-can-be c)))))
|
||||
(let iter-loop ([before empty]
|
||||
[after sg])
|
||||
(cond
|
||||
[(empty? after)
|
||||
(backtrack! #f)]
|
||||
[else
|
||||
(define c (first after))
|
||||
(define cb (cell-can-be c))
|
||||
(or (and (not (= (set-count cb) 1))
|
||||
(for/or ([o (in-set cb)])
|
||||
(let/ec new-backtrack!
|
||||
(define nc
|
||||
(struct-copy cell c
|
||||
[can-be (seteq o)]))
|
||||
(solve-loop
|
||||
(cons
|
||||
nc
|
||||
(append before (rest after)))
|
||||
new-backtrack!))))
|
||||
(iter-loop (cons c before)
|
||||
(rest after)))])))
|
||||
(until-fixed-point propagate g failed-solution? done?)))
|
||||
|
||||
(require 2htdp/image
|
||||
2htdp/universe)
|
||||
(define (fig s) (text/font s 12 "black" #f 'modern 'normal 'normal #f))
|
||||
(define MIN-FIG (fig "1"))
|
||||
(define CELL-W (* 3 (image-width MIN-FIG)))
|
||||
(define CELL-H (* 3 (image-height MIN-FIG)))
|
||||
|
||||
(struct draw-state (i before after))
|
||||
(define (draw-it! gs)
|
||||
(define (move-right ds)
|
||||
(match-define (draw-state i before after) ds)
|
||||
(cond
|
||||
[(empty? (rest after))
|
||||
ds]
|
||||
[else
|
||||
(draw-state (add1 i)
|
||||
(cons (first after) before)
|
||||
(rest after))]))
|
||||
(define (draw-can-be can-be)
|
||||
(define (figi i)
|
||||
(if (set-member? can-be i)
|
||||
(fig (number->string i))
|
||||
(fig " ")))
|
||||
(place-image/align
|
||||
(if (= 1 (set-count can-be))
|
||||
(scale 3 (fig (number->string (set-first can-be))))
|
||||
(above (beside (figi 1) (figi 2) (figi 3))
|
||||
(beside (figi 4) (figi 5) (figi 6))
|
||||
(beside (figi 7) (figi 8) (figi 9))))
|
||||
0 0
|
||||
"left" "top"
|
||||
(rectangle CELL-W CELL-H
|
||||
"outline" "black")))
|
||||
(define (draw-draw-state ds)
|
||||
(match-define (draw-state i before after) ds)
|
||||
(define g (first after))
|
||||
(for/fold ([i
|
||||
(empty-scene (* CELL-W 11)
|
||||
(* CELL-H 11))])
|
||||
([c (in-list g)])
|
||||
(match-define (cell x y can-be) c)
|
||||
(place-image/align
|
||||
(draw-can-be can-be)
|
||||
(* CELL-W
|
||||
(cond [(<= x 2) (+ x 0)]
|
||||
[(<= x 5) (+ x 1)]
|
||||
[ else (+ x 2)]))
|
||||
(* CELL-H
|
||||
(cond [(<= y 2) (+ y 0)]
|
||||
[(<= y 5) (+ y 1)]
|
||||
[ else (+ y 2)]))
|
||||
"left" "top"
|
||||
i)))
|
||||
(big-bang (draw-state 0 empty gs)
|
||||
(on-tick move-right 1/8)
|
||||
(on-draw draw-draw-state)))
|
||||
|
||||
;; Wikipedia Example
|
||||
(define b1
|
||||
(board
|
||||
"53 | 7 | "
|
||||
"6 |195| "
|
||||
" 98| | 6 "
|
||||
"-----------"
|
||||
"8 | 6 | 3"
|
||||
"4 |8 3| 1"
|
||||
"7 | 2 | 6"
|
||||
"-----------"
|
||||
" 6 | |28 "
|
||||
" |419| 5"
|
||||
" | 8 | 79"))
|
||||
|
||||
;; "Hard" example
|
||||
(define b2
|
||||
(board
|
||||
" 7 | 2 | 5"
|
||||
" 9| 87| 3"
|
||||
" 6 | | 4 "
|
||||
"-----------"
|
||||
" | 6 | 17"
|
||||
"9 4| |8 6"
|
||||
"71 | 5 | "
|
||||
"-----------"
|
||||
" 9 | | 8 "
|
||||
"5 |21 |4 "
|
||||
"4 | 9 | 6 "))
|
||||
|
||||
;; "Evil" example
|
||||
(define b3
|
||||
(board
|
||||
" 8| | 45"
|
||||
" | 8 |9 "
|
||||
" 2|4 | "
|
||||
"-----------"
|
||||
"5 | 1|76 "
|
||||
" 1 | 7 | 8 "
|
||||
" 79|5 | 1"
|
||||
"-----------"
|
||||
" | 7|4 "
|
||||
" 7| 6 | "
|
||||
"65 | |3 "))
|
||||
|
||||
#;(draw-state-i
|
||||
(draw-it!
|
||||
(solve-it
|
||||
b2)))
|
||||
(require sugar/debug)
|
||||
(time-avg 10 (void (solve-it b1)))
|
||||
(time-avg 10 (void (solve-it b2)))
|
||||
(time-avg 10 (void (solve-it b3)))
|
@ -0,0 +1,14 @@
|
||||
#lang csp
|
||||
(require csp racket/list)
|
||||
|
||||
#:output foo
|
||||
|
||||
(define-variable q (range 33))
|
||||
|
||||
foo
|
||||
|
||||
(define-variable n (range 33))
|
||||
|
||||
(define-constraint c (λ (q n) (= (+ q n) 33)) '(q n))
|
||||
|
||||
(solve foo)
|
@ -0,0 +1,10 @@
|
||||
#lang info
|
||||
(define collection 'multi)
|
||||
(define deps '("beautiful-racket-lib"
|
||||
"htdp-lib"
|
||||
"math-lib"
|
||||
("base" #:version "6.0") "sugar" "rackunit-lib" "debug" "graph"))
|
||||
(define update-implies '("sugar"))(define build-deps '("at-exp-lib"
|
||||
"math-doc"
|
||||
"racket-doc"
|
||||
"scribble-lib"))
|
Loading…
Reference in New Issue