-
Notifications
You must be signed in to change notification settings - Fork 5
/
evaluate.py
98 lines (74 loc) · 2.61 KB
/
evaluate.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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
"""Evaluation functions"""
import math
import typing
import definition
COORDINATES: list[tuple[int, int, int]] = [
(-1, -1, -1), (-1, -1, 0), (-1, -1, 1),
(-1, 0, -1), (-1, 0, 0), (-1, 0, 1),
(-1, 1, -1), (-1, 1, 0), (-1, 1, 1),
(0, -1, -1), (0, -1, 0), (0, -1, 1),
(0, 0, -1), (0, 0, 0), (0, 0, 1),
(0, 1, -1), (0, 1, 0), (0, 1, 1),
(1, -1, -1), (1, -1, 0), (1, -1, 1),
(1, 0, -1), (1, 0, 0), (1, 0, 1),
(1, 1, -1), (1, 1, 0), (1, 1, 1)
]
COST: float = 8 + 4 * math.sqrt(2)
"""average cost"""
exponent = 2
"""exponent of Minkowski distance"""
h: typing.Callable[[list[int]], float] = None
"""heuristic function"""
def chebyshev(data: list[int], ev: int = 0) -> float:
"""Chebyshev distance"""
for i, v in enumerate(data):
ev += max((
abs(COORDINATES[i][j] - COORDINATES[v][j]) for j in range(3)))
return ev
def euclidean(data: list[int], ev: int = 0) -> float:
"""Euclidean distance"""
for i, v in enumerate(data):
ev += math.hypot(
*(COORDINATES[i][j] - COORDINATES[v][j] for j in range(3)))
return ev
def manhattan(data: list[int], ev: int = 0) -> float:
"""Manhattan distance"""
for i, v in enumerate(data):
for j in range(3):
ev += abs(COORDINATES[i][j] - COORDINATES[v][j])
return ev
def hamming(data: list[int], ev: int = 0) -> int:
"""Hamming distance"""
for i, v in enumerate(data):
ev += i != v
return ev
def minkowski(data: list[int], ev: int = 0, *, p: float = 1/exponent) -> float:
"""Minkowski distance"""
for i, v in enumerate(data):
for j in range(3):
ev += abs(COORDINATES[i][j] - COORDINATES[v][j])**p
return ev**(1/p)
def custom(data: list[int], ev: int = 0) -> int:
"""Custom heuristic function"""
for i, v in enumerate(data):
if i in definition.SIDES:
ev += math.hypot(
*(COORDINATES[i][j] - COORDINATES[v][j] for j in range(3)))
elif i in definition.CORNERS:
for j in range(3):
ev += abs(COORDINATES[i][j] - COORDINATES[v][j])
return ev
def g(ev: int, op: definition.OPS) -> float:
"""cost function"""
if op in ('LR', 'UD', 'FB'):
return ev + COST / 2
return ev + COST
def f(ev: int, op: definition.Ways, data: list[int], depth: int, *, algo: definition.Algos) -> float:
"""evaluate function"""
match algo:
case 'BFS': return 0
case 'DFS': return depth - 1
case 'UCS': return g(ev, op)
case 'AS': return g(ev, op) + h(data)
case 'HC': return h(data)
case _: raise ValueError(algo)