-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathKnight.py
83 lines (63 loc) · 2.88 KB
/
Knight.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
class Knight:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
self.board = None
self.representation = "K"
self.step_counter = 0
self.moves = [(1, 2), (1, -2), (2, 1), (2, -1), (-1, 2), (-1, -2), (-2, 1), (-2, -1)]
def set_board(self, board):
self.board = board
if self.board.knight is not self:
self.board.set_knight(self)
self.board.area[self.x][self.y] = self.representation
def get_unvisited_neighbor_cells(self, x, y):
# Number of unvisited neighbors
num = 0
# For each possible move
for move_x, move_y in self.moves:
# Get new position after the move is executed
new_pos_x, new_pos_y = x + move_x, y + move_y
if self.is_valid_move(new_pos_x, new_pos_y):
# Increment number of unvisited neighbors
num += 1
return num
def get_neighbor_cells(self, x, y):
# Neighbor cells were we can move (also contains the neighbor's neighbor count)
cells = []
# For each possible move
for move_x, move_y in self.moves:
# Get new position after the move is executed
new_pos_x, new_pos_y = x + move_x, y + move_y
if self.is_valid_move(new_pos_x, new_pos_y):
# Get the neighbors from the new position (current neighbor neighbors)
num_neighbor_cells = self.get_unvisited_neighbor_cells(new_pos_x, new_pos_y)
cells.append((new_pos_x, new_pos_y, num_neighbor_cells))
# Sort cells where we can move (neighbors) by their neighbor count (ascending)
cells.sort(key=lambda move: move[2])
return cells
def start(self):
self.step_counter += 1
# Starting the knight traversal
if Knight.find_path(self.x, self.y, self.board, self.step_counter, self):
return True
def is_valid_move(self, x, y):
# If not outside of bounds of the board
return (0 <= x < len(self.board.area) and 0 <= y < len(self.board.area) and
self.board.area[x][y] is self.board.empty_cell)
@staticmethod
def find_path(x, y, board, step_counter, figure):
board.area[x][y] = str(step_counter)
# All the cells are marked
if step_counter == len(board.area) ** 2:
return True
# Get list of neighbors sorted by the least amount of unvisited neighbor cells (Warnsdorffs Heuristic)
neighbor_cells = figure.get_neighbor_cells(x, y)
# For each neighbor
for new_pos_x, new_pos_y, _ in neighbor_cells:
# Try to find path from neighbor the neighbors position
if Knight.find_path(new_pos_x, new_pos_y, board, step_counter+1, figure):
return True
# Reached a dead end. Moving backwards.
board.area[x][y] = board.empty_cell
return False