python – Gomoku (Connect 5) game implementation in pygame

I attempted to implement a simple Gomoku game (connect 5) in pygame and wanted to get some help. So far, the basic features are working fine with 2 players going against each other.

Questions

  1. I was trying to display a text message in a black box when a player wins but the message never appears on the screen.

the code is below:

# font
my_font = pygame.font.Font('freesansbold.ttf', 40)

# text message
label_1 = my_font.render('Player 1 wins!', 1, WHITE, BLACK)
label_2 = my_font.render('Player 2 wins!', 1, WHITE, BLACK)

# text surface
text_box_1 = label_1.get_rect()
text_box_1.center = (S_WIDTH // 2, S_HEIGHT // 2)
text_box_2 = label_2.get_rect()
text_box_2.center = (S_WIDTH // 2, S_HEIGHT // 2)

If a player wins, display the text in a text box

                    if who_wins(board,piece_1):
                        print('Player 1 wins!')
                        SCREEN.blit(label_1, text_box_1)
                        pygame.display.update()
                        game_over = True

update:

I thought the text surface was not necessary, so I got rid of it.

new code:

# font
my_font = pygame.font.Font('freesansbold.ttf', 40)

# text message
label_1 = my_font.render('Black wins!', True, WHITE, BLACK)
label_2 = my_font.render('White wins!', True, WHITE, BLACK)

I also updated the arguments within blit() method.

                    if who_wins(board,piece_1):
                        print('Black wins!')
                        SCREEN.blit(label_1, (375,375))
                        pygame.display.update()
                        game_over = True

From my understanding, the render() method takes in arguments text, antialias, color, background, which I believe I input correctly. Also, for the blit() method, I put in the arguments as I was supposed to blit(source = text_i_want, dest = (tuple_x,y)). However, the text still would not print on the screen. Am I using the blit() method in the wrong place? Or should I create another surface to render the text, on top of my pygame window?

  1. Another issue I seem to be having is if I click a spot where a piece is already in place, the piece color would not change. Technically I can have one player go alone like this

enter image description here

A normal game would look like this

enter image description here

The function I created to check if it is a valid position to drop a piece is this:

# check if it is a valid location
def is_valid_loc(board, row, col):
    return board(row)(col) == 0

Usage within the game loop:

  elif event.type == pygame.MOUSEBUTTONDOWN:
            # Ask for Player 1 move
            if turn == 0:
                x_pos = event.pos(0)
                y_pos = event.pos(1)
                # row = int(input('Player 1, Enter the row you want to place your piece: '))
                # col = int(input('Player 1, Enter the col you want to place your piece: '))
                col = int(math.floor(x_pos / BLOCKSIZE))
                row = int(math.floor(y_pos / BLOCKSIZE))

                # check if its a valid location then drop a piece
                if is_valid_loc(board, row, col):
                    drop_piece(board, row, col, piece_1)

                    if who_wins(board,piece_1):
                        print('Player 1 wins!')
                        SCREEN.blit(label_1, text_box_1)
                        pygame.display.update()
                        game_over = True

The entire code looks a bit messy but any help/criticism would be very welcome. Thanks!

import numpy as np
import pygame
import sys
import math

# initialize the pygame program
pygame.init()

# static variables
ROW_COUNT = 15
COL_COUNT = 15
game_over = False
turn = 0
piece_1 = 1 # black
piece_2 = 2 # white

# define screen size
BLOCKSIZE = 50 # individual grid
S_WIDTH = COL_COUNT * BLOCKSIZE # screen width
S_HEIGHT = ROW_COUNT * BLOCKSIZE # screen height
SCREENSIZE = (S_WIDTH,S_HEIGHT)
RADIUS = 20 # game piece radius

# colors
BLACK = (0,0,0)
WHITE = (255,255,255)
BROWN = (205,128,0)

# FPS
FPS = 60
frames_per_sec = pygame.time.Clock()

# create a board array
def create_board(row, col):
    board = np.zeros((row,col))
    return board

# draw a board in pygame window
def draw_board(screen):
    for x in range(0,S_WIDTH,BLOCKSIZE):
        for y in range(0,S_HEIGHT,BLOCKSIZE):
            rect = pygame.Rect(x, y, BLOCKSIZE, BLOCKSIZE)
            pygame.draw.rect(screen,BROWN,rect)

    # draw inner grid lines
    # draw vertical lines
    for x in range(BLOCKSIZE // 2, S_WIDTH - BLOCKSIZE // 2 + BLOCKSIZE, BLOCKSIZE):
        line_start = (x, BLOCKSIZE // 2)
        line_end = (x,S_HEIGHT-BLOCKSIZE // 2)
        pygame.draw.line(screen, BLACK, line_start,line_end,2)

    # draw horizontal lines
    for y in range(BLOCKSIZE // 2, S_HEIGHT - BLOCKSIZE // 2 + BLOCKSIZE, BLOCKSIZE):
        line_start = (BLOCKSIZE // 2,y)
        line_end = (S_WIDTH-BLOCKSIZE // 2,y)
        pygame.draw.line(screen, BLACK, line_start,line_end,2)

    # draw game pieces at mouse location
    for x in range(COL_COUNT):
        for y in range(ROW_COUNT):
            circle_pos = (x * BLOCKSIZE + BLOCKSIZE//2, y * BLOCKSIZE + BLOCKSIZE//2)
            if board(y)(x) == 1:
                pygame.draw.circle(screen, BLACK, circle_pos, RADIUS)
            elif board(y)(x) == 2:
                pygame.draw.circle(screen, WHITE, circle_pos, RADIUS)
    pygame.display.update()

# drop a piece
def drop_piece(board, row, col, piece):
    board(row)(col) = piece

# check if it is a valid location
def is_valid_loc(board, row, col):
    return board(row)(col) == 0

# victory decision
def who_wins(board, piece):
    # check for horizontal win
    for c in range(COL_COUNT - 4):
        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
                and board(r)(c+4) == piece:
                return True

    # check for vertical win
    for c in range(COL_COUNT):
        for r in range(ROW_COUNT-4):
            if board(r)(c) == piece and board(r+1)(c) == piece and board(r+2)(c) == piece and board(r+3)(c) == piece
                and board(r+4)(c) == piece:
                return True

    # check for positively sloped diagonal wih
    for c in range(COL_COUNT-4):
        for r in range(4,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
                and board(r-4)(c+4) == piece:
                return True

    # check for negatively sloped diagonal win
    for c in range(COL_COUNT-4):
        for r in range(ROW_COUNT-4):
            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
                and board(r+4)(c+4) == piece:
                return True


# board 2D array
board = create_board(ROW_COUNT,COL_COUNT)
print(board)

# game screen
SCREEN = pygame.display.set_mode(SCREENSIZE)
pygame.display.set_caption('Gomoku (Connet 5)')
# icon = pygame.image.load('icon.png')
# pygame.display.set_icon(icon)

# font
my_font = pygame.font.Font('freesansbold.ttf', 40)

# text message
label_1 = my_font.render('Player 1 wins!', 1, WHITE, BLACK)
label_2 = my_font.render('Player 2 wins!', 1, WHITE, BLACK)

# text surface
text_box_1 = label_1.get_rect()
text_box_1.center = (S_WIDTH // 2, S_HEIGHT // 2)
text_box_2 = label_2.get_rect()
text_box_2.center = (S_WIDTH // 2, S_HEIGHT // 2)

# display the screen
draw_board(SCREEN)
pygame.display.update()

# game loop
while not game_over:

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


        elif event.type == pygame.MOUSEBUTTONDOWN:
            # Ask for Player 1 move
            if turn == 0:
                x_pos = event.pos(0)
                y_pos = event.pos(1)
                # row = int(input('Player 1, Enter the row you want to place your piece: '))
                # col = int(input('Player 1, Enter the col you want to place your piece: '))
                col = int(math.floor(x_pos / BLOCKSIZE))
                row = int(math.floor(y_pos / BLOCKSIZE))

                # check if its a valid location then drop a piece
                if is_valid_loc(board, row, col):
                    drop_piece(board, row, col, piece_1)

                    if who_wins(board,piece_1):
                        print('Player 1 wins!')
                        SCREEN.blit(label_1, text_box_1)
                        pygame.display.update()
                        game_over = True

            # Ask for Player 2 move
            else:
                # row = int(input('Player 2, Enter the row you want to place your piece: '))
                # col = int(input('Player 2, Enter the col you want to place your piece: '))
                x_pos = event.pos(0)
                y_pos = event.pos(1)

                col = int(math.floor(x_pos / BLOCKSIZE))
                row = int(math.floor(y_pos / BLOCKSIZE))

                # check if its a valid location then drop a piece
                if is_valid_loc(board, row, col):
                    drop_piece(board, row, col, piece_2)

                    if who_wins(board,piece_2):
                        print('player 2 wins!')
                        SCREEN.blit(label_2, text_box_2)
                        pygame.display.update()
                        game_over = True

            print(board)
            draw_board(SCREEN)

            turn += 1
            turn = turn % 2

            if game_over:
                pygame.time.wait(4000)

    frames_per_sec.tick(FPS)