Search code examples
python-3.xpygameminimax

PyGame, waiting for computer to decide its move


Okay

So I am building a tic-tac-toe on pygame in which A player can play against player, computer vs player or computer vs computer.

I have already developed the code for a MiniMaxAgent() which takes its input as a 2D matrix and returns the (row, col) where it would play a move. The thing is that this code can take several seconds to execute on an nxn board. Because of this the pyGame Code hangs.

Sample event loop:

while running:
    mouseClicked = False
    DISPLAYSURF.fill(BGCOLOR)
    renderBoard()
    #event handlers
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        if event.type == MOUSEMOTION:
                mouseX, mouseY = event.pos
        elif event.type == MOUSEBUTTONUP:
            mouseX, mouseY = event.pos
            mouseClicked = True

    row, col = players[currentPlayer].turn(currentPlayer*board.state)
    board.state[row][col] = currentPlayer
    currentPlayer = currentPlayer * -1
    pygame.display.update()

As you can see, when I call the function players[currentPlayer].turn(), It should return me the optimal move in some seconds. But PyGame freezes.

How should I implement this?


Solution

  • A simple solution is to run the blocking function in question in a Thread. This will allow your game loop to keep running.

    Here's a simple example. Note how the loop keeps running while the turn function wastes some time.

    import pygame
    import pygame.freetype
    import random
    import time
    import threading
    pygame.init()
    screen = pygame.display.set_mode((800, 300))
    
    PLAYER_TURN, AI_TURN = 0, 1
    font = pygame.freetype.Font(None, 30)
    state = PLAYER_TURN
    running = True
    result = None
    
    def turn(boardstate):
        print('thinking about ' + boardstate + '....')
        time.sleep(1)
        print('thinking very hard....')
        time.sleep(1)
        global result
        global state
        result = random.randint(10, 100)
        state = PLAYER_TURN
    
    r = pygame.rect.Rect((0, 250, 100, 50))
    
    while running:
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                running = False
            elif e.type == pygame.MOUSEBUTTONUP:
                if state == PLAYER_TURN:
                    state = AI_TURN
                    threading.Thread(target=turn, args=['an argument']).start()
    
        screen.fill(pygame.color.Color('grey'))
        if state == PLAYER_TURN:
            font.render_to(screen, (50, 50), 'It is your turn. Click anything')
            if result:
                font.render_to(screen, (50, 180), 'AI said: ' + str(result))
        elif state == AI_TURN:
            font.render_to(screen, (50, 50), 'Waiting for AI')
            pygame.draw.rect(screen, pygame.color.Color('red'), r)
            r.move_ip(1, 0)
            if not screen.get_rect().contains(r):
                r.x = 0
    
        pygame.display.update()
    

    enter image description here