Connect 4


Daniel Koch & Liam Davies

Issue 54, January 2022

This article includes additional downloadable resources.
Please log in to access.

Log in

We make a large-scale electronic Connect 4 game with a few DIYODE twists.

Connect 4 is a classic board game originally marketed by Milton Bradley in 1974. If you haven’t played it, it is a grid of six rows of seven columns, into which coloured discs are dropped turn by turn. The object is to get four of your coloured discs in a row. There have been a few variations over the years, but our inspiration does not come from any of these. Rather, we were motivated by the Youtube channel ‘How Ridiculous’, and the crew of Brett Stanford, Derrek Herron, Scott Gaunson, and Editor Jack. Oh, and of course, Rexy!

This team has been making some very popular videos with all sorts of themes, but several of their antics have involved Connect 4. One is based on golf putting, another is a basketball version, and there is a soccer version as well. Recently, they have also made a giant version that looks just like the commercial tabletop one, but a bit bigger and using gym balls instead of discs. We’ve linked to all of these in our ‘Reading and Resources’ section. There’s more on why this is important, shortly.


However, as awesome as How Ridiculous are, we’re not them. We’re DIYODE! There would be nothing to be gained from outright copying anyway, but we always want to make our version of a game like this somewhat electronic. Additionally, our game was built with a community youth group in mind. Items like discs get lost easily enough, but one of the bigger games that relies on balls or the like would see the supplies lost or ‘borrowed’ to other activities very quickly. The unit needed to be self-contained and independent, and function, therefore, would be closer to the traditional game than the How Ridiculous versions.

This is a bit of a trade-off that we would have liked to have found a way around. The traditional board game is considered a ‘perfect information’ game, which means that both of the opposing sides have all the possible information: Which moves have taken place, and which moves can still take place. There is no element of secrecy or concealed strategy as such. The game is also considered ‘solved’, which means its mathematical possibilities have been mapped out and there are fixed solutions. Assuming perfect play, if the first player drops their first disc into the middle column, they can win.

In real life, this is not always the case. Generally, us mere mortals who are not hyper-intelligent mathematicians cannot process all of the available moves and possibilities, or at least, not at once while consciously keeping them front of mind. We invariably forget about something or miss something. Thus, games that begin with the first player dropping their first disc into the middle column can still be won by the second player. This usually occurs through either exploitation of spontaneous mistakes, or deception and attention-diverting.

The How Ridiculous versions, however, add an element of chance. If you haven’t watched the videos, the involvement of thrown basketballs, kicked soccer balls, or putted golf balls means that a shot may not go into the column it was intended to land in, if it goes into one at all. This changes the gameplay completely and adds a level of chance, and excitement, not found in the traditional board game. While we would have liked this, we couldn’t find a way to build it in. Not in a physical way, anyhow. Instead, we came up with a way to use software to add the random factor. It isn’t as random as the versions involving throwing or kicking, but it’s a reasonable approximation.


A build of this nature is necessarily going to cost more than $10 and not all be available off the shelf at your local supermarket. However, we certainly weren’t going to have the whole thing built out of stainless steel by an engineering workshop and covered with a screen-printed acrylic front panel. While the build we ended up with isn’t a cheap build, it isn’t ‘second mortgage’ expensive, and none of it is available only to specialists.

The WS2812 LEDs we went with are available from LEDsales. The frame is made from regular timber from major hardware stores, and the cells from dollar shop foiled cardboard. Even the circle cutter used came from a major craft store. Furthermore, and perhaps most importantly, the build is adaptable. You could scale it down or even up, depending on budget and end-use. We would have liked to have made it cheaper so that more people can build it, but this just isn’t possible at the scale we wanted.


The overall concept took shape quite quickly. Initially, we thought of a large panel with buttons at the top of each row. However, some of the children involved are as young as school year two, and could not comfortably reach the top. In addition, while the youth group has no attendees with physical barriers at the moment, the possibility of someone in the future who was, say, wheelchair-bound, had to be considered. Therefore, the lighted columns had to be on their own, and the control surface had to be in its own console. That way, it could be moved and placed as needed.

This also made it easier to add buttons. We thought of using WS2812 LEDs for the console and panel straight away, so this would allow us to enable colour-selection for each player. The console features seven buttons for the columns, plus one for each player, and one more for game mode. The console is both battery-powered and USB-powered, so that it suits different situations. The main display is mains-powered via a PC power supply.


The display would have to be bright. At first, we thought of using an array of WS2812 LEDs to do this, in the form of several strips cut from a 5M ribbon, and assembled as one lamp. However, to achieve any reasonable brightness after the diffuser was added, we needed at least twenty LEDs per cell, with more if the room were to be brightly lit. There would be more in the control buttons. A 6 x 7 grid has 42 cells in it.

That would be eight hundred and forty WS2812 LEDs in one string just for the array, plus a few more for the controller. The Arduino Uno and Nano cannot control more than about 500 WS2812 LEDs before the dynamic RAM is exceeded. The Mega can handle over 1000 but not while doing a whole lot else. Power would also be an insane issue. This caused us to reconsider WS2812 LEDs, which we had thought of out of familiarity. We looked around for other options, but found other WS2812 solutions before we found anything else entirely different.

