Rebol3 Code Examplex


Knight's tour

Find a path that visits every square of a chessboard once.

Rebol [
    title: "Rosetta code: Knight's tour"
    file: %Knight's_tour.r3
    url: https://rosettacode.org/wiki/Knight%27s_tour
]

knights-tour: function/with [
    board-size [integer!]
][
    ;; Prepare board...
    brd: make block! size: board-size
    loop size [
        row: make block! size
        append/dup row 0 size
        append/only brd row
    ]
    ;; Starting position...
    pos: as-pair random size random size
    brd/(pos/x)/(pos/y): 1

    ;; Found solutions...
    found: solve pos 2

    either found [
        print-brd print ""
    ][  print ["no solutions found:" pos] ]

][
    dirs: [1x2 1x-2 2x1 2x-1 -1x2 -1x-2 -2x-1 -2x1]
    size: brd: pos: none

    cnt-moves: function [m [pair!]] [
        n: 0
        foreach d dirs [
            p: m + d
            rn: p/x
            cn: p/y
            if all [
                rn >= 1 rn <= size
                cn >= 1 cn <= size
                zero? brd/:rn/:cn
            ][
                n: n + 1
            ]
        ]
        n
    ]

    sort-moves: function [movs [block!]] [
        cnt: map-each m movs [cnt-moves m]
        i: 1
        while [i <= ((length? cnt) - 1)] [
            j: i + 1
            while [j <= length? cnt] [
                if cnt/:j < cnt/:i [
                    tmp: cnt/:i  cnt/:i: cnt/:j  cnt/:j: tmp
                    tmp: movs/:i  movs/:i: movs/:j  movs/:j: tmp
                ]
                j: j + 1
            ]
            i: i + 1
        ]
        movs
    ]

    solve: function [pos [pair!] cnt] [
        if cnt > (size * size) [return true]
        movs: make block! 8
        foreach d dirs [
            p: pos + d
            rn: p/x  cn: p/y
            if all [
                rn >= 1 rn <= size
                cn >= 1 cn <= size
                zero? brd/:rn/:cn
            ][
                append movs p
            ]
        ]
        movs: sort-moves movs
        foreach p movs [
            rn: p/x  cn: p/y
            brd/:rn/:cn: cnt
            if solve p cnt + 1 [return true]
            brd/:rn/:cn: 0
        ]
        false
    ]

    print-brd: func [/local fmt] [
        foreach row brd [
            foreach cell row [prin pad cell 4]
            print ""
        ]
    ]
]

knights-tour 8
knights-tour 16

Output:

34  59  12  51  36  47  10  49  
13  52  35  60  11  50  23  46  
58  33  64  53  44  37  48  9   
63  14  55  38  61  22  45  24  
32  57  62  43  54  25  8   21  
15  42  29  56  39  18  5   2   
28  31  40  17  26  3   20  7   
41  16  27  30  19  6   1   4   

160 21  206 245 162 23  208 175 164 25  186 177 120 27  122 179 
205 240 161 22  207 246 163 24  209 176 165 26  187 178 119 28  
20  159 244 241 248 253 230 227 174 189 210 185 166 121 180 123 
221 204 239 254 237 242 247 252 229 226 173 188 181 184 29  118 
158 19  222 243 256 249 228 231 190 233 182 211 172 167 124 169 
203 220 255 238 223 236 251 234 225 214 191 138 183 170 117 30  
18  157 200 217 250 151 224 215 232 141 212 171 116 125 168 113 
197 202 219 154 199 216 235 150 213 192 137 142 139 114 31  78  
156 17  198 201 218 149 152 193 136 143 140 115 126 79  112 1   
47  196 155 148 153 194 135 144 109 90  127 104 111 96  77  32  
16  147 48  195 134 145 108 89  128 105 110 91  80  103 2   95  
49  46  133 146 59  64  129 106 99  84  87  102 97  92  33  76  
132 15  50  63  130 107 54  83  88  101 98  81  86  75  94  3   
45  12  131 58  53  60  65  100 55  82  85  74  93  36  69  34  
14  51  10  43  62  57  8   41  66  73  6   39  68  71  4   37  
11  44  13  52  9   42  61  56  7   40  67  72  5   38  35  70