Connect Four with Minimax Algorithm
import numpy as np
import sys
ROWS = 6
COLUMNS = 7
PLAYER1 = 1
PLAYER2 = 2
class ConnectFour:
def __init__(self):
self.board = np.zeros((ROWS, COLUMNS), int)
def print_board(self):
print(np.flip(self.board, 0))
def is_valid_location(self, col):
return self.board[ROWS - 1][col] == 0
def get_next_open_row(self, col):
for r in range(ROWS):
if self.board[r][col] == 0:
return r
def drop_piece(self, row, col, piece):
self.board[row][col] = piece
def winning_move(self, piece):
# Check horizontal locations
for c in range(COLUMNS - 3):
for r in range(ROWS):
if all(self.board[r][c + i] == piece for i in range(4)):
return True
# Check vertical locations
for c in range(COLUMNS):
for r in range(ROWS - 3):
if all(self.board[r + i][c] == piece for i in range(4)):
return True
# Check positively sloped diagonals
for c in range(COLUMNS - 3):
for r in range(ROWS - 3):
if all(self.board[r + i][c + i] == piece for i in range(4)):
return True
# Check negatively sloped diagonals
for c in range(COLUMNS - 3):
for r in range(3, ROWS):
if all(self.board[r - i][c + i] == piece for i in range(4)):
return True
return False
def minimax(self, depth, alpha, beta, maximizing_player):
valid_locations = [c for c in range(COLUMNS) if self.is_valid_location(c)]
is_terminal = self.winning_move(PLAYER1) or self.winning_move(PLAYER2) or not
valid_locations
if depth == 0 or is_terminal:
if self.winning_move(PLAYER1):
return (None, 100000000000000)
elif self.winning_move(PLAYER2):
return (None, -10000000000000)
else:
return (None, 0)
if maximizing_player:
value = -np.inf
column = np.random.choice(valid_locations)
for col in valid_locations:
row = self.get_next_open_row(col)
self.drop_piece(row, col, PLAYER1)
new_score = self.minimax(depth - 1, alpha, beta, False)[1]
self.drop_piece(row, col, 0)
if new_score > value:
value = new_score
column = col
alpha = max(alpha, value)
if alpha >= beta:
break
return column, value
else:
value = np.inf
column = np.random.choice(valid_locations)
for col in valid_locations:
row = self.get_next_open_row(col)
self.drop_piece(row, col, PLAYER2)
new_score = self.minimax(depth - 1, alpha, beta, True)[1]
self.drop_piece(row, col, 0)
if new_score < value:
value = new_score
column = col
beta = min(beta, value)
if beta <= alpha:
break
return column, value
def play_game(self):
while True:
# Player 1 Input
self.print_board()
col = int(input("Player 1 (1) - Select a column (0-6): "))
if self.is_valid_location(col):
row = self.get_next_open_row(col)
self.drop_piece(row, col, PLAYER1)
if self.winning_move(PLAYER1):
self.print_board()
print("Player 1 wins!")
break
# Player 2 (AI) Move
col, _ = self.minimax(4, -np.inf, np.inf, True)
if self.is_valid_location(col):
row = self.get_next_open_row(col)
self.drop_piece(row, col, PLAYER2)
if self.winning_move(PLAYER2):
self.print_board()
print("Player 2 (AI) wins!")
break
if __name__ == "__main__":
game = ConnectFour()
game.play_game()