-
Notifications
You must be signed in to change notification settings - Fork 891
/
problem_304.py
68 lines (45 loc) · 1.56 KB
/
problem_304.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
from typing import Set, List
BOARD_SIZE = 8
POSSIBLE_MOVES = 8
CACHE = dict()
KNIGHT_RANGE = [-2, -1, 1, 2]
class Position:
def __init__(self, x: int, y: int):
self.x = x
self.y = y
def __hash__(self) -> int:
return hash((self.x, self.y))
def __eq__(self, other) -> bool:
return self.x == other.x and self.y == other.y
def __repr__(self) -> str:
return "Pos[x={},y={}]".format(self.x, self.y)
def is_valid(self) -> bool:
return self.x > 0 and self.x <= BOARD_SIZE and self.y > 0 and self.y <= BOARD_SIZE
def get_valid_moves(start: Position) -> Set[Position]:
if start in CACHE:
return CACHE[start]
candidates = set()
for hor in KNIGHT_RANGE:
for ver in KNIGHT_RANGE:
if abs(hor) + abs(ver) == 3:
candidates.add(Position(start.x + hor, start.y + ver))
val_candidates = [pos for pos in candidates if pos.is_valid()]
CACHE[start] = val_candidates
return val_candidates
def explore(start: Position, turns: int, counts: List) -> None:
if not turns:
return
valid_moves = get_valid_moves(start)
counts[0] += POSSIBLE_MOVES
counts[1] += len(valid_moves)
for next_pos in valid_moves:
explore(next_pos, turns - 1, counts)
def get_prob_remain(start: Position, turns: int) -> float:
global CACHE
CACHE = dict()
counts = [0, 0]
explore(start, turns, counts)
return counts[1] / counts[0]
# Tests
assert get_prob_remain(Position(4, 4), 1) == 1.0
assert get_prob_remain(Position(1, 1), 3) < 0.66