Guest User

Tantrix solver

a guest
Dec 25th, 2015
5,042
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Racket 5.58 KB | None | 0 0
  1. #lang racket
  2.  
  3. ; Place the tile number side up, then fip it horizontally.
  4. ; First edge color is on the right, then walk clockwise.
  5. (define tiles '(
  6.                 "ryybrb"
  7.                 "brrbyy"
  8.                 "rrbbyy"
  9.                 "brybyr"
  10.                 "ryyrbb"
  11.                 "ybryrb"
  12.                 "rbbyry"
  13.                 "ybbryr"
  14.                 "rbyryb"
  15.                 "byyrbr"
  16.                 ))
  17.  
  18. ; hex tiles will be positioned like:
  19. ;       (0 2) (1 2) (2 2)
  20. ;    (0 1) (1 1) (2 1)
  21. ; (0 0) (1 0) (2 0)
  22. (struct pos (x y) #:prefab)
  23.  
  24. ; rotations of placed tiles start with the tile flipped over sideways after
  25. ; reading the number, then are counter-clockwise, so the
  26. ; exit color in a given dir will be (remainder (+ dir rot) 6)
  27. (struct pt (loc tile rot) #:prefab)
  28.  
  29. ; check if two positions are identical
  30. (define (pos= l1 l2)
  31.   (and (= (pos-x l1) (pos-x l2))
  32.        (= (pos-y l1) (pos-y l2))))
  33.  
  34. ; return a position that is one of the six neighbors of a position
  35. ; directions start at 0 to the right, then increase clockwise
  36. (define (neighbor loc dir)
  37.   (define x (pos-x loc))
  38.   (define y (pos-y loc))
  39.   (cond
  40.     [(= 0 dir) (pos (+ x 1) y)]
  41.     [(= 1 dir) (pos (+ x 1) (- y 1))]
  42.     [(= 2 dir) (pos x (- y 1))]
  43.     [(= 3 dir) (pos (- x 1) y)]
  44.     [(= 4 dir) (pos (- x 1) (+ y 1))]
  45.     [(= 5 dir) (pos x (+ y 1))]))
  46.  
  47. ; return true if the positions are neighbirs
  48. (define (is-adjacent? p1 p2)
  49.   (ormap (lambda (dir) (pos= p2 (neighbor p1 dir))) (range 0 6)))
  50.    
  51. ; returns the color exiting the placed tile in dir direction
  52. (define (dir-color a-pt dir-from-a)
  53.   (string-ref
  54.    (list-ref tiles (pt-tile a-pt))
  55.    (remainder (+ dir-from-a
  56.                  (pt-rot a-pt))
  57.               6)))
  58.  
  59. ; returns true if the last element connects both follow colors
  60. (define (list-is-loop? placed follow-color)
  61.   (define a-pt (first placed))
  62.   (andmap (lambda (dir-from-a)
  63.              (define color-a (string-ref
  64.                               (list-ref tiles (pt-tile a-pt))
  65.                               (remainder (+ dir-from-a
  66.                                             (pt-rot a-pt))
  67.                                          6)))
  68.              (if (equal? (dir-color a-pt dir-from-a) follow-color)
  69.                  ; must have a neighbor this dir
  70.                  (ormap (lambda (b-pt)
  71.                           (pos= (neighbor (pt-loc a-pt) dir-from-a)
  72.                                (pt-loc b-pt)))
  73.                         placed)
  74.                  ; don't need a neighbor on other colors
  75.                  #t))
  76.            (range 0 6))) ; directions to check from last tile
  77.  
  78. ; check if two neighbor tiles have a valid color connection
  79. (define (colors-match? a-pt b-pt dir-from-a)
  80.   (define color-a (dir-color a-pt dir-from-a))
  81.   (define color-b (dir-color b-pt (list-ref '(3 4 5 0 1 2) dir-from-a)))
  82.   (equal? color-a color-b))
  83.    
  84. ; check if a new tile placement will violate any color rules from already placed tiles
  85. (define (valid? new-pt placed)
  86.   ; for each neighbor of new, see if it is in placed
  87.   (andmap (lambda (dir)
  88.             (define check-pos (neighbor (pt-loc new-pt) dir))
  89.             ; all tiles must either not be in this pos, or match colors
  90.             (andmap (lambda (check-pt)
  91.                       (or (not (pos= check-pos (pt-loc check-pt)))
  92.                           (colors-match? new-pt check-pt dir)))
  93.                     placed))
  94.           (range 0 6)))
  95.          
  96. ; handle completion or place another tile
  97. (define (add-tile placed follow-color)
  98. ;  (printf "~a\n" placed)
  99.   (cond
  100.     [(= (length placed) (length tiles))
  101.       ; all tiles have been placed
  102.       (when (list-is-loop? placed follow-color)
  103.         (printf "solution: ~a\n" placed))]
  104.    
  105.     [else
  106.      ; place the next tile in an open adjacent spot to the last tile
  107.      ; if that direction is the follow color
  108.      (define last-loc (pt-loc (first placed)))
  109.      (for-each (lambda (dir)
  110.                  ; only try this dir if it is the right color
  111.                  (when (equal? follow-color (dir-color (first placed) dir))
  112.                    (define this-loc (neighbor last-loc dir))
  113.                    ; we can only use this loc if no other tiles match it
  114.                    (when (not (ormap (lambda (t)
  115.                                        (pos= (pt-loc t) this-loc))
  116.                                      placed))
  117.                      ; try all tiles in this spot
  118.                      (for-each (lambda (tile-num)
  119.                                  ; can't use the tile if it has already been placed
  120.                                  (when (not (ormap (lambda (t)
  121.                                                      (= (pt-tile t) tile-num))
  122.                                                    placed))
  123.                                    ; try all rotations of this tile at the noew spot
  124.                                    (for-each (lambda (dir)
  125.                                                (define new (pt this-loc tile-num dir))
  126.                                                (when (valid? new placed)
  127.                                                  ; this is a good placement, go on to the next tile
  128.                                                  (add-tile (cons new placed) follow-color)))
  129.                                              (range 0 6))))
  130.                                (range 0 (length tiles)))))) ; selection of new tile
  131.                  (range 0 6))])) ; neighbor dirs from last placed tile
  132.  
  133. ; Start with tile 1 placed and follow yellow.  The direction doesn't matter, because the
  134. ; solutions can be rotated.
  135. (add-tile (list (pt (pos 0 0) 0 0)) #\y)
Advertisement
Add Comment
Please, Sign In to add comment