Connect 4 – Week 8 (10.10 – 16.10)


This week, we finally added the algorithm to our connect 4 demo python program. You can now choose difficulties from 0 to 5, where 0 equals random turn and 1 to 5 the parameter of the tree depth of the minmax algorithm. We used the implementation from Keith Galli, he made a good YouTube video about it: https://www.youtube.com/watch?v=MMLtza3CZFM Just needed to do the adjustment to our working functions and variable names..

def minimax(board, depth, alpha, beta, maximizing_player):
    open_columns = get_open_columns(board)
    is_terminal = winning_move(board, PLAYER_COIN) or winning_move(board, COMPUTER_COIN) or len(
        get_open_columns(board)) == 0
    if is_terminal:
        if winning_move(board, COMPUTER_COIN):
            return None, 100000000000000
        elif winning_move(board, PLAYER_COIN):
            return None, -10000000000000
        else:  # Game is over, no more valid moves
            return None, 0
    if depth == 0:  # Depth is zero
        return None, score_position(board, COMPUTER_COIN)

    if maximizing_player:
        value = -math.inf
        column = random.choice(open_columns)
        for col in open_columns:
            b_copy = board.copy()
            place_coin(b_copy, col, COMPUTER_COIN)
            new_score = minimax(b_copy, depth - 1, alpha, beta, False)[1]
            if new_score > value:
                value = new_score
                column = col
            alpha = max(alpha, value)
            if alpha >= beta:
                break
        return column, value

With difficulty 4 and 5 it’s impossible to win and even draw is really hard. On difficulty 3 you can play draw really good and winning is quite possible if you are familiar with “traps” and looking / thinking a bit into the future. Also with more depth, the calculation power needed rises very much! (Every new tree level the possibilities rises exponentially.) Zoran gave as a Rasperry 3 B+ this week and I tried to run the program on it and also on my own Rasperry 3 B+ and my personal computer (with Ryzen 7 processor). Below is a table of how long it takes to calculate one move.

Device and processorDifficulty / depth 4Difficulty / depth 5
Laptop with Ryzen 7 processor< 1 sec3 sec
Rasperry Pi 3 with ARM 4 core processor4 sec18 sec
Rasperry Pi 1 with Broadcom single core processor15 sec1 min 8 sec

As you can see, the time improvement from Rasperry Pi 1 to 3 is a quarter! Really good we think..

We also read about buttons via GPIO on rasperry pi. We will have a difficulty button and a start/stop button. There should be also something like a main menu on the LCD, where you can view the difficulty.. And with the start button you can start out of the main menu. Pressing the button again the game should stop. The problem that came up is that waiting for a button interrupt isn’t useful, as we cannot play in the meantime.

import RPi.GPIO as GPIO
BUTTON_GPIO = 18
if __name__ == '__main__':
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(BUTTON_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    while True:
        GPIO.wait_for_edge(BUTTON_GPIO, GPIO.FALLING)
        print("Button pressed.")

So we researched a little bit and found this tutorial: https://roboticsbackend.com/raspberry-pi-gpio-interrupts-tutorial/
There is a function GPIO.add_event_detect() and it will run a callback function as soon as the button is pressed:

import signal
import sys
import RPi.GPIO as GPIO
BUTTON_GPIO = 16
def signal_handler(sig, frame):
    GPIO.cleanup()
    sys.exit(0)
def button_pressed_callback(channel):
    print("Button pressed!")
if __name__ == '__main__':
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(BUTTON_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.add_event_detect(BUTTON_GPIO, GPIO.FALLING, 
            callback=button_pressed_callback, bouncetime=100)
    
    signal.signal(signal.SIGINT, signal_handler)
    signal.pause()

So the next idea is to pack the game into a own process or thread, that will be start or stopped by button press. With the use of separate process/thread, it is also guaranteed that the game is closed properly and a new “fresh” game will start after reopen. Also we can easily pass the difficulty into the game. We will have a look into that next week and hope to realize it then already.


We also cutted the whole gameboard. As pictures are saying more than 1000 words, just look into our picture gallery below for our progress and the finished game board 🙂

The gameboard shown above is almost correct, it just needs a little bit of adjusting the holes to match the LED light on the LED strip. After this part we can lasercut and assemble the top part for dropping the coins in the gameboard. The difficulty is going to be that the coins only have a small margin to the front and the back so we have to make sure that the coindropper is pretty precize.

, ,

Leave a Reply