After a little bit of research, we came up with two options: Adafruit’s 3W NeoPixel, and a 3W WS2812 Generic option from LEDsales. There are advantages and disadvantages to both. The NeoPixels are cheaper and more compact. However, they are 5V units.

The LEDsales ones are 12V units, and although they are more expensive, they do not necessarily need to be attached to a heat sink like the NeoPixels. The NeoPixel version has a smaller aluminium back and nowhere near as much inherent heat sinking capability as the 12V versions which have a larger aluminium PCB. These may benefit from heat sinking, but in addition, the power supply and driver board is less dense, with better component spacing for individual component heat dissipation to ambient air.

In the end, we added heatsinks just to be safe, but the LEDs did not exceed 60°C while sitting on the workbench for three hours at full brightness. As an aside, the 12 version also includes a reservoir and power supply filter capacitor for each LED, whereas the NeoPixels do not. It also, after exploring both side-by-side on the workbench, has a much smoother PWM driver and resulting light output free of visible stepping.

Importantly, the 12V supply voltage also more than halved the current requirement, which would be a significant advantage when running wiring around. The wiring could be much smaller without excessive voltage drop or heating. Because we intended to power the LEDs and the logic from a PC power supply, 12V was available as well as the 5V or even 3.3V to power the logic.


The final plan, then, involved a separate display panel with 12V, 3W, WS2812 LEDs for the main ‘disc’ or ‘token’ cells, <> run from an Arduino Uno Wifi, and powered by a PC power supply. It would have a wooden frame built with only basic carpentry skills, into which foiled cardboard reflective cells could be placed. This would be faced with thin MDF with cut-outs holding tracing paper which would help diffuse the light from the 3W LEDs, and painted blue to dress the game up as the board game original.

Separately to the panel, a console for player controls would be built, able to be placed on a table, lap, or separate stand. This would have the control buttons with their own WS2812 LEDs, and would also be controlled by an Arduino Uno Wifi. Like the real game, the code would not try to figure out if a win had been achieved. The console would have an internal lithium-Ion battery, and USB power/charge circuit.


The first task in the frame build was to determine the depth of the frame, which in turn is defined by the viewing angle of the LEDs used. We could have used the data for this, but the stated viewing angles are usually from centre to where the light has dropped to 50% of the peak value. This may or may not be visually acceptable, especially once penetration through the diffuser was added in. So, we decided to explore experimentally.

This same experiment would also determine the size of the circle for the tokens/disc, which itself would define the size of each grid square and by extension, the whole array. Soon, we settled on a circle 300mm in diameter, on a frame with external dimensions of 330 x 330mm. This left a little room for the face to go over the frame without the frame being visible.

Using standard timber widths of 64mm, 89mm, and 140mm, we decided on 89mm high. 140mm gave a better diffusion but at 89mm, the diffusion was still acceptable and the brighter spot in the middle was not overly distracting or overpowering. The spot is from only one level of diffuser, separating layers of diffuser with spacing spreads the light better but wasn’t practical. This made the frame smaller and lighter than using the larger timber.


Before investing in a big build, we decided to prototype in small scale. We’re glad we did, because we learned a few things. Our initial idea involved having one button to choose game modes. That meant pressing and holding for a certain time, then pressing to cycle through game modes, before pressing and holding again.

The same button could be used for colour choice functions and so on. However, in prototyping, we found that not only is that really complicated for non-technically minded people (we borrowed some from a next-door business to test with), it doesn’t help us much. We intended to reduce the number of buttons but an LED is needed for each function anyway, whether WS2812 or regular LEDs with their own I/O pin.

Instead, we decided to multiplex the buttons, and use independent buttons for game modes and colour choice. There would still be a short push and hold feature, to help avoid sudden problems if the wrong button is pushed during a heated game. However, all mode buttons would have the same hold time, avoiding the confusion from the single button idea.

We built the scale versions using foam core board and a bit of scrap MDF (actually the back of a scrapped photo frame, we hadn’t bought the MDF for the build). The ‘panel’ model consisted of six lengths of WS2812 LED ribbon, seven LEDs long each. They were glued one under the other and wired as pictured, the way we intended the final build to be wired. Underneath was attached a Wifi Uno from Jaycar Electronics, XC4411. These were another lesson. They’re a valid item in their own right and we used them because we have several in the workshop from past projects and as stock. However, at less than half the price of the genuine Arduino Uno Wifi Rev 2, corners have to be cut.

One of these savings is by using a very quirky design with a separate ESP8266 unit onboard, connected via DIP switches. Both have to have the code loaded and be made to talk to each other, with separate drivers involved. For our purposes, this was just too much trouble. We ordered two of the genuine Uno Wifi Rev 2 for the build. However, those and other quirks aside, development was still able to take place. Minimal changes would be needed to get the code working on the Wifi Rev 2, after managing to get it working at all on the other boards!

