Connect Four Game in Python

CONNECT4

Before starting off, let us first understand what connect Four game actually is.

Connect4 game is also known as Four Up, Plot Four, Find Four, Captain’s Mistress, Four in a Row, Drop Four, and Gravitrips in the Soviet Union.

It is a two-player connection board game, in which the players choose a color and then take turns dropping colored discs into a seven-column, six-row vertically suspended grid.

The pieces fall straight down, occupying the lowest available space within the column.

The objective of the game is to be the first to form a horizontal, vertical, or diagonal line of four of one’s own discs. Connect Four is a solved game.

The first player can always win by playing the right moves. Sounds fun right?

Let us understand how to code this game in python programming language.


Import the necessary Libraries for the Connect Four Game

1. NumPy module

NumPy Library: NumPy stands for Numerical Python. NumPy is a Python library used for working with arrays. It also has functions for working in domain of linear algebra, fourier transform, and matrices. It is an open source project and you can use it freely. NumPy is a Python library that provides a simple yet powerful data structure: the n-dimensional array.

If you don’t have NumPy already pre-installed on your system, type the following command in your window’s cmd:

C:\Users\Admin> pip install numpy

When you call the statement import numpy as np , you are shortening the phrase “numpy” to “np” to make your code easier to read. It also helps to avoid namespace issues.

import numpy as np

2. Pygame module

Pygame is a free and open-source cross-platform library for the development of multimedia applications like video games using Python.

It uses the Simple DirectMedia Layer library and several other popular libraries to abstract the most common functions, making writing these programs a more intuitive task.

If you don’t have Pygame already pre-installed on your system, type the following command in your window’s cmd:

C:\Users\Admin> pip install numpy

3. Python sys module

The python sys module provides functions and variables which are used to manipulate different parts of the Python Runtime Environment. It lets us access system-specific parameters and functions. import sys. First, we have to import the sys module in our program before running any functions. sys.modules.

4. Python math module

Some of the most popular mathematical functions are defined in the math module. These include trigonometric functions, representation functions, logarithmic functions, angle conversion functions, etc. In addition, two mathematical constants are also defined in this module.

If you don’t have math already pre-installed on your system, type the following command in your window’s cmd:

C:\Users\Admin> pip install maths

Implementing Connect Four Game in Python

Step 01

Import the NumPy package as np. Then we will create a python function named create_board( ).

np.zeros( ) function is used to create a matrix full of zeroes. This function in Python can be used when you initialize the weights during the first iteration in TensorFlow and other statistic tasks. ((6,7)) are the dimensions. 6 rows and 7 columns. Then we just return that board.

We will begin writing the main game loop now. We’re going to create a loop as while not game_over. A while not loop repeatedly executes the body of the loop until the condition for loop termination is met. Our loop is going to run as long as this game_over variable is false. We will initialize the game_over as False. The only time its going to switch to true is if someone gets 4 circles in a row.

To increase the turn by 1 we will use turn += 1. To make it switch between player 1 and 2 alternatively, we use turn = turn % 2.

import numpy as np

def create_board():
    board = np.zeros((6,7))
    return board

#initialize board
board = create_board()
#We will initialize the game_over as False.
game_over = False
turn = 0

while not game_over:
    #Ask for player 1 input
    if turn == 0:
        selection = int(input("Player 1, Make your Selection(0-6):"))

    #Ask for player 2 input
    else:
        selection = int(input("Player 2, Make your Selection(0-6):"))

    turn += 1
    turn = turn % 2

Step 02

In the step 02, we make a few alterations and updates to the previous code.

We want the selection variable to actually drop a piece on the board. For that, the first thing we will do is create another three functions called def drop_piece( ), def is_valid_location( ), def get_next_open_row( ).

How these functions are going to Work together is as follows, the player will make a selection. The (0-6) in the code represents the column where they want to drop their piece. Hence we update the name of selection variable to column variable (col).

Now we will take this col in the current board that we have and pass it as parameters in all the three functions with board.

We will initialize global variables called ROW_COUNT and COLUMN_COUNT. In Python, a variable declared outside of the function or in global scope is known as a global variable. This means that a global variable can be accessed inside or outside of the function.

