Skip to content

Instantly share code, notes, and snippets.

@Samuel-Retter
Last active August 29, 2015 14:01
Show Gist options
  • Save Samuel-Retter/7109ebb265bd2044a00a to your computer and use it in GitHub Desktop.
Save Samuel-Retter/7109ebb265bd2044a00a to your computer and use it in GitHub Desktop.
Plays the game of Connect Four against a human opponent.
__author__ = 'Samuel'
# Python 3.3
# Plays the game of Connect 4 against a human opponent
import random
# global constants
X = 'X'
O = 'O'
EMPTY = " "
TIE = 'TIE'
A = [0,1,2,3,4,5]
B = [6,7,8,9,10,11]
C = [12,13,14,15,16,17]
D = [18,19,20,21,22,23]
E = [24,25,26,27,28,29]
F = [30,31,32,33,34,35]
G = [36,37,38,39,40,41]
COLUMNS = [A, B, C, D, E, F, G]
COLUMNSNAMES = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
WAYS_TO_WIN = []
for i in range(24):
WAYS_TO_WIN.append((i,i+6,i+12,i+18))
for i in range(42):
if i % 6 <= 2:
WAYS_TO_WIN.append((i,i+1,i+2,i+3))
for i in range(42):
if i <= 23 and i % 6 <= 2:
WAYS_TO_WIN.append((i,i+7,i+14,i+21))
for i in range(42):
if i <= 23 and i % 6 > 2:
WAYS_TO_WIN.append((i,i+5,i+10,i+15))
def display_instruct():
print(
"""
Welcome to Connect 4.
You will make your move known by entering a letter, A-G. The letter will
correspond to a column as follows:
A B C D E F G
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
| | | | | | | |
+---+---+---+---+---+---+---+
"""
)
def ask_yes_no(question):
"""Ask a yes or no question."""
response = None
while response not in ("1", "2"):
response = input(question).lower()
return response
def ask_letter(question):
"""Ask for a letter"""
response = 'nothingYet'
while response.upper() not in COLUMNSNAMES:
response = input(question)
return response.upper()
def pieces():
"""Determine if player or computer goes first."""
go_first = ask_yes_no("Enter 1 to go first, 2 to go second: ")
if go_first == "1":
print("\nOk. Make a move.")
human = X
computer = O
else:
print("\nI'll go first, then.")
computer = X
human = O
return computer, human
def new_board():
"""Create new game board."""
board = []
for square in range(42):
board.append(EMPTY)
return board
def display_board(board):
"""Display game board on screen."""
print("\n A B C D E F G")
print(" +"+"---+"*7)
print(" |", board[5], "|", board[11], "|", board[17], "|", board[23], "|", board[29], "|", board[35], "|", board[41], "|")
print(" +"+"---+"*7)
print(" |", board[4], "|", board[10], "|", board[16], "|", board[22], "|", board[28], "|", board[34], "|", board[40], "|")
print(" +"+"---+"*7)
print(" |", board[3], "|", board[9], "|", board[15], "|", board[21], "|", board[27], "|", board[33], "|", board[39], "|")
print(" +"+"---+"*7)
print(" |", board[2], "|", board[8], "|", board[14], "|", board[20], "|", board[26], "|", board[32], "|", board[38], "|")
print(" +"+"---+"*7)
print(" |", board[1], "|", board[7], "|", board[13], "|", board[19], "|", board[25], "|", board[31], "|", board[37], "|")
print(" +"+"---+"*7)
print(" |", board[0], "|", board[6], "|", board[12], "|", board[18], "|", board[24], "|", board[30], "|", board[36], "|")
print(" +"+"---+"*7)
print()
def legal_moves(board):
"""Create a list of legal moves."""
moves = []
for column in COLUMNS:
if column:
moves.append(column)
return moves
def winner(board):
"""Determine the game winner."""
for row in WAYS_TO_WIN:
if board[row[0]] == board[row[1]] == board[row[2]] == board[row[3]] != EMPTY:
winner = board[row[0]]
return winner
if EMPTY not in board:
return TIE
return None
def human_move(board, human):
"""Get human move."""
legal = legal_moves(board)
move = 'nothingYet'
while move.upper() not in COLUMNSNAMES:
move = ask_letter("In which column would you like to drop your piece? (A - G): ")
if move.upper() not in COLUMNSNAMES:
print("\nThat column is already full. Choose another.\n")
return move
def moveprinter(moveX):
for i in 'DCEBFAG':
if moveX == globals()[i]:
print(i)
return
def test(move, human, board):
board = board[:]
if len(move) == 1:
return 'safe'
board[move[1]] = human
if winner(board) == human:
return 'unsafe'
return 'safe'
board[move[1]] = EMPTY
def test2(move, computer, board):
board = board[:]
if len(move) == 1:
return 'safe'
board[move[1]] = computer
if winner(board) == computer:
return 'unsafe'
return 'safe'
board[move[1]] = EMPTY
def computer_move(board, computer, human):
print("\nI will drop my piece in column", end=" ")
# win if possible
board = board[:]
for move in legal_moves(board):
board[move[0]] = computer
if winner(board) == computer:
moveprinter(move)
return move
board[move[0]] = EMPTY
# block human's win
for move in legal_moves(board):
board[move[0]] = human
if winner(board) == human:
moveprinter(move)
return move
board[move[0]] = EMPTY
# create double trap
for move in legal_moves(board):
board[move[0]] = computer
rows_with_at_least_three_computers = []
for row in WAYS_TO_WIN:
computersinrow = []
for square in row:
if board[square] == computer:
computersinrow.append(square)
availablesquares = []
for column in COLUMNS:
if column:
availablesquares.append(column[0])
if row[0] in availablesquares or row[1] in availablesquares or row[2] in availablesquares or row[3] in availablesquares:
bool1 = True
else:
bool1 = False
if len(computersinrow) == 3 and EMPTY in [board[row[0]], board[row[1]], board[row[2]], board[row[3]]] and bool1:
rows_with_at_least_three_computers.append(row)
if len(rows_with_at_least_three_computers) == 2 and test(move, human, board) == 'safe':
moveprinter(move)
return move
# undo move
board[move[0]] = EMPTY
# if human can create a double trap, block it
for move in legal_moves(board):
board[move[0]] = human
rows_with_at_least_three_humans = []
for row in WAYS_TO_WIN:
humansinrow = []
for square in row:
if board[square] == human:
humansinrow.append(square)
availablesquares = []
for column in COLUMNS:
if column:
availablesquares.append(column[0])
if row[0] in availablesquares or row[1] in availablesquares or row[2] in availablesquares or row[3] in availablesquares:
bool2 = True
else:
bool2 = False
if len(humansinrow) == 3 and EMPTY in [board[row[0]], board[row[1]], board[row[2]], board[row[3]]] and bool2:
rows_with_at_least_three_humans.append(row)
if len(rows_with_at_least_three_humans) == 2 and test(move, human, board) == 'safe' and test2(move, computer, board) == 'safe':
moveprinter(move)
return move
# undo move
board[move[0]] = EMPTY
# horizontal trios
midtrios = []
for i in range(6,24):
midtrios.append((i,i+6,i+12))
if i % 6 <= 2:
midtrios.append((i,i+7,i+14))
elif i % 6 > 2:
midtrios.append((i,i+5,i+10))
begtrios = []
for i in range(0,6):
begtrios.append((i,i+6,i+12))
if i % 6 <= 2:
begtrios.append((i,i+7,i+14))
elif i % 6 > 2:
begtrios.append((i,i+5,i+10))
endtrios = []
for i in range(24,30):
endtrios.append((i,i+6,i+12))
if i % 6 <= 2:
endtrios.append((i,i+7,i+14))
elif i % 6 > 2:
endtrios.append((i,i+5,i+10))
best_moves = [D,C,E,B,F,A,G]
r1 = random.randint(0,1)
r2 = random.randint(0,1)
r3 = random.randint(0,1)
if r1:
best_moves[1],best_moves[2] = best_moves[2],best_moves[1]
if r2:
best_moves[3],best_moves[4] = best_moves[4],best_moves[3]
if r3:
best_moves[5],best_moves[6] = best_moves[6],best_moves[5]
# if human can complete a trio next turn, block it
for move in best_moves:
if move and test(move, human, board) == 'safe' and test2(move, computer, board) == 'safe':
board[move[0]] = human
for trio in midtrios:
if board[trio[0]-(trio[1]-trio[0])] == EMPTY or board[trio[2]+(trio[2]-trio[1])] == EMPTY:
bool3 = True
else:
bool3 = False
if board[trio[0]] == board[trio[1]] == board[trio[2]] == human and bool3:
moveprinter(move)
return move
board[move[0]] = human
for trio in begtrios:
if board[trio[2]+(trio[2]-trio[1])] == EMPTY:
bool4 = True
else:
bool4 = False
if trio[0]==trio[1]==trio[2]==human and bool4:
moveprinter(move)
return move
board[move[0]] = human
for trio in endtrios:
if board[trio[0]-(trio[1]-trio[0])] == EMPTY:
bool5 = True
else:
bool5 = False
if trio[0]==trio[1]==trio[2]==human and bool5:
moveprinter(move)
return move
board[move[0]] = EMPTY
# if computer can complete a trio next turn, go there
for move in best_moves:
if move and test(move, human, board) == 'safe' and test2(move, computer, board) == 'safe':
board[move[0]] = computer
for trio in midtrios:
if board[trio[0]-(trio[1]-trio[0])] == EMPTY or board[trio[2]+(trio[2]-trio[1])] == EMPTY:
bool3 = True
else:
bool3 = False
if board[trio[0]] == board[trio[1]] == board[trio[2]] == computer and bool3:
moveprinter(move)
return move
board[move[0]] = computer
for trio in begtrios:
if board[trio[2]+(trio[2]-trio[1])] == EMPTY:
bool4 = True
else:
bool4 = False
if trio[0]==trio[1]==trio[2]==computer and bool4:
moveprinter(move)
return move
board[move[0]] = computer
for trio in endtrios:
if board[trio[0]-(trio[1]-trio[0])] == EMPTY:
bool5 = True
else:
bool5 = False
if trio[0]==trio[1]==trio[2]==computer and bool5:
moveprinter(move)
return move
board[move[0]] = EMPTY
for move in best_moves:
if move:
if move in legal_moves(board) and test(move, human, board) == 'safe' and test2(move, computer, board) == 'safe':
moveprinter(move)
return move
for move in best_moves:
if move:
if move in legal_moves(board) and test(move, human, board) == 'safe':
moveprinter(move)
return move
for move in best_moves:
if move in legal_moves(board):
moveprinter(move)
return move
def next_turn(turn):
"""Switch turns."""
if turn == X:
return O
else:
return X
def congrat_winner(the_winner, computer, human):
"""Congratulate the winner."""
if the_winner == computer:
print("I win!")
elif the_winner == human:
print("You win!")
elif the_winner == TIE:
print("It's a tie!")
def main():
print('\n\n\n\n')
display_instruct()
computer, human = pieces()
turn = X
board = new_board()
display_board(board)
while not winner(board):
if turn == human:
done0 = False
while not done0:
move = human_move(board, human)
moverow = globals()[move]
try:
board[moverow[0]] = human
moverow.remove(moverow[0])
done0 = True
print("\nFine...")
except IndexError:
print("\nThat column is already full. Choose another.\n")
else:
move = computer_move(board, computer, human)
board[move[0]] = computer
move.remove(move[0])
display_board(board)
turn = next_turn(turn)
the_winner = winner(board)
congrat_winner(the_winner, computer, human)
# for human_move, "move" is a str and "moverow" is the actual list
# but for computer_move, "move" itself is the list (no need for moverow)
# now start the program
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment