-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathConnect4.py
More file actions
245 lines (192 loc) · 6.89 KB
/
Connect4.py
File metadata and controls
245 lines (192 loc) · 6.89 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
import random
import copy
import sys
BOARDWIDTH = 7
BOARDHEIGHT = 6
def main():
"""
b = getNewBoard()
b[6][5] = 'X'
b[5][4] = 'X'
b[4][3] = 'X'
b[3][2] = 'X'
drawBoard(b)
print(isWinner(b, 'X'))
sys.exit()
"""
print('Four-In-A-Row')
print()
while True:
humanTile, computerTile = enterHumanTile()
turn = whoGoesFirst()
print('The %s player will go first.' % (turn))
mainBoard = getNewBoard()
while True:
if turn == 'human':
drawBoard(mainBoard)
move = getHumanMove(mainBoard)
makeMove(mainBoard, humanTile, move)
if isWinner(mainBoard, humanTile):
winner = 'human'
break
turn = 'computer'
else:
drawBoard(mainBoard)
print('The computer is thinking...')
move = getComputerMove(mainBoard, computerTile)
makeMove(mainBoard, computerTile, move)
if isWinner(mainBoard, computerTile):
winner = 'computer'
break
turn = 'human'
if isBoardFull(mainBoard):
winner = 'tie'
break
drawBoard(mainBoard)
print('Winner is: %s' % winner)
if not playAgain():
break
def playAgain():
# This function returns True if the player wants to play again, otherwise it returns False.
print('Do you want to play again? (yes or no)')
return input().lower().startswith('y')
def enterHumanTile():
# Let's the human player type which tile they want to be.
# Returns a list with the human player's tile as the first item, and the computer's tile as the second.
tile = ''
while not (tile == 'X' or tile == 'O'):
print('Do you want to be X or O?')
tile = input().upper()
# the first element in the tuple is the human player's tile, the second is the computer's tile.
if tile == 'X':
return ['X', 'O']
else:
return ['O', 'X']
def drawBoard(board):
print()
print(' ', end='')
for x in range(1, BOARDWIDTH + 1):
print(' %s ' % x, end='')
print()
print('+---+' + ('---+' * (BOARDWIDTH - 1)))
for y in range(BOARDHEIGHT):
print('| |' + (' |' * (BOARDWIDTH - 1)))
print('|', end='')
for x in range(BOARDWIDTH):
print(' %s |' % board[x][y], end='')
print()
print('| |' + (' |' * (BOARDWIDTH - 1)))
print('+---+' + ('---+' * (BOARDWIDTH - 1)))
def getNewBoard():
board = []
for x in range(BOARDWIDTH):
board.append([' '] * BOARDHEIGHT)
return board
def getHumanMove(board):
while True:
print('Which column do you want to move on? (1-%s, or "quit" to quit game)' % (BOARDWIDTH))
move = input()
if move.lower().startswith('q'):
sys.exit()
if not move.isdigit():
continue
move = int(move) - 1
if isValidMove(board, move):
return move
def getComputerMove(board, computerTile):
potentialMoves = getPotentialMoves(board, computerTile, 2)
bestMoveScore = max([potentialMoves[i] for i in range(BOARDWIDTH) if isValidMove(board, i)])
bestMoves = []
for i in range(len(potentialMoves)):
if potentialMoves[i] == bestMoveScore:
bestMoves.append(i)
return random.choice(bestMoves)
def getPotentialMoves(board, playerTile, lookAhead):
if lookAhead == 0:
return [0] * BOARDWIDTH
potentialMoves = []
if playerTile == 'X':
enemyTile = 'O'
else:
enemyTile = 'X'
# Returns (best move, average condition of this state)
if isBoardFull(board):
return [0] * BOARDWIDTH
# Figure out the best move to make.
potentialMoves = [0] * BOARDWIDTH
for playerMove in range(BOARDWIDTH):
dupeBoard = copy.deepcopy(board)
if not isValidMove(dupeBoard, playerMove):
continue
makeMove(dupeBoard, playerTile, playerMove)
if isWinner(dupeBoard, playerTile):
potentialMoves[playerMove] = 1
break
else:
# do other player's moves and determine best one
if isBoardFull(dupeBoard):
potentialMoves[playerMove] = 0
else:
for enemyMove in range(BOARDWIDTH):
dupeBoard2 = copy.deepcopy(dupeBoard)
if not isValidMove(dupeBoard2, enemyMove):
continue
makeMove(dupeBoard2, enemyTile, enemyMove)
if isWinner(dupeBoard2, enemyTile):
potentialMoves[playerMove] = -1
break
else:
results = getPotentialMoves(dupeBoard2, playerTile, lookAhead - 1)
potentialMoves[playerMove] += (sum(results) / BOARDWIDTH) / BOARDWIDTH
return potentialMoves
def whoGoesFirst():
# Randomly choose the player who goes first.
if random.randint(0, 1) == 0:
return 'computer'
else:
return 'human'
def makeMove(board, player, column):
for y in range(BOARDHEIGHT-1, -1, -1):
if board[column][y] == ' ':
board[column][y] = player
return
def isValidMove(board, move):
if move < 0 or move >= (BOARDWIDTH):
return False
if board[move][0] != ' ':
return False
return True
def isBoardFull(board):
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
if board[x][y] == ' ':
return False
return True
def isWinner(board, tile):
# check horizontal spaces
for y in range(BOARDHEIGHT):
for x in range(BOARDWIDTH - 3):
if board[x][y] == tile and board[x+1][y] == tile and board[x+2][y] == tile and board[x+3][y] == tile:
return True
# check vertical spaces
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT - 3):
if board[x][y] == tile and board[x][y+1] == tile and board[x][y+2] == tile and board[x][y+3] == tile:
return True
# check / diagonal spaces
for x in range(BOARDWIDTH - 3):
for y in range(3, BOARDHEIGHT):
if board[x][y] == tile and board[x+1][y-1] == tile and board[x+2][y-2] == tile and board[x+3][y-3] == tile:
return True
# check \ diagonal spaces
for x in range(BOARDWIDTH - 3):
for y in range(BOARDHEIGHT - 3):
if board[x][y] == tile and board[x+1][y+1] == tile and board[x+2][y+2] == tile and board[x+3][y+3] == tile:
return True
return False
def playAgain():
# This function returns True if the player wants to play again, otherwise it returns False.
print('Do you want to play again? (yes or no)')
return input().lower().startswith('y')
if __name__ == '__main__':
main()