The np.flip( ) function reverses the order of array elements along the specified axis, preserving the shape of the array.

Syntax: np.flip(array, axis)
import numpy as np

ROW_COUNT = 6
COLUMN_COUNT = 7

def create_board():
    board = np.zeros((6,7))
    return board

def drop_piece(board,row,col,piece):
    board[row][col]= piece

def is_valid_location(board,col):
    #if this condition is true we will let the use drop piece here.
    #if not true that means the col is not vacant
    return board[5][col]==0

def get_next_open_row(board,col):
    for r in range(ROW_COUNT):
        if board[r][col]==0:
            return r
    
def print_board(board):
    print(np.flip(board,0))
    
board = create_board()
print_board(board)
game_over = False
turn = 0

while not game_over:
    #Ask for player 1 input
    if turn == 0:
        col = int(input("Player 1, Make your Selection(0-6):"))
        #Player 1 will drop a piece on the board
        if is_valid_location(board,col):
            row = get_next_open_row(board,col)
            drop_piece(board,row,col,1)
        
    #Ask for player 2 input
    else:
        col = int(input("Player 2, Make your Selection(0-6):"))
        #Player 2 will drop a piece on the board
        if is_valid_location(board,col):
            row = get_next_open_row(board,col)
            drop_piece(board,row,col,2)

    print_board(board)
            
    turn += 1
    turn = turn % 2 

Step 03: Complete Code Walkthrough

In step 03, we will create a game with a GUI and not just the one with the matrices. The above code along with the new modifications that we do will make the game look like an actual board game.

First we will import all the necessary libraries.

Next we will define the colours blue, black, red and yellow as global static variables. These values are going to be rgb values.

We will initialize global variables called ROW_COUNT and COLUMN_COUNT. Number of rows are 6 and number of columns are 7.

Then we create 5 functions named create_board( ), drop_piece( ), is_valid_location( ), get_next_open_row( ) and print_board( ).

Then we create a function called winning_move() and we check for horizontal locations to win, vertical locations to win, positively and negatively sloped diagonals to win.

In horizontal and vertical locations, we create a nested for loop for the rows and columns and check an if condition statement to see if the piece has been dropped to that location on the board. If the if condition is satisfied, it will return TRUE. We will repeat the same procedure for vertical locations, positively and negatively sloped diagonals as well.

In the function def draw_board( ), pygame.draw is a module for drawing shapes.

pygame.draw.rect is used to draw a rectangle. Now we will define the triangle. Define the height and width and the position.

So the position is going to be, c*SQUARESIZE and the position of the y-axis is going to be r*SQUARESIZE+SQUARESIZE.

Height and width are going to be the other two parameters and thats just going to be SQUARESIZE, SQUARESIZE. Repeat the same procedure for circles as well.

import numpy as np
import pygame
import sys
import math

BLUE = (0,0,255)
BLACK = (0,0,0)
RED = (255,0,0)
YELLOW = (255,255,0)

ROW_COUNT = 6
COLUMN_COUNT = 7

def create_board():
	board = np.zeros((ROW_COUNT,COLUMN_COUNT))
	return board

def drop_piece(board, row, col, piece):
	board[row][col] = piece

def is_valid_location(board, col):
	return board[ROW_COUNT-1][col] == 0

def get_next_open_row(board, col):
	for r in range(ROW_COUNT):
		if board[r][col] == 0:
			return r

def print_board(board):
	print(np.flip(board, 0))

def winning_move(board, piece):
	# Check horizontal locations for win
	for c in range(COLUMN_COUNT-3):
		for r in range(ROW_COUNT):
			if board[r][c] == piece and board[r][c+1] == piece and board[r][c+2] == piece and board[r][c+3] == piece:
				return True

	# Check vertical locations for win
	for c in range(COLUMN_COUNT):
		for r in range(ROW_COUNT-3):
			if board[r][c] == piece and board[r+1][c] == piece and board[r+2][c] == piece and board[r+3][c] == piece:
				return True

	# Check positively sloped diaganols
	for c in range(COLUMN_COUNT-3):
		for r in range(ROW_COUNT-3):
			if board[r][c] == piece and board[r+1][c+1] == piece and board[r+2][c+2] == piece and board[r+3][c+3] == piece:
				return True

	# Check negatively sloped diaganols
	for c in range(COLUMN_COUNT-3):
		for r in range(3, ROW_COUNT):
			if board[r][c] == piece and board[r-1][c+1] == piece and board[r-2][c+2] == piece and board[r-3][c+3] == piece:
				return True

def draw_board(board):
	for c in range(COLUMN_COUNT):
		for r in range(ROW_COUNT):
			pygame.draw.rect(screen, BLUE, (c*SQUARESIZE, r*SQUARESIZE+SQUARESIZE, SQUARESIZE, SQUARESIZE))
			pygame.draw.circle(screen, BLACK, (int(c*SQUARESIZE+SQUARESIZE/2), int(r*SQUARESIZE+SQUARESIZE+SQUARESIZE/2)), RADIUS)
	
	for c in range(COLUMN_COUNT):
		for r in range(ROW_COUNT):		
			if board[r][c] == 1:
				pygame.draw.circle(screen, RED, (int(c*SQUARESIZE+SQUARESIZE/2), height-int(r*SQUARESIZE+SQUARESIZE/2)), RADIUS)
			elif board[r][c] == 2: 
				pygame.draw.circle(screen, YELLOW, (int(c*SQUARESIZE+SQUARESIZE/2), height-int(r*SQUARESIZE+SQUARESIZE/2)), RADIUS)
	pygame.display.update()


board = create_board()
print_board(board)
game_over = False
turn = 0

#initalize pygame
pygame.init()

#define our screen size
SQUARESIZE = 100

#define width and height of board
width = COLUMN_COUNT * SQUARESIZE
height = (ROW_COUNT+1) * SQUARESIZE

size = (width, height)

RADIUS = int(SQUARESIZE/2 - 5)

screen = pygame.display.set_mode(size)
#Calling function draw_board again
draw_board(board)
pygame.display.update()

myfont = pygame.font.SysFont("monospace", 75)

while not game_over:

	for event in pygame.event.get():
		if event.type == pygame.QUIT:
			sys.exit()

		if event.type == pygame.MOUSEMOTION:
			pygame.draw.rect(screen, BLACK, (0,0, width, SQUARESIZE))
			posx = event.pos[0]
			if turn == 0:
				pygame.draw.circle(screen, RED, (posx, int(SQUARESIZE/2)), RADIUS)
			else: 
				pygame.draw.circle(screen, YELLOW, (posx, int(SQUARESIZE/2)), RADIUS)
		pygame.display.update()

		if event.type == pygame.MOUSEBUTTONDOWN:
			pygame.draw.rect(screen, BLACK, (0,0, width, SQUARESIZE))
			#print(event.pos)
			# Ask for Player 1 Input
			if turn == 0:
				posx = event.pos[0]
				col = int(math.floor(posx/SQUARESIZE))

				if is_valid_location(board, col):
					row = get_next_open_row(board, col)
					drop_piece(board, row, col, 1)

					if winning_move(board, 1):
						label = myfont.render("Player 1 wins!!", 1, RED)
						screen.blit(label, (40,10))
						game_over = True


			# # Ask for Player 2 Input
			else:				
				posx = event.pos[0]
				col = int(math.floor(posx/SQUARESIZE))

				if is_valid_location(board, col):
					row = get_next_open_row(board, col)
					drop_piece(board, row, col, 2)

					if winning_move(board, 2):
						label = myfont.render("Player 2 wins!!", 1, YELLOW)
						screen.blit(label, (40,10))
						game_over = True

			print_board(board)
			draw_board(board)

			turn += 1
			turn = turn % 2

			if game_over:
				pygame.time.wait(3000)

Our completed GUI Connect Four Game in Python

connect four game connect4 game connect 4 game in PYthon

Ending notes…

This was the complete explanation of how to code the famous connect four game in Python. Pygame makes it easy for the users to learn and code a lot of games. I hope you will surely try coding this and enjoy the game that you created yourself.

Happy Learning!