The console prototype used the same XC4411 module, with a group of buttons mounted in the MDF panel. Seven are for the columns, and one each for the colour select, standard, chance, and timed game modes, plus one more each for each of the two players and a reset button. That’s fourteen buttons all up, and each would be illuminated with a WS2812 LED. Because we used plain black pushbuttons, much smaller than the final build’s arcade buttons, we cut lengths of WS2812 LED ribbon to suit, and glued them on above the buttons.

Underneath, things got interesting. We had to multiplex the buttons, but they are not physically arranged the same way. While the multiplexing was a four by four grid with two places redundant, the buttons were arranged in a row of seven, a row of five, and two singles. The solution was to draw two diagrams, one electrical and one more physical, and carefully label the wires on each. We also carefully labelled the underside of the panel for each button. Then, after each button was fitted with a 100nF debouncing capacitor, we started wiring with coloured silicone wire.

With the diagrams and labels, and the switches all aligned so the pins were facing the same direction, we were able to wire each into its place in the matrix. The wires were then brought out and around to the front top face of the panel, where they were attached to the Uno. The wires for pins 2 to 5 are sent high by the Uno, so these were soldered to headers and plugged in. Pin 6 is reserved for the WS2812 LED, but pins 7 to 10 are the pins that are polled by the Uno and therefore need 10kΩ resistors to ground. These were trimmed to length and inserted, then bent to form the shape you see, with a common ground. One spare piece of hookup wire was used to ground them, then the relevant wires from the switch matrix were soldered to the other side of the resistors.

Finally, power wiring was run to the LED strips, and one wire was run to connect the strips in one line. Also mounted was a breadboard power supply to give a stable 5V with enough current to run the LEDs. The same applies to the panel prototype. Note on both that there is a 330Ω resistor on the data line for the WS2812 LEDs, and the panel has a 1000µF capacitor in the middle to help stabilise the power supply.

The prototype allowed us to verify that our plan to multiplex the buttons would work, that the idea of using one mode control/colour control button was definitely too complicated (and in the end more complex to code than reading the array of buttons) and to develop the game code while physical construction took place. However, during coding, we discovered that using the internal pull-up resistors was a better option, as some pre-existing libraries for reading multiplexed buttons work this way. Therefore, they are absent from the final design and schematics.

The Panel Build:


Note: Due to the size of the cutting diagrams, they are not shown here. They would be too small to see anything meaningful. Instead, they are available under the resources section below where you can view, or print in A3.

The frame was made from four sections of 19 x 89 x 2400mm Dressed All Round (DAR) pine cut to size, with cut-down 6mm MDF sheets originally 1200 x 2400mm used for the backing. We were going to use 3mm sheets, but picking them up at the hardware store, they clearly did not have enough rigidity. The 6mm product is heavier, but stronger.

The sides of the frame are cut down to 2020mm. This corresponds to 6 x 330mm cells, plus 40mm allowed for the top and bottom rails of the frame. This allowed butt joining of the pieces, which is easier for many people. Mitre joints are stronger but require the right tools and are only better when they are done well. That’s not easy if you’re not used to them. The top rails are 2310 long, which corresponds to 7 x 330mm cells.

2 x 2400 x 1200 x 3mm MDF Sheets
2 x 2400 x 1200 x 6mm MDF Sheets
6 x 2400 x 89 x 19mm DAR Pine
3 x 2400 x 70 x 35mm Framing Pine
4G x 12mm Wood Screws
8G x 30mm Wood Screws
8G x 50mm Wood Screws
8G x 65mm Wood Screws


The backing panels had to be cut down on two sides, as the join needed to be in the centre. While not strictly necessary, we considered a centre join helpful for alignment. The height is 2020mm, a neat fit for the sides. For the shorter cut side, we take the 2310 rail length, divide it in half, but add 20mm for the frame side. That ends up at 1175mm. Strictly the extra for the frame side is 19mm but the line will be in the middle of the cut when we saw it, the blade on our circular saw having a 3mm cut width.

The frame was assembled by pilot-drilling and screwing the pieces together. We used 8G x 50mm pine screws, and we also clearance-drilled the holes in the sides. Not doing so can cause splitting as the holes are close to the end. We did not use any glue in assembly, because we want to be able to break it down for transport: Even with glue, the assembly will not be strong enough to strap to roof racks or a trailer. The backing panels were screwed on as well, with pilot holes drilled and 4G x 20mm screws used.

To help add rigidity and give somewhere to screw the MDF panel joint to, we added a brace. This is 19 x 89mm DAR pine, cut to the same 2020mm as the sides and screwed over the backing panels. Again, we used pilot holes, and clearance holes in the brace. We offset ours ever so slightly from centre because of where we had absent-mindedly placed some screws holding the panels on.

Finally, measurements were made and lines drawn to divide the inner space into 330mm cells, and diagonal lines added to find the centre of each cell. Then, a hole saw was used to drill clearance holes for the heat sinks. Use Pythagoras’s theorem to find the diagonal of your heat sink, because this dictates the diameter of the holes. A hole was drilled adjacent to the lower right-hand end LED location, for the LED power wiring. One small hole was also added at the top left for the incoming data wire for the first LED.


