add knight's tour
parent
7ee2c4ad8f
commit
26f5113e68
@ -0,0 +1,95 @@
|
||||
#!/usr/bin/python
|
||||
# vim:set fileencoding=utf-8:
|
||||
|
||||
"""
|
||||
A backtracking Knight's Tour solver.
|
||||
"""
|
||||
|
||||
from __future__ import division, print_function
|
||||
import numpy as np
|
||||
import random
|
||||
import sys
|
||||
|
||||
|
||||
visual = True
|
||||
|
||||
|
||||
def clear_board(n):
|
||||
ANSI_CPL = "\033[%dF" # CPL = Cursor Previous Line
|
||||
ANSI_EL = "\033[2K" # EL = Erase Line
|
||||
print(n*(ANSI_CPL % 1 + ANSI_EL), end='')
|
||||
|
||||
|
||||
def print_board(board, clear=False):
|
||||
if clear:
|
||||
n = board.shape[0]
|
||||
clear_board(n)
|
||||
|
||||
print(board)
|
||||
|
||||
|
||||
def next_moves(position, n):
|
||||
offsets = [(r, c) for r in range(-2, 2+1) for c in range(-2, 2+1)
|
||||
if abs(r*c) == 2]
|
||||
|
||||
moves = [tuple(np.add(position, offset)) for offset in offsets]
|
||||
moves = [move for move in moves
|
||||
if all(coord in range(0, n) for coord in move)]
|
||||
|
||||
return moves
|
||||
|
||||
|
||||
def possible_next_moves(position, n, board):
|
||||
return [move for move in next_moves(position, n) if board[move] == 0]
|
||||
|
||||
|
||||
def ordered_possible_next_moves(position, n, board):
|
||||
# Warnsdorf's Rule
|
||||
moves = sorted([(len(possible_next_moves(move, n, board)), move)
|
||||
for move in possible_next_moves(position, n, board)])
|
||||
return [move[1] for move in moves]
|
||||
|
||||
|
||||
def set_next_knight(board, position, k):
|
||||
n = board.shape[0]
|
||||
|
||||
assert board[position] == 0
|
||||
board[position] = k
|
||||
|
||||
if visual and random.random() < 0.001:
|
||||
print_board(board, clear=True)
|
||||
|
||||
if 0 not in board:
|
||||
# Solved
|
||||
return board
|
||||
|
||||
for move in ordered_possible_next_moves(position, n, board):
|
||||
|
||||
ret = set_next_knight(board, move, k+1)
|
||||
if ret is not None:
|
||||
board = ret
|
||||
return board
|
||||
|
||||
# dead end ⇒ backtrack
|
||||
board[position] = 0
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
np.set_printoptions(linewidth=999) # if n>19 or so
|
||||
|
||||
print(__doc__)
|
||||
|
||||
for n in range(1, 31+1):
|
||||
print('\nn = {}\n'.format(n))
|
||||
board = np.zeros((n, n), dtype=np.int)
|
||||
print_board(board)
|
||||
board = set_next_knight(board, (0, 0), 1)
|
||||
if board is not None:
|
||||
print_board(board, clear=True)
|
||||
else:
|
||||
clear_board(n)
|
||||
print('No solution')
|
||||
|
||||
|
||||
main()
|
Loading…
Reference in New Issue