This week, I focused on integrating the two boards. Last week, both boards could independently detect button presses and light up the corresponding LEDs, and we had a simple dice detection algorithm, so this week, I worked on synchronizing the two boards.
I wrote the code that sends messages between both game boards to ensure they are in sync. Whenever a button press or dice roll is detected, it now sends a message to all connected peers (in this case, only one other board). Each board currently stores its peer information (hostname, IP, etc.) in a configuration file. When the program starts, it reads this config, opens a socket that listens on all ports, and spawns a thread dedicated to receiving and processing incoming messages. Two other threads handle checking for button presses and dice rolls (and sending messages whenever anything is detected). This way, both boards can update each other in real time.
I also implemented a save state system. When a player stops playing, the board records its current state (which LEDs are on, whose turn it is, etc.) and writes it to a file. When the board is powered on again, the script automatically loads this saved state so gameplay can resume exactly where it left off. To complement this, I added a clear board button that resets all LEDs so users can start a new game at any time.
Since we decided to downsize our prototype to six tiles, I also worked on remapping the dice rolls. Normally, Catan uses numbers 2–12, but we only use seven of them (six resource tiles and 7 for the robber). We decided to turn the remaining four numbers into ports. Players can choose what resource will be gained from each port, and when a port’s number is rolled, they can take that resource. This ensures every resource appears at least twice across the six tiles and four ports, keeping the game balanced but flexible.
Finally, we added support for more than two players, even with only two boards. Instead of assigning each board to a fixed player color, I added an “end turn” button. When pressed, it cycles through the colors based on the number of players (2–4) entered at the start of the game. This means four players can now play together using the same board, increasing the overall usability.
Finally, we also finished the visual design: gluing down the printed resource images on each tile and adding the blue water background to make the board match the real Catan aesthetic.
Next week, I plan on thoroughly testing our boards and fixing any minor bugs in the code. I also plan on spending most of my time working on the presentation, as I will be working from home and won’t be on campus to work on the actual game boards. Once I come back, I hope to spend time working on making the RPi start running the script immediately upon it being powered on (so you don’t need to connect a computer to start the script). Any information the user needs to enter can be entered directly through a connected keyboard.
To implement board synchronization, I had to learn more about socket programming and managing multiple threads in Python. I previously took Distributed Systems in Go, so I reused the structure I would normally write in Go, then translated that into Python by reading library docs and small code examples online.
I also had to learn how to debug NeoPixel strip issues that only showed up as segfaults in the terminal. At first it wasn’t obvious that the problem was the LEDs at all, or that it was caused by multiple threads writing to the strips at the same time. I went through a lot of Stack Overflow posts and videos about driving multiple NeoPixel strips from one Raspberry Pi. That’s how I realized the NeoPixel library itself isn’t thread-safe, and that simple locks around the strips weren’t enough. In the end, I fixed it by creating a single dedicated thread whose only job is to update the NeoPixels. All other parts of the code just push “update requests” into a queue, and that one thread processes them in order. This removed the race condition without needing complicated locking and made the LED behavior much more stable.