This repository was archived by the owner on Jun 27, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathoplevering.py
More file actions
362 lines (303 loc) · 11.3 KB
/
oplevering.py
File metadata and controls
362 lines (303 loc) · 11.3 KB
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
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
import random
import hashlib
import time
import colorama
def tetrisPrint():
"""Prints an animated text that spells Tetris!, in the colors of the games logo"""
print(colorama.Fore.RED + 'T', end='\r')
time.sleep(.2)
print(colorama.Fore.GREEN + 'Te', end='\r')
time.sleep(.2)
print(colorama.Fore.LIGHTRED_EX + 'Tet', end='\r')
time.sleep(.2)
print(colorama.Fore.MAGENTA + 'Tetr', end='\r')
time.sleep(.2)
print(colorama.Fore.CYAN + 'Tetri', end='\r')
time.sleep(.2)
print(colorama.Fore.YELLOW + 'Tetris', end='\r')
time.sleep(.2)
print(colorama.Fore.WHITE + 'Tetris!', end='\r')
def in_a_row_n_east(ch, r_start, c_start, a, n):
"""Checks whether ch has n in a row starting at r_start, c_start going east"""
if r_start < 0 or r_start >= len(a) or \
c_start < 0 or c_start >= len(a[0]) - n+1:
return False
for i in range(0, n):
if a[r_start][c_start+i] != ch:
return False
return True
def in_a_row_n_south(ch, r_start, c_start, a, n):
"""Checks whether ch has n in a row starting at r_start, c_start going south"""
if r_start < 0 or r_start >= len(a) - n+1 or \
c_start < 0 or c_start >= len(a[0]):
return False
for i in range(0, n):
if a[r_start+i][c_start] != ch:
return False
return True
def in_a_row_n_southeast(ch, r_start, c_start, a, n):
"""Checks whether ch has n in a row starting at r_start, c_start going southeast"""
if r_start < 0 or r_start >= len(a) - n+1 or \
c_start < 0 or c_start >= len(a[0]) - n+1:
return False
for i in range(0, n):
if a[r_start+i][c_start+i] != ch:
return False
return True
def in_a_row_n_northeast(ch, r_start, c_start, a, n):
"""Checks whether ch has n in a row starting at r_start, c_start going northeast"""
if r_start < n-1 or r_start >= len(a) or \
c_start < 0 or c_start >= len(a[0]) - n+1:
return False
for i in range(0, n):
if a[r_start-i][c_start+i] != ch:
return False
return True
class Board:
"""A data type representing a Connect-4 board
with an arbitrary number of rows and columns.
"""
def __init__(self, width, height, alternatief=False):
"""Construct objects of type Board, with the given width and height."""
self.width = width
self.height = height
self.alt = alternatief
self.data = [[' ']*width for row in range(height)]
# We hoeven niets terug te geven vanuit een constructor!
def __repr__(self):
"""This method returns a string representation for an object of type Board."""
s = '' # de string om terug te geven
for row in range(0, self.height):
s += '|'
for col in range(0, self.width):
text = self.data[row][col]
if text == 'X':
text = colorama.Fore.RED + text + colorama.Fore.RESET + '|'
else:
text = colorama.Fore.YELLOW + text + colorama.Fore.RESET + '|'
s += text
s += '\n'
s += (2*self.width + 1) * '-' # onderkant van het bord
# hier moeten de nummers nog onder gezet worden
s += '\n'
for i in range(self.width):
s += ' ' + str(i % 10)
return s # het bord is compleet, geef het terug
def add_move(self, col, ox):
"""Adds a stone for player ox to column col"""
i = 0
while i < self.height and self.data[i][col] == ' ':
i += 1
self.data[i-1][col] = ox
def clear(self):
"""Clears the board"""
self.data = [[' ']*self.width for _ in range(self.height)]
def set_board(self, move_string):
"""Accepts a string of columns and places
alternating checkers in those columns,
starting with 'X'.
For example, call b.set_board('012345')
to see 'X's and 'O's alternate on the
bottom row, or b.set_board('000000') to
see them alternate in the left column.
move_string must be a string of one-digit integers.
"""
next_checker = 'X' # we starten door een 'X' te spelen
for col_char in move_string:
col = int(col_char)
if 0 <= col <= self.width:
self.add_move(col, next_checker)
if next_checker == 'X':
next_checker = 'O'
else:
next_checker = 'X'
def allows_move(self, col):
"""Checks whether column col can be played"""
return 0 <= col < self.width and self.data[0][col] == ' '
def is_full(self):
"""Checks whether the board is full"""
return all(not self.allows_move(col) for col in range(self.width))
def del_move(self, col):
"""Removes a stone from column col"""
i = 0
while i < self.height and self.data[i][col] == ' ':
i += 1
if i < self.height:
self.data[i][col] = ' '
def wins_for(self, ox):
"""Checks whether player ox wins the game"""
for y in range(self.height):
for x in range(self.width):
if in_a_row_n_east(ox, y, x, self.data, 4) or \
in_a_row_n_south(ox, y, x, self.data, 4) or \
in_a_row_n_southeast(ox, y, x, self.data, 4) or \
in_a_row_n_northeast(ox, y, x, self.data, 4):
return True
return False
def host_game(self):
"""Plays a game of Connect Four"""
ox = 'O'
while True:
# druk het bord af
print(self)
# controleer of het spel afgelopen is
if self.wins_for(ox):
print(ox, 'heeft gewonnen!')
break
if self.is_full():
print('Gelijkspel!')
break
# verander de huidige speler
if ox == 'O':
ox = 'X'
else:
ox = 'O'
# laat de speler een kolom kiezen
col = -1
while not self.allows_move(col):
col = int(input('Kolom voor '+ox+': '))
# voer de zet uit
self.add_move(col, ox)
def tetris(self):
"""
Checks if there is a full row on the board,
clears it and adds a new clean row on the top.
"""
if self.alt:
if ' ' not in self.data[self.height-1]:
tetrisPrint()
self.data = [[' ']*self.width] + self.data[0:self.height-1]
def play_game(self, px, po, show_scores=False):
"""
Plays a game of Connect Four between players px and po.
If show_scores is True, the player's board evaluations are printed each turn.
"""
ox = 'O'
while True:
# druk het bord af
print(self)
# controleer of het spel afgelopen is
if self.wins_for(ox):
print(f'{ox} heeft gewonnen!')
break
if self.is_full():
print('Gelijkspel!')
break
self.tetris()
# verander de huidige speler
if ox == 'O':
ox = 'X'
player = px
else:
ox = 'O'
player = po
if player == 'human':
# laat de menselijke speler een kolom kiezen
col = -1
while not self.allows_move(col):
col = int(input('Kolom voor ' + ox + ': '))
else:
# de computerspeler berekent een zet
if show_scores:
scores = player.scores_for(self)
print('Scores voor ', ox, ':', [int(sc) for sc in scores])
col = player.tiebreak_move(scores)
else:
col = player.next_move(self)
# voer de zet uit
self.add_move(col, ox)
class Player:
"""An AI player for Connect Four."""
def __init__(self, ox, tbt, ply):
"""Construct a player for a given checker, tie-breaking type, and ply."""
self.ox = ox
self.tbt = tbt
self.ply = ply
self.Cply = ply
def __repr__(self):
"""Create a string represenation of the player."""
s = "Player: ox = " + self.ox + ", "
s += "tbt = " + self.tbt + ", "
s += "ply = " + str(self.ply)
return s
def opp_ch(self):
"""Deze functie geeft de vijandige speler terug"""
return 'X' if self.ox == 'O' else 'O'
def score_board(self, b):
"""Deze functie geeft een score terug van hoe goed de speler er voor staat
100 is een win
50 is gelijk voor beide speler
0 is een verlies
"""
if b.wins_for(self.ox):
return 100.0
if not b.wins_for(self.opp_ch()) and not b.wins_for(self.ox):
return 50.0
return 0.0
def tiebreak_move(self, scores):
"""Chooses a column for a move during a tiebreaker,
using the chosen direction given by the player.
"""
max_indices = []
ms = max(scores)
for i, x in enumerate(scores):
if x == ms:
max_indices.append(i)
if self.tbt == "RIGHT":
return max_indices[-1]
if self.tbt == "LEFT":
return max_indices[0]
return random.choice(max_indices)
def scores_for(self, b):
"""Neemt een bord en kijkt naar wat de beste zet zal zijn voor een speler
met de regels die al gedetermineerd waren voor de speler.
"""
LString = str(b.data)
x = hashlib.md5((LString + self.ox + str(self.ply)
).encode('utf-8')).digest()
if x in hash_dict:
return hash_dict[x]
scores = [50] * b.width
for col in range(b.width):
if not b.allows_move(col):
scores[col] = -1
elif b.wins_for(self.ox):
scores[col] = 100
elif b.wins_for(self.opp_ch()):
scores[col] = 0
elif self.ply == 0:
scores[col] = 50
else:
b.add_move(col, self.ox)
other_player = Player(
self.opp_ch(), self.tbt, self.ply-1)
other_scores = other_player.scores_for(b)
if max(other_scores) == 0:
scores[col] = 100
elif max(other_scores) == 100:
scores[col] = 0
elif max(other_scores) == 50:
scores[col] = 50
b.del_move(col)
hash_dict[x] = scores
return scores
def next_move(self, b):
"""Geeft de volgende zet terug"""
return self.tiebreak_move(self.scores_for(b))
hash_dict = {}
p1 = Player('X', 'RANDOM', 4)
p2 = Player('O', 'RANDOM', 4)
state = input(
'Wil je tegen een AI spelen of tegen een persoon? \
\nDe default waarde bij niks invullen is AIvAI \
\n[AI/Persoon/AIvAI]==>')
alt = input('Wil je het in tetris modes spelen? \n[Ja/Nee]==>')
bord = Board(7, 6)
if alt in ['Ja', 'ja', 'JA', 'J', 'j', 'Y', 'y']:
bord.alt = True
if state == 'AI':
bord.play_game('human', p1)
elif state == 'Persoon':
bord.play_game('human', 'human')
else:
bord.play_game(p2, p1)