-
Notifications
You must be signed in to change notification settings - Fork 0
/
ConnectFourComputer.py
316 lines (243 loc) · 8.31 KB
/
ConnectFourComputer.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
312
313
314
315
316
#c:\Python27
import random
import sys
import math
import time
import os
board = {} #(columb, row) : 0(empty), 1(P1), 10(P2)
height, width = 6, 7 #6x7 is standard Connect Four
#Initialize board
for row in range (0,height):
for col in range (0,width):
board[(col, row)] = 0
def print_board(board, newPlay):
"""Print a graphical representation of the board.
Human is X. Computer is 0.
@newPlay - the column most recently played in"""
clearScreen()
boardString = ''
boardString += "\n\n"
newPiece = 0 #Used to identify if the new piece has been added with the < > identifiers
#Make the string
for row in range(height-1, -1, -1): #Start at the top and go down
boardString += "|"
for col in range(0,width): #Start at the left and go right
if row == height-1 and newPlay == col and board[(newPlay,height-1)] != 0:
if 1 == board[(col, row)]: #Player 1
boardString += "<X>"
elif 10 == board[(col, row)]: #Computer
boardString += "<O>"
else: # Empty
boardString += " "
newPiece = -1
newPlay = -1
else:
if newPiece != 1:
if 1 == board[(col, row)]: #Player 1
boardString += " X "
elif 10 == board[(col, row)]: #Computer
boardString += " O "
else: # Empty
boardString += " "
if newPiece == 1 and newPlay == col:
if 1 == board[(col, row)]: #Player 1
boardString += "<X>"
elif 10 == board[(col, row)]: #Computer
boardString += "<O>"
else: # Empty
boardString += " "
newPiece = -1
newPlay = -1
elif newPiece == 1:
if 1 == board[(col, row)]: #Player 1
boardString += " X "
elif 10 == board[(col, row)]: #Computer
boardString += " O "
else: # Empty
boardString += " "
if newPlay == col and newPiece == 0 and row > 0 and board[(col, row-1)] != 0:
newPiece += 1
boardString += "|\n\n"
#Add column labels on the bottom
for col in range(0, width-1):
boardString += "- - "
boardString += "\n "
for col in range(0, width):
boardString += " {0} " .format(col)
boardString += "\n"
win = winner(board)
if win:
if -1 == win:
boardString += "\n\nIt's a tie!"
print boardString
def clearScreen():
for i in range(100):
print "\n"
def play_computer(board, difficulty):
"""Play a one player game on board until someone wins"""
p1_turn = True
col = -1
while True:
print_board(board, col)
print col
if p1_turn:
if col != -1:
print "\nComputer played in column:", col
#score, col = minimax(board,p1_turn,difficulty, board)
tmp, col = put_piece(board,p1_turn,-1)
p1_turn = False
else: #Computer turn
print "\nThinking..."
score, col = minimax(board,p1_turn,difficulty, board)
put_piece(board,p1_turn,col)
p1_turn = True
if winner(board):
print_board(board, col)
if 1 == winner(board):
sys.exit("Human player wins!")
else:
sys.exit("Computer player wins!")
def put_piece(board, p1, computerColumn=-1):
"""Ask a player for the next move. Place the piece in the board."""
if True == p1:
piece = 1
else:
piece = 10
#Human turn
if -1 == computerColumn:
message = "\nPlayer {0}'s turn.\nWhich column?\n>> " .format('X')
choice = raw_input(message)
col = int(choice)
while col >= width or col < 0:
print "Not a valid input. Choose again."
choice = raw_input(message)
col = int(choice)
while 0 != board[(col, height-1)]: #If the top slot isn't empty, it's not valid
print "Not a valid input. Choose again."
choice = raw_input(message)
col = int(choice)
#Computer Turn
else:
col = computerColumn
#Piece gets added to the first empty slot in the column
for row in range(0, height):
if board[(col, row)] == 0:
board[(col, row)] = piece
return row, col
return -1, -1
def winner(board):
"""Determine if someone has gotten four in a row"""
#Check horizontal
for row in range(0, height):
for col in range(0, width-3):
if board[(col,row)] != 0 and board[(col,row)] == board[(col+1,row)] and board[(col+1,row)] == board[(col+2,row)] and board[(col+2,row)] == board[(col+3,row)]:
return board[(col,row)]
#Check vertical
for col in range(0, width):
for row in range(0,height-3):
if board[(col,row)] != 0 and board[(col,row)] == board[(col,row+1)] and board[(col,row+1)] == board[(col,row+2)] and board[(col,row+2)] == board[(col,row+3)]:
return board[(col,row)]
#Check diagonal, top left to bottom right
for row in range(height-1, 2, -1):
for col in range(0,width-3):
if board[(col,row)] != 0 and board[(col,row)] == board[(col+1,row-1)] and board[(col+1,row-1)] == board[(col+2,row-2)] and board[(col+2,row-2)] == board[(col+3,row-3)]:
return board[(col,row)]
#Check diagonal, bottom left to top right
for row in range(0, height-3):
for col in range(0, width-3):
if board[(col,row)] != 0 and board[(col,row)] == board[(col+1,row+1)] and board[(col+1,row+1)] == board[(col+2,row+2)] and board[(col+2,row+2)] == board[(col+3,row+3)]:
return board[(col,row)]
#The board is full; it's a tie.
for col in range(0,width):
if 0 == board[(col,height-1)]:
break
elif col == width-1:
sys.exit("The game is tie. Nobody is a winner")
return 0 #No winner
def score_board(board):
"""Return a value for the board. Positive for Comp, Negative for Human"""
CompWins = 1000000
HumanWins = -CompWins
score = 0
#Check horizontal
for row in range(0, height):
for col in range(0, width-3):
tmp = board[(col,row)] + board[(col+1,row)] + board[(col+2,row)] + board[(col+3,row)]
if tmp == 40:
return CompWins
elif tmp == 4:
return HumanWins
else:
score += (int(tmp/10))**3 - (tmp%10)**3 ##Since Comp is represented by 10 and Human by 1, Comp is tens digit, Human is ones digit
#Check vertical
for col in range(0, width):
for row in range(0,height-3):
tmp = board[(col,row)] + board[(col,row+1)] + board[(col,row+2)] + board[(col,row+3)]
if tmp == 40:
return CompWins
elif tmp == 4:
return HumanWins
else:
score += (int(tmp/10))**3 - (tmp%10)**3 ##Since Comp is represented by 10 and Human by 1, Comp is tens digit, Human is ones digit
#Check diagonal, top left to bottom right
for row in range(height-1, 2, -1):
for col in range(0,width-3):
tmp = board[(col,row)] + board[(col+1,row-1)] + board[(col+2,row-2)] + board[(col+3,row-3)]
if tmp == 40:
return CompWins
elif tmp == 4:
return HumanWins
else:
score += (int(tmp/10))**3 - (tmp%10)**3 ##Since Comp is represented by 10 and Human by 1, Comp is tens digit, Human is ones digit
#Check diagonal, bottom left to top right
for row in range(0, height-3):
for col in range(0, width-3):
tmp = board[(col,row)] + board[(col+1,row+1)] + board[(col+2,row+2)] + board[(col+3,row+3)]
if tmp == 40:
return CompWins
elif tmp == 4:
return HumanWins
else:
score += (int(tmp/10))**3 - (tmp%10)**3 ##Since Comp is represented by 10 and Human by 1, Comp is tens digit, Human is ones digit
return score
def minimax(maxOrmin, p1, depth, board):
"""Determine the move the maximizes the minimum loss"""
HumanWins = -1000000
CompWins = 1000000
if 0 == depth:
move = -1
score = score_board(board)
return(score, move)
else:
if maxOrmin:
bestScore = HumanWins
else:
bestScore = CompWins
bestMove = -1
for col in range(0,width):
if board[(col, height-1)] != 0:
continue
rowFilled, tmp = put_piece(board, p1, col)
if rowFilled == -1:
continue
s = score_board(board)
if (maxOrmin and s == 1000000) or (not maxOrmin and s == -1000000):
bestMove = col
bestScore = s
board[(col,rowFilled)] = 0
return (bestScore, bestMove)
moveInner, scoreInner = 0, 0
inner = minimax(not maxOrmin, not p1, depth-1, board)
moveInner = inner[1]
scoreInner = inner[0]
board[(col,rowFilled)] = 0
if maxOrmin:
if scoreInner >= bestScore:
bestScore = scoreInner
bestMove = col
else:
if scoreInner <= bestScore:
bestScore = scoreInner
bestMove = col
return (bestScore, bestMove)
play_computer(board,5)