The cells are made from foiled cardboard. They are simply strips cut to 89mm wide, and a length slightly longer than the circumference of the circle of your chosen cut-out. Our cut-out was 300mm but the chosen cell diameter was 330mm. Standard poster cardboard sheets are 510mm x 635mm or thereabouts. We cut the sheets into strips of 89mm x 510mm, and joined two strips end-to-end to give a circle of 325mm (rounded up from decimal). That works pretty well. These were arrayed on the grid and tacked down with small amounts of hot melt glue. The amount had to be just enough to keep the ring in place, but not so much that it couldn’t be removed when the LEDs were installed and the wiring completed.

Over the top of this were laid two sheets of 3mm MDF. These were cut to size from 1200 x 2400 sheets the same as the back panels. They had the same grid drawn on them, taking the side walls into consideration, and circles cut out with a jigsaw. A good quality jigsaw and some experience using it are very helpful for this step, as getting a precise cut is hard otherwise. Our cuts are not perfect, especially since some were rushed to finish one the same day in failing light. However, they look ok from the distance that they will be viewed from in general use.

The panels were laid over the frame and cells, and screw holes marked and pilot-drilled for 4G x 20mm screws. Then, the panels were removed, the pilot holes enlarged to clear the thread (but not the countersunk heads) of the screws, and then painted with a roller and interior house paint. Make sure to get inside the cuts as well.

On the reverse side, baking paper was rolled out and carefully taped down with cloth-backed tape. Because of our not-the-best circle-cutting, there are slight gaps. This becomes the diffuser later for the light from the LEDs. We had debated acrylic sheet as a diffuser but unless you have a plastic supplier nearby, it’s hard to get. It’s also too expensive to justify when there are viable alternatives.

Alternatively, you can cut the MDF to 310mm and dress the face. This allows a less precise cut, and after cleaning the cuts, we propose facing the panel with three rows of craft paper cut from a roll. Rolls of this material come in various widths, but ours worked neatly when one side was trimmed slightly and the rows laid horizontally. If done carefully, the joins don’t even have to be covered. Once this is positioned properly, the position can be marked on it, and the grid drawn on the back. A circle cutter is then used to cut very neat 300mm holes in the paper, and then the paper is painted blue to look like the real Connect 4. At least, that’s our theoretical proposal.


With the frame and cells built, it was time to add the electronics. The LEDs have a large hexagonal PCB, but with the heat sink clearance hole drilled, the PCBs fit into the 54mm holes for our 42 x 42mm heatsinks. Additionally, the 6mm backing panel depth was too thin to safely accommodate screws: There would be sharp points protruding. Hot melt glue is out of the question because of the heat of the PCB when in operation. However, hot melt glue will work on the wiring. Accordingly, we chose to tape the wires down under a little tension with cloth-backed tape, and use that in conjunction with the friction fit of the heatsinks in the clearance holes to hold the LEDs in place.

The heat sinks were attached to the PCBs with the adhesive heatsink tape, and the LEDs placed over the holes, taking care that the LEDs faced the correct way. The PCB is marked for Data In and Data Out for the WS2812 control. The tape was applied before the wires were cut near the plugs so the extra length could be added. We missed out on using the supplied plugs and sockets by around 50mm, so if your build is smaller, you can likely use the plugs and sockets that are already attached.

Parts Required:JaycarAltronicsPakronics
1 x Arduino Uno Wifi Rev 2--ARD-ABX00021
42 x WS2812 3W LEDs LEDsales: 3W_RGB_WS2811--
1 x 330Ω ResistorRR0560R7546SS110990043
1 x ATX PC Power Supply---
12m Light-duty Hookup WireWH3015W2255ADA3175
8m 7.5A Red Medium Duty Hookup WireWH3040W2270-
8m 7.5A Black Medium Duty Hookup Wire #WH3041W2272-

Parts Required:

# For power bus and joining LEDs in rows

Each row of LEDs has its own connection to the power supply. At one end of each row, the +12V and GND wires are attached to a bus, which in our case were lengths of 7.5A hookup wire. This runs to the bottom with a bit of extra length, for use later. The power wires were joined between LEDs with the same medium duty hookup wire, which was glued down to hold it in one place.

The data wires are different: They must run in a continuous line, from the first LED to the last. That means that you need to decide now whether you will wire yours as ‘switched’ or ‘same direction’. We chose ‘same direction’, so that arrays were easier to use to control individual pixels, and this is what we coded for. We used light-duty hookup wire to run from the right-hand end of one row to the left-hand end of the next row down. We started at the top left because if arrays are to be used to control the pixels, we’re conditioned to read left-to-right, top-to-bottom.

The Arduino Uno Wifi was installed at the top left, too, but on the back of the panel. A 330Ω resistor was added between the Uno and the first LED, as recommended by most manufacturers of WS2812 products. We 3D-printed an enclosure for it, but you can buy commercial cases if a 3D printer isn’t around. A separate power supply was run in medium duty figure-eight wire down the side of the panel and along the bottom, then down the same stand leg as the 12V wiring. This connects straight to the 5V and GND pins at the Arduino end, using soldered-on and heat-shrinked header pins; and the other end is ready to wire into the ATX PC power supply.

