From 26f5113e6848c8369f726233aa711284d6f76991 Mon Sep 17 00:00:00 2001 From: neingeist Date: Sun, 31 May 2015 19:32:36 +0200 Subject: [PATCH] add knight's tour --- knights-tour.py | 95 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100755 knights-tour.py diff --git a/knights-tour.py b/knights-tour.py new file mode 100755 index 0000000..10122a1 --- /dev/null +++ b/knights-tour.py @@ -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()