-
Notifications
You must be signed in to change notification settings - Fork 0
/
alphabeta-lethtop.py
134 lines (99 loc) · 3.66 KB
/
alphabeta-lethtop.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import math
TEMPLATE_FIELD = '|e|e|e|\n|e|e|e|\n|e|e|e|\n'
HUGE_NUMBER = 1000000
class AlphaBetaNode(object):
def __init__(self):
pass
def generate_children(self):
pass
def is_max_node(self):
pass
def is_end_state(self):
pass
def value(self):
pass
class TicTacToe(AlphaBetaNode):
"""Class that contains current state of the game and implements AlphaBetaNode methods
:attr state: Current state of the board (str)
:attr state: Indicates whose turn it is (Boolean)
"""
def __init__(self, state, crosses_turn):
super().__init__()
self.state = state
self.crosses_turn = crosses_turn
def is_end_state(self):
return ('?' not in self.state) or self.won('x') or self.won('o')
def won(self, c):
triples = [self.state[0:3], self.state[3:6], self.state[6:9], self.state[::3], self.state[1::3],
self.state[2::3], self.state[0] + self.state[4] + self.state[8],
self.state[2] + self.state[4] + self.state[6]]
combo = 3 * c
return combo in triples
def __str__(self):
field = TEMPLATE_FIELD
for c in self.state:
field = field.replace('e', c, 1)
return field
def is_max_node(self):
return self.crosses_turn
def generate_children(self):
"""
Generates list of all possible states after this turn
:return: list of TicTacToe objects
"""
children, i = [], 0
player = 'x' if self.is_max_node() else 'o'
for i in range(9):
if self.state[i] == '?':
new_state = self.state[:i] + player + self.state[i+1:]
new_node = TicTacToe(new_state, not self.is_max_node())
children.append(new_node)
return children
def value(self):
"""
Current score of the game (0, 1, -1)
:return: int
"""
if self.won('x'): return 1
if self.won('o'): return -1
if self.is_end_state(): return 0
def alpha_beta_value(node):
"""Implements the MinMax algorithm with alpha-beta pruning
:param node: State of the game (TicTacToe)
:return: int
"""
if node.is_max_node():
v = max_value(node, -math.inf, math.inf)
else: v = min_value(node, -math.inf, math.inf)
return v
def max_value(node, alpha, beta):
if node.is_end_state():
print(node, '\n', 'MAX ENDSTATE', str(node.value()), alpha, beta, '\n')
return node.value()
v = -math.inf
for child in node.generate_children():
v = max(v, min_value(child, alpha, beta))
alpha = max(alpha, v)
if alpha >= beta: return v
return v
def min_value(node, alpha, beta):
if node.is_end_state():
print(node, '\n', 'MIN ENDSTATE', str(node.value()), alpha, beta, '\n')
return node.value()
v = math.inf
for child in node.generate_children():
v = min(v, max_value(child, alpha, beta))
beta = min(alpha, v)
if alpha >= beta: return v
return v
# JUNKYARD
# children = self.__str__().find("?", i)
# [char if i != child_idx else player for i, char in enumerate(self.state)]
# child_idx = self.__str__().find("?", i)
# i = child_idx
# child_idx = self.__str__().find("?", i)
# print(new_state)
# while child_idx != -1:
# new_state = [char if i != child_idx else player for i, char in enumerate(self.state)]#'{}{}{}'.format(self.state[:child_idx], player, self.state[child_idx+1:])
# new_node = TicTacToe(new_state, not self.is_max_node())
# children.append(new_node)