All wiring was secured with a combination of cable clamps and cloth-backed tape. The assembly is intended to be mounted against a wall, but there are always concerns about any exposed wiring. Insurance companies do not like it, even when the wiring is 12V and 5V. Having the wiring covered with tape is not a great impression, either, and in the eyes of those unfamiliar with electronics, induces a sense of haphazardness. Additionally, the unit would not be set up permanently, and would need to be packed away. Having wiring covered with both tape and cloth helps prevent snags and damage when the unit is being moved. The frame stand necessarily has to have wide feet to be stable enough not to be pulled over if a child tries to climb on it or has a meltdown, so this leaves a gap big enough to get into.

Therefore, after all wiring was carefully secured, we planned to fit cable channel to hide the wiring. This material can be a bit brittle, however, at the smaller sizes, so we decided to wait until after transport for this step. Accordingly, you won’t see it in the photos. If you are building a version of this creation at any scale for home, you likely won’t have to worry at all.


It makes sense to test your assembly before going further. As the console had not been built yet, and we wrote the article in the same order we built ours in, we used the example projects for Adafruit NeoPixels to test our device, choosing “strandtest’. We just set the number of LEDs to 42, and everything else was left default. We could have used the prototype console but it was still set up to drive the ESP8266-based prototype panel. We uploaded the code to the Uno Wifi by taking it out of its enclosure, then replaced it and reconnected its panel wiring.

However, we did have to carefully make connections temporarily to the power supply for both the Arduino and LEDs. Accordingly, instead of modifying the PC ATX power supply (which we hadn’t actually sourced yet), we used the benchtop power supply from issue 7. We secured the 12V and 5V wires, double checked they were in the right order, and turned the power switch. We were greeted by the expected cycle of colour displays, which confirmed that we had wired correctly and soundly.


Finally, we were able to assemble the whole panel. With the wiring safely inside and the tape protecting the wiring on the back, the cells can be reinstalled. A small notch is needed in each to clear the wiring, before they are glued down with enough glue to hold it in place, but not enough to prevent removal for transport. The front MDF panels were secured again with their screws, and we were ready to add the supporting frame. Note that on the middle cells where the MDF halves meet in the middle of a circle, we used skewers extending from one panel to hold the tracing paper rigid into open space, with the other panel laying on top, so that the panels are still removable.


This step is optional for some people. This frame makes the panel freestanding, and houses the power supply. It’s a pretty simple affair made from 70 x 30mm framing pine, with 45° angle cuts being the hardest feature.

The vertical is 1m high, and secures to the panel by way of 50mm screws positioned so that the 5mm protruding finds empty space and not the edge of a reflector ring where it touches the frame. 65mm screws are used to attach the vertical to the base, and the angle braces. Two identical units were made.

One of them later had an enclosure added to cover the power supply, with plenty of ventilation holes. This is a simple box made from spare MDF, with a small hole in the front for the low voltage wires, and a larger hole at the back for the mains cord. Cable clamps were used inside to secure the wiring. After the panel is attached, so that it is 500mm off the ground, the panel power wiring can be run into the box, and the joins made.


Initially we were going to build a power supply for this project, however we saw our ATX Lab Power Supply from Issue 7 on our workbench. As this is extremely capable at delivering our required current, we opted to use this.

Even if you don't build the large 3D printed case from the original ATX Lab Power Supply project, computer power supplies are still a very efficient and safe option.

The Console Build:


The console houses the gameplay switches, an Arduino Uno Wifi, battery, and charger/DC-DC converter combination. We chose the combination device because it is guaranteed to work with both functions simultaneously. When it comes to using separate charger and DC-DC converter modules, there is no guarantee that the battery will charge correctly. Chiefly, drain from the load may affect battery condition sensing, but other challenges have been reported. The combined units feature a dedicated controller which enables the USB input to charge the battery and power the device at the same time.

This controller has status LEDs on it, and we wanted to break these out to the back panel with plastic optic fibre rather than trying to desolder and replace the tiny onboard LEDs. However, in the event, it proved very difficult and was not worth the gain.

Future consideration has been given to mounting a small seven-segment display in the front panel, for a timed-turn game. We hadn’t got this coded by the time we needed to go to print, but we want to leave the option in. Therefore, the space for it in the front panel is closed off by a blanking plate designed with enough room to accomodate a future display. Because so many I/O pins are used in this build, we expect that the display would be an SPI-driven device.


The enclosure is too big to 3D print even on our 300 x 300 x 400mm CR-10S Pro V2 and CR-X, although we could have gotten away with reducing it to just fit. Many people do not have such big printers, with 220 x 220 being around the standard now. Plenty of DIYODE readers haven’t had enough need in their lives to buy such a big 3D printer, and others haven’t needed one at all.

Often, 3D printers allow us to do projects that we would otherwise not be able to, which is why so many feature 3D printing. Other projects use it because, while there may be other ways, they require skills we don’t have or don’t have well-developed. This is such a project, but we still used timber. The enclosure is made from timber components, which is not our strongest skill set. However, many readers are good at woodwork, and there are a healthy number who have metalwork skills as well. If that’s you, then you could no doubt improve on this enclosure.

