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 processor | Difficulty / depth 4 | Difficulty / depth 5 |
Laptop with Ryzen 7 processor | < 1 sec | 3 sec |
Rasperry Pi 3 with ARM 4 core processor | 4 sec | 18 sec |
Rasperry Pi 1 with Broadcom single core processor | 15 sec | 1 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.