-
Notifications
You must be signed in to change notification settings - Fork 0
/
TicTacToe.py
311 lines (261 loc) · 9.34 KB
/
TicTacToe.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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
# Opdracht 2
import random
bord = [0, 0, 0, 0, 0, 0, 0, 0, 0]
# bord = ["x", 0, "o", "o", "x", 0, 0, 0, "o"]
def findNextStates(bord, maxing):
"""Vind alle mogelijke states/zetten voor de kunstmatige intelligentie.
argumenten:\n
bord (list) -- een lijst van het speelbord.\n
maxing (bool) -- of het de minimaliserende (false) of
maximaliserende (true) speler is.
"""
# Een lijst voor alle gevonden states.
states = []
# Voor iedere plek in de lijst.
for i in range(0, len(bord)):
# Maak een replica van het bord aan.
replica = list(bord)
# Als er een lege plek is.
if replica[i] == 0:
# Als het de maximaliserende speler (in dit geval de cirkel) is.
if maxing:
# Vervang de lege plek met een cirkel.
replica[i] = "o"
# Als het de minimaliserende speler (in dit geval het kruisje) is.
else:
# Vervang de lege plek met een kruisje.
replica[i] = "x"
# Creëer een nieuwe state
# en voeg vervolgens de nieuw gevonden state
# toe aan de lijst met states.
states.append(replica)
return states
def move(vak, figuur):
"""maak een zet.
argumenten:\n
vak (int) -- positie waar de speler zijn teken wil neerzetten (1 t/m 9).\n
figuur (string) -- welk figuur heeft de speler. (x of o)5
"""
# Vervang de lege plek met het gegeven figuur
bord[vak - 1] = figuur
print("Move: ")
# Print het aangepaste bord.
printBoard(bord)
def AskUserInput():
"""Vraag en controleer de input van de speler"""
try:
zet = int(input("Het is jouw zet! "
"In welk vakje wil je een zet maken? "))
except ValueError:
print("Er is geen nummer ingevuld, probeer opnieuw")
zet = AskUserInput()
return zet
else:
if zet in [1, 2, 3, 4, 5, 6, 7, 8, 9]:
return zet
else:
print("Dit is een incorrect nummer, voer een nummer in "
"binnen het bereik van 1 t/m 9")
zet = AskUserInput()
return zet
def checkIllegalMove(vak):
"""controleer of de zet wel mag
vak (int) -- positie waar de speler zijn teken wil neerzetten (1 t/m 9).
"""
# Als het vakje leeg is
if bord[vak - 1] == 0:
return True
else:
return False
def playerTurn():
"""Functie om de speler zijn zet te laten zetten"""
# Vraag de positie van de zet op en controleer of de input correct is.
zet = AskUserInput()
# Controleer of de zet wel mag is
if checkIllegalMove(zet):
# Maak de zet.
move(zet, "x")
# Controleer of iemand gewonnen heeft, zo ja, print een statement.
win = checkGoalState(bord)
if win == -1:
print("Proficiat! U heeft gewonnen!")
elif win == 0:
print("Gelijkspel!")
else:
# Zo niet, is de AI aan de beurt.
AITurn()
# Als de zet niet mag, print een statement en start de beurt overnieuw.
else:
print("Dit vakje is al bezet.")
playerTurn()
def AITurn():
"""Functie om de kunstmatige intelligentie zijn zet te laten zetten"""
print("Zet van de AI...")
# Zoek naar de nieuwe states die behaald kunnen worden
# vanuit de huidige state.
next = findNextStates(bord, True)
# Een lijst voor de waarden van de nieuwe states.
nextvalues = []
# Voor iedere state.
for state in next:
# Bereken de waarde van deze state met het minimax algoritme
# en voeg deze toe aan de lijst van waarden.
nextvalues.append(miniMax(state, True, -2, 2))
# De best mogelijke state.
beststate = []
# De best mogelijke value.
bestvalue = 0
print(next, nextvalues)
# Voor iedere value van de nieuwe states.
for i in range(0, len(nextvalues)):
# Als deze winnend is voor de AI.
if nextvalues[i] == 1:
# Dan maak deze de beste state en de beste value.
beststate = next[i]
bestvalue = 1
break
# Als er geen winnende state gevonden is.
if bestvalue != 1:
# Zoek dan naar een state waar er gelijkspel te vinden is.
for i in range(0, len(nextvalues)):
if nextvalues[i] == 0:
print("h")
beststate = next[i]
break
# De zet die de ki gaat maken.
zet = 0
# Kijk waar het verschil zit tussen de huidige state en de beste state
# en gebruik dit verschil als zet.
for i in range(0, len(bord)):
if bord[i] != beststate[i]:
zet = i + 1
# Maak de zet.
move(zet, "o")
# Controleer of de ki gewonnen heeft of gelijk heeft gespeeld.
win = checkGoalState(bord)
if win == 1:
print("Helaas, U heeft verloren.")
elif win == 0:
print("Gelijkspel!")
else:
# Zo niet, dan is het de beurt van de speler.
playerTurn()
def printBoard(bord):
"""print het bord, er wordt van links naar rechts
en van boven naar onderen gewerkt.
bord (list) -- een lijst van het speelbord.
"""
# Maak een placeholder lijst aan zodat het echte bord niet wordt aangepast.
placeholder = list(bord)
# Maak van de 0 een leeg vakje voor betere leesbaarheid.
for i in range(0, len(placeholder)):
if placeholder[i] == 0:
placeholder[i] = " "
else:
# En maak van de integer een string.
placeholder[i] = str(placeholder[i])
print('{:^3}|{:^3}|{:^3}'.format(placeholder[0],
placeholder[1],
placeholder[2]))
print('{:-^11}'.format('-'))
print('{:^3}|{:^3}|{:^3}'.format(placeholder[3],
placeholder[4],
placeholder[5]))
print('{:-^11}'.format('-'))
print('{:^3}|{:^3}|{:^3}'.format(placeholder[6],
placeholder[7],
placeholder[8]))
def checkGoalState(bord):
"""Functie die controleerd of het spel voorbij is"""
# Kruisjes:
for i in range(1, 4):
if ((bord[(i - 1) * 3] == "x" and
bord[(i - 1) * 3 + 1] == "x" and
bord[(i - 1) * 3 + 2] == "x") or
(bord[0 - 1 + i] == "x" and
bord[3 - 1 + i] == "x" and
bord[6 - 1 + i] == "x")):
return -1
# Diagonalen:
if ((bord[0] == "x" and
bord[4] == "x" and
bord[8] == "x") or
(bord[2] == "x" and
bord[4] == "x" and
bord[6] == "x")):
return -1
# Cirkels:
for i in range(1, 4):
if ((bord[(i - 1) * 3] == "o" and
bord[(i - 1) * 3 + 1] == "o" and
bord[(i - 1) * 3 + 2] == "o") or
(bord[0 - 1 + i] == "o" and
bord[3 - 1 + i] == "o" and
bord[6 - 1 + i] == "o")):
return 1
# Diagonalen:
if ((bord[0] == "o" and
bord[4] == "o" and
bord[8] == "o") or
(bord[2] == "o" and
bord[4] == "o" and
bord[6] == "o")):
return 1
# Controleer of er nog zetten zijn, zo niet, is het gelijkspel.
if 0 in bord:
return 5
else:
return 0
def miniMax(bord, maxing, a, b):
"""het minimax algoritme
Als de huidige state een goal state is, return de value van de goalstate.
"""
# Als de huidige state een goal state is, return de value van de goalstate.
if checkGoalState(bord) != 5:
return checkGoalState(bord)
else:
# De values van de nieuwe states.
statevalues = []
# Zoek de nieuwe states.
states = findNextStates(bord, not maxing)
# Voor iedere gevonden state.
for state in states:
loop = miniMax(state, not maxing, a, b)
# Zoek de value van de state dmv de volgende states te zoeken
# totdat deze tegen een goal state op lopen.
statevalues.append(loop)
# Als het de beurt van de maximaliserende speler is
# (en de vorige beurt dus van de minimaliserende speler is).
if maxing:
# Kijk dan of de beta verhoogd is.
b = min(b, loop)
# En als deze hoger is dan de alpha, break uit de loop
# (want deze tak wordt nooit gekozen door de speler).
if b <= a:
break
# En doe dit andersom voor de minimaliserende speler.
else:
a = max(a, loop)
if b <= a:
break
# Als het de beurt van de maximaliserende speler is
# (en de vorige beurt dus van de minimaliserende speler is).
if maxing:
# Geef dan de laagste waarde van alle state values
# (omdat dit het beste voor de minimaliserende speler is).
best = min(statevalues)
# Doe dit andersom als het de beurt van de minimaliserende speler is.
else:
best = max(statevalues)
# En return deze value
return best
def start():
"""de start functie"""
# bepaal wie er gaat starten
start = random.randint(0, 1)
printBoard(bord)
if start == 0:
playerTurn()
else:
AITurn()
start()