While our design features a primarily timber body, there are some panel cut-outs into which are inserted 3D-printed sub-panels for detailed work. Again, if your skills are up to it, feel free to skip the 3D printing and use what you know or have access to. We worked with 6mm MDF and 89 x 19mm DAR pine offcuts from the panel build.

Parts Required:JaycarAltronicsPakronics
14 x White Illuminated Arcade SwitchesSP0669S0914-
14 x WS2812 RGB LEDs on Round PCBZD0272-ADA1559
1 x 330Ω ResistorRR0560R7546SS110990043
1m Tinned Copper WireWH4032WR0420-
Assorted Hookup Wire - See TextWH3025W2431ADA3175
1 x LiPo Rider DC/DC Converter and LiPo Battery Charger--SS106990290
1 x 26650 Lithium BatterySB2319S4761-
1 x Latching Pushbutton On'Off SwitchSP0718S1083-
1 x Arduino Uno Wifi Rev 2--ARD-ABX00021

Parts Required:

* Quantity shown, may be sold in packs. You’ll also need a breadboard and prototyping hardware.

† The mounting hole for this switch may be smaller than the specified 20mm.

The top panel features holes for the arcade buttons used to control everything. A hole saw, Forstner bit, or spade drill is needed. The size will vary by brand of switch, but ours needed a 25mm cut-out. Unfortunately, someone got a little mixed up and cut 32mm holes. The switches have an outer diameter of 33mm! Enter the saving grace of the 3D printer. You can see in our photos that there is a bezel printed for each switch. Now you know why.

There is no set way to lay out or dimension the enclosure, but we have included plans for our enclosure and panels anyway. The back panel has a cutout that is designed to take the USB-end of the charging module. With USB C involved, we couldn’t find a short plug-to-socket fly lead (that would arrive in time) to enable mounting of the module remotely.

Once you have an assembled enclosure, drill any holes you need based on the following paragraphs, and paint your enclosure.


There are fourteen arcade buttons in this build. Seven are arranged across the top, with one for each column on the panel. In standard gameplay, the player in turn presses the button corresponding to which row they wish to drop their token into. There are also two player buttons. These are used for choosing player colour, and for ‘shooting’ in the randomised game mode that attempts to replicate the chance added by the How Ridiculous-style throwing or putting games. There are also three game mode selection buttons, a colour selection mode button, and a reset button.

The first step was to modify the arcade switches. These usually have an integral LED in a fixed-colour 5mm T1 ¾ package. We specifically wanted a colour-changing ability, and so that meant installing WS2812 LEDs. We explored using a 5mm addressable device, but the extra two legs do not fit in the mounting. Instead, we used a PCB-mounted 5050-sized WS2812 LED. Tinned copper wire was used to attach the power connections to their respective tabs on the wedge housing, while wires extended out of the case for the Data In and Data Out connections. Just like the big WS2812 LEDs used in the main panel, these need to be connected in a continuous line. The other advantage to replacing the LEDs is that the switches are 12V by default, with the LED having a resistor installed for 12V. WS2812 LED PCBs run on the same 5V as the Arduino. To make life easier after the switches were assembled, green wire was used for data in, and blue for data out.

You might find, as we did, that the data wires impact the operation of the switch. The spring-loaded plunger has a plastic extension that operates the actuator of the limit switch, however it is double-sided so the switch can be assembled either way. You may need to trim down the side opposite the actuator, as the plunger may impact the wiring and be held too high. We found that we could push our wires to the side and glue them, eliminating the need to trim anything.

That done, the switches were installed in the panel, and light-duty hookup wire was used to connect all of the LED GND pins and LED 5V pins in common rails. This works better if you pay close attention to the orientation when you install the WS2812 LED PCBs so that GND and V are always on the same side. Yes, this observation comes from us not being careful enough.

In the end, we didn’t use the 100nF capacitors or the resistors: Using the internal pull-up resistors seems to negate it, although we are prepared to install capacitors at a future time if switch bounce is an issue. Accordingly, we could now wire up the switches. We used coloured silicone wire for this, which made keeping track of what wire went where much easier. We wrote on our diagrams to show which colour was which, and just replicated it. Having the underside of your panel labelled also helps a lot!

Next, the 5V and GND wires from the LED string were taken to the charger/DC-DC converter module, and soldered to the relevant pads along with two wires to power the Uno. A solder-tab 26650 3.7V lithium-ion cell was also attached at this point, and glued down after soldering the wires on. Its wires were soldered to the correct place on the charger/DC-DC board. Finally, the Arduino Uno Wifi was installed on its base. All the switch wires were trimmed to length, a header pin soldered on, and inserted into the I/O header. Note that the default Pin 6 was used as the LED pin because a PWM pin had to be used anyway, eliminating the possibility of having all the button inputs in a continuous row.


There were two remaining tasks. Firstly, we made a simple cowling, painted bright yellow, to go around the legs of the panel stand. There had been a need identified to sandbag or otherwise weigh down the legs to prevent tipping if someone grabbed hold of the panel and pulled it forward. The cowling prevents tripping over the legs or sandbags, and helps reduce access behind the panel. While it is tempting to write off these possibilities as ‘unlikely’ or even ‘self-inflicted’, that’s not good enough for a public space. Reasonable attempts must be taken to prevent injury by identified hazards, no matter the level of apparent ignorance or intention involved. This is particularly true of community youth and adult support groups, which often involve people with significant trauma which can cause behaviours that seem irrational or silly to casual observers.

The second task was to build a stand for the console. The design has a large panel for a base, made from 12mm plywood. This is large enough that one or both players stand on it during use, preventing tipping. It has a centre post connected to an upper panel which has a low lip to hold the console in place. This can present similar hazards if left unattended, such as someone colliding with it or tripping headlong over it. However, being so much lighter, it can be moved out of the way if other games are taking place nearby. It will not be able to fall onto someone, being shorter. The only potential injury is from someone falling over into it and tipping it in doing so, then landing on it. Careful elimination of sharp corners rendered this no more of a risk than the average chair.


We chose Arduino Uno Wifi boards because there needs to be communication between the console and the panel. The Uno in the panel handles no more than lighting the correct WS2812 LED. It doesn’t exactly work hard. The Uno in the console, however, has to run the game modes and figure out which LED to light. This takes the form of an array, with each LED having its own index that can be accessed when needed. This is used to ‘drop’ the tokens down the columns, as well as to ‘chase’ the LEDs in the Chance Mode. The challenge is that the code in the console has to figure out which of the LEDs on its own WS2812 LED to light, and which array address to send wirelessly to the Uno in the panel, so that it knows which LED to light.

Despite the name WiFi, The Arduino WiFi Uno boards also have Bluetooth Low Energy built-in, which makes communication between multiple boards relatively simple. We have two Unos, one in the console and one in the button panel, acting as a master and slave respectively.

Bluetooth Low Energy can be confusing to begin with, considering it has a number of differences to regular Bluetooth, but it’s really quite a simple and clever protocol. When two devices connect (usually one ‘central’ device and one ‘peripheral’), the central device looks for available ‘services’ on the peripheral device, which is intended to accomplish some purpose or broader functionality. Within these services, there are ‘characteristics’ that are essentially data fields. They can be written to, read from, and even set up to notify the central device when changed. It is possible to use any of the predefined characteristics listed in the Bluetooth LE standard, or you can define your own custom characteristic as we’re doing.


Long story short, we set up our Button Board with one service and two characteristics. Our service is called ‘ButtonBoard’ and contains ‘NeoCharacteristic’ (for the WS2812B NeoPixel LEDs) and ‘ButtonCharacteristic’ (for buttons on the button board).

// set advertised local name and service UUID:
  BLE.setLocalName("Button Board");

Besides some basic initialization within the main setup function, there isn’t a lot the button board does. It’s a master-slave arrangement, and most of the functionality occurs within the control board.

Our NeoCharacteristic takes an unsigned long as data, which is really just 4 bytes in a row. It’s typically interpreted as one number, but in this case, we’re using each byte to represent a single NeoPixel write:

Byte No.Function
1LED Position
2Red Channel
3Green Channel
4Blue Channel

We can parse this NeoPixel data into writing into an actual value like this:

int i = (neoCharacteristic.value() >> 0 ) & 0xFF;
int r = (neoCharacteristic.value() >> 8 ) & 0xFF;
int g = (neoCharacteristic.value() >> 16) & 0xFF;
int b = (neoCharacteristic.value() >> 24) & 0xFF;
Serial.println("Pixel " + (String)i + ": " + (String)r + ", " + (String)g + ", " + (String)b);;

The ‘>>’ and ‘&’ operators are known as bitwise operators because they directly use the bit data of the data. This means that our 4-byte unsigned long can be parsed into four separate bytes, which we use later to write directly to the required NeoPixel light!

The control board is where the magic happens. Like the button board, it has its own Bluetooth Low energy arrangement, but instead of advertising its own characteristics, it reads values from the Button Board. The ButtonCharacteristic, for example, is the system used for figuring out which button was pressed. It’s possible to connect to the button board with a phone to see the ASCII data coming in when a button is pressed. For instance, the first column button sends through a ‘1’, and the reset button sends through a ‘R’. It’s then up to the control board to handle the functionality.


There are two main game modes, with an option on a third that we haven’t coded yet. We will describe it anyway, because we think someone out there will want to write their own code for it and modify the build with the addition of the seven-segment display mentioned.

By default, game mode is Standard, the left-hand player is yellow and the right-hand player is red.


Some features are common to all game modes. There are a set of ‘game mode’ buttons that can be used to switch between the Standard, Timed and Chance game modes. These are all disabled during gameplay, but once a game has been completed a different game mode can be selected. Pressing the Colour-selection button activates player colour selection. First, the left-hand player’s button can be pressed in single short presses to cycle through a bank of preset colours. To choose, the player presses the colour selection button once, at which point the right-hand player’s button can be pressed to choose a colour. Once the Control button is pressed for the right-hand player’s colour selection, selection is complete and locked, and the mode goes back to standby.

The reset button resets the game in progress, not the Arduino. It is needed after a win, because we decided not to use an auto-timeout after a win. Younger kids in particular like to make sure someone else has seen their win.


This is the default mode. Whether using default or chosen colours, the player and column buttons light in the player’s colour. They then press a column-selection button. A token represented by the illuminated LEDs in the panel drops down that chosen column fairly quickly (1.2 seconds to descend all six rows, or pro-rata thereof) to the first available row, just like dropping a physical token in the board game: If there are tokens under it, it sits on top of them.

void updatePlayerPositions() {
  if(lastUpdateTime + updateSpeed > millis()) {
  lastUpdateTime = millis();
  for(int x = 0; x < 7; x++) {
    // Note: Must be done from the 
    // bottom up to avoid 
   // moving players instantly to the bottom.
    for(int y = 0; y < 5; y++) {
      if(pixelGrid[x][y] == 0 && 
pixelGrid[x][y + 1] != 0) {
         //A player is waiting to fall here, 
       //move them down.
         byte player = pixelGrid[x][y+1];
         pixelGrid[x][y+1] = 0;
         pixelGrid[x][y] = player;

This is the code responsible, and it’s a system to move players down towards the bottom of the board. While it looks a bit crazy, most of it is actually dedicated to making sure that no weird behaviour results from moving players around. The first couple of lines are for slowing the token down as it falls, and the next couple of lines is a For loop that iterates over the columns and rows. ‘Moving’ a player down simply consists of setting the next square to their colour, and setting their previous square to empty. Provided that the player 1) hasn’t hit the bottom of the board and 2) hasn’t overwritten another active token, the token continues moving down.

From when a player’s button is pressed, to when the token lands in position, the player button inputs are locked so that an overzealous (or malicious) opponent cannot jump their turn and confuse the system. From here, it’s just a regular game of Connect 4!


In Chance Mode, a player presses their button to start their turn, at which point a light chase begins along the column-selection buttons, and the top row of the main panel at the same time. There are three speeds, with the default being ‘medium’. In this gamemode, each player is offered at the beginning of the game a speed from 1-7, using the column selection buttons. Button 1 would be considered easy, and is lit up green, while Button 7 is lit up red to signify it is much more difficult. All of the buttons in between have got orange, yellow, etc to make it slightly easier or harder. The player must predict when the pixel will arrive at the column they would like to put their token into, and press the relevant column-selection button while that column’s pixel or button is illuminated. This adds an element of chance because you may not react in the correct time.

Medium default speed corresponds to 1.4 seconds to transition the width of the row, the fastest is 0.7 seconds, and the slowest is 2.1 seconds. The idea here is that people can, via agreement, of course, scale the skill for certain players. For example, a late teen or adult playing against an eight-year old is probably unfair if the speed is the same for both.

If the token is ‘dropped’ into a column that is already full, the turn counts but no token is added. Furthermore, there is a time limit of eight chases, either left to right or right to left, before the turn expires. An expired turn is still a turn.

We’ve set up the code for this gamemode so its parameters can be set for any behaviour you would like. Minimum speed, maximum speed, player ‘turn’ parameters can all be modified within the code.


This one is a variation of Standard Mode and is the one we didn’t have time to finish coding because it relies on the seven-segment display for a visual countdown. It involves a time limit on each player’s turn, which we suggest to be ten to fifteen seconds, hence the need for a two-digit display. After play starts and the first turn is selected, the timer starts automatically after each token ‘lands’. Play automatically switches between players, so only column-selection buttons need to be pressed. The first player to press their player button starts the game, so it would be best to decide this via agreement first.


Connect4 is won whenever there are four tokens of the same colour connected continuously, either horizontally, vertically, or diagonally. The line needs to be straight, so bending to connect four tokens is not permitted. The code looks for situations where there are four tokens in a row, but we had to be careful that it did not look for only four tokens: There are situations where a player may have, say, a row of three, a space, and a single token. Dropping their token into the space creates a row of five, still a valid win but not something that code looking for only rows of four would see.

Detecting wins can be slightly difficult because of the larger search space. Each token can be involved with up to 4 different manoeuvres: Vertical, Horizontal, Right Descending Diagonal, Left Descending Diagonal. Since there are 42 tokens slots, this accounts for 168 possible ‘checks’ for every time a token is inserted. There are a number of possible optimisations that are possible for this code, but we opted with the simple route and just checked every row and column for a linear group of like-coloured tokens. Since tokens are represented with numbers (0 = Empty, 1 = Player 1, 2 = Player 2), it’s a matter of ‘walking’ down each possible win direction and seeing whether a colour is continuous for 4 steps. We haven’t included the exact algorithm here since it is quite bulky.


We would love to see someone code the timed version and the SPI-driven seven-segment module to go with it. You could also use an Arduino Mega for extra I/O and memory.

You could also sheet the front of the unit in clear acrylic sheet, for extra mechanical protection.

If you’re adventurous or just confident enough with the language and hardware, this project would probably work well with Raspberry Pi. These would be far more capable of some of the missing features like win detection.

Additionally, the project can scale. If you don’t have any community space where you’re installing it, you can make it smaller, or possibly even bigger! We chose this size because of the intensity of the 3W lights spread out to 300mm being a good visual effect, and the fact that it just fits through the height of a standard doorway. However, a TV-sized one might be more practical for the games or pool room.