Connect 4 with NeoPixel Matrix RGB LED
.
Overview
by Ha Dao and Joseph Doughty
This project implements the popular game Connect 4 on an mbed. Connect 4 is a two-player game where players take turns dropping markers of their respective color into a vertical board until one player has four in a row, column, or diagonal. Think tic-tac-toe, but with a bigger board and needing four to win instead of just three. If you're not familiar with how the game works, you can play a version of it online here.
Along with an mbed, this circuit uses an Adafruit NeoPixel NeoMatrix 8x8 - 64 RGB LED Pixel Matrix, a SparkFun 5-Way Tactile Switch Breakout, and a Wall Adapter Power Supply - 5V DC 2A (Barrel Jack). Take a moment to check out the Cookbook pages for the NeoMatrix and the Tactile Switch before beginning to build the circuit.
After you familiarize yourself with the components, you'll be well on your way to building the game shown in the video below! All you have to do is hook your parts up as directed by the Pin Connections segment, import the Connect_4_with_NeoPixel program into your compiler workspace, and then put it on your mbed!
When your circuit is assembled and your code is on the mbed, then you should be good to go. Hit the Reset button on your mbed to start the game. The game begins with the red player - move the joystick left or right to pick where you want to drop your marker, then center press the joystick to drop it. Next, the blue player gets to do the same. The red player and blue player alternate until a player has won, at which point the game ends and the winning four markers flash. To start a new game, just reset the mbed again!
If you have any questions, please comment on this page or email josahty@gmail.com - I'll be happy to help!
Demonstration Video
Components
- mbed LPC1768
- Adafruit NeoPixel NeoMatrix 8x8 - 64 RGB LED Pixel Matrix
- SparkFun 5-Way Tactile Switch Breakout
- Wall Adapter Power Supply - 5V DC 2A (Barrel Jack)
Information
Note: The 5-Way Tactile Switch is no longer sold by SparkFun. However, there are several similar options available on the website.
Pin Connections
mbed | 5v Power Supply | NeoPixel Matrix |
---|---|---|
GND | GND | |
+5v | +5v | |
pin 18 | DIN |
mbed | Tactile Switch |
---|---|
U - up | |
D - down | |
pin 7 | L - left |
pin 5 | R - right |
pin 8 | C - center |
GND | - |
+ |
Information
Since the up and down capability of the tactile switch is not used in this project, the corresponding pins don't need to be wired to the mbed.
The + pin of the tactile switch doesn't need to be powered since the project is using the mbed's internal pullups.
Code
Import programConnect_4_with_NeoPixel
Connect 4 game using the NeoPixel Matrix 8x8 RGB LED and a 5-way Tactile Navigation Switch.
main.cpp
// ====================================================================== // Program to create a Connect 4 game using a NeoPixel Matrix 8x8 RGB LED // and a 5-way Tactile Navigation Switch. // Ha Dao and Joseph Doughty // April 25, 2018 // Georgia Institute of Technology, ECE4011 Final Project //======================================================================= #include "mbed.h" #include "NeoStrip.h" #include "PinDetect.h" #include "Matrix.h" #define N 64 NeoStrip strip(p18, N); // 8x8 neopixel matrix with each "pixel" LED addressable by its index, which range from 0 to 63 Matrix board(8,7); // the Connect Four game board is a 6x7 matrix, the NeoPixel matrix is 8x8, created an 8x7 matrix to keep track of moves PinDetect right(p5); PinDetect left(p7); PinDetect center(p8); int pos = 0; //c urrent position of LED in Neopixel index int row = 0; int col = 0; int winmode = 0; //0 means the game hasn't yet been won, 1-4 are different ways to win int red = 0xFF0000; // one player is red int blue = 0x0000FF; // other player is blue int color = red; // begin the game with the red player int winningcolor = 0; // clears the LED matrix by turning each one off void alloff() { for (int i = 0; i < N; i++) strip.setPixel(i, 0, 0, 0); strip.write(); } // converts row and column indexes of a matrix to the corresponding index of the NeoPixel int matrix2index(int r, int c) { return (r-1)*8 + c - 1; } // when the game is won, flashes the four LEDs corresponding to the winning move // this will continue until the game is reset via the mbed reset button void display_winner(int mode, int r, int c, int wincolor) { switch (mode) { case 1: while (1) { strip.setPixel(matrix2index(r,c), wincolor); strip.setPixel(matrix2index(r,c+1), wincolor); strip.setPixel(matrix2index(r,c+2), wincolor); strip.setPixel(matrix2index(r,c+3), wincolor); strip.write(); wait(0.2); strip.setPixel(matrix2index(r,c), 0, 0, 0); strip.setPixel(matrix2index(r,c+1), 0, 0, 0); strip.setPixel(matrix2index(r,c+2), 0, 0, 0); strip.setPixel(matrix2index(r,c+3), 0, 0, 0); strip.write(); wait(0.2); } case 2: while (1) { strip.setPixel(matrix2index(r,c), wincolor); strip.setPixel(matrix2index(r+1,c), wincolor); strip.setPixel(matrix2index(r+2,c), wincolor); strip.setPixel(matrix2index(r+3,c), wincolor); strip.write(); wait(0.2); strip.setPixel(matrix2index(r,c), 0, 0, 0); strip.setPixel(matrix2index(r+1,c), 0, 0, 0); strip.setPixel(matrix2index(r+2,c), 0, 0, 0); strip.setPixel(matrix2index(r+3,c), 0, 0, 0); strip.write(); wait(0.2); } case 3: while (1) { strip.setPixel(matrix2index(r,c), wincolor); strip.setPixel(matrix2index(r+1,c+1), wincolor); strip.setPixel(matrix2index(r+2,c+2), wincolor); strip.setPixel(matrix2index(r+3,c+3), wincolor); strip.write(); wait(0.2); strip.setPixel(matrix2index(r,c), 0, 0, 0); strip.setPixel(matrix2index(r+1,c+1), 0, 0, 0); strip.setPixel(matrix2index(r+2,c+2), 0, 0, 0); strip.setPixel(matrix2index(r+3,c+3), 0, 0, 0); strip.write(); wait(0.2); } case 4: while (1) { strip.setPixel(matrix2index(r,c), wincolor); strip.setPixel(matrix2index(r+1,c-1), wincolor); strip.setPixel(matrix2index(r+2,c-2), wincolor); strip.setPixel(matrix2index(r+3,c-3), wincolor); strip.write(); wait(0.2); strip.setPixel(matrix2index(r,c), 0, 0, 0); strip.setPixel(matrix2index(r+1,c-1), 0, 0, 0); strip.setPixel(matrix2index(r+2,c-2), 0, 0, 0); strip.setPixel(matrix2index(r+3,c-3), 0, 0, 0); strip.write(); wait(0.2); } default: break; } } // checks to see if the game has been won; a game is won if either player has // four markers in a row horizontally, diagonally, or vertically void check_winner() { //checks for four markers in a row for (int r = 1; r < 9; r++) { for (int c = 1; c < 6; c++) { if (board.getNumber(r,c) != 0 && board.getNumber(r,c) == board.getNumber(r,c+1) && board.getNumber(r,c+1) == board.getNumber(r,c+2) && board.getNumber(r,c+2) == board.getNumber(r,c+3)) {//have winner row = r; col = c; winmode = 1; winningcolor = color; return; //avoid the uncessary of continue to check } } } //checks for four markers in a column for (int c = 1; c < 9; c++) { for (int r = 1; r < 6; r++) { if (board.getNumber(r,c) != 0 && board.getNumber(r,c) == board.getNumber(r+1,c) && board.getNumber(r+1,c) == board.getNumber(r+2,c) && board.getNumber(r+2,c) == board.getNumber(r+3,c)) {//have winner row = r; col = c; winmode = 2; winningcolor = color; return; } } } //checks for four markers in a forward (right-leaning) diagonal for (int r = 3; r < 6; r++) { for (int c = 1; c < 5; c++) { if (board.getNumber(r,c) != 0 && board.getNumber(r,c) == board.getNumber(r+1,c+1) && board.getNumber(r+1,c+1) == board.getNumber(r+2,c+2) && board.getNumber(r+2,c+2) == board.getNumber(r+3,c+3)) {//have winner row = r; col = c; winmode = 3; winningcolor = color; return; } } } //checks for four markers in a reverse (left-leaning) diagonal for (int r = 3; r < 6; r++) { for (int c = 4; c < 8; c++) { if (board.getNumber(r,c) != 0 && board.getNumber(r,c) == board.getNumber(r+1,c-1) && board.getNumber(r+1,c-1) == board.getNumber(r+2,c-2) && board.getNumber(r+2,c-2) == board.getNumber(r+3,c-3)) {//have winner row = r; col = c; winmode = 4; winningcolor = color; return; } } } } // move the player marker to the right void right_hit_callback (void) { strip.setPixel(pos, 0, 0, 0); // turn off the current LED if (pos < 6) pos = pos + 1; // only move to the right if not at "screen" edge } // move the player marker to the left void left_hit_callback (void) { strip.setPixel(pos, 0, 0, 0); // turn off the current LED if (pos > 0) pos = pos - 1; // only move to the left if not at "screen" edge } // drop the player marker straight down the current column void center_hit_callback (void) { strip.setPixel(pos, 0, 0, 0); // turn off the current LED // show marker at lowest unoccupied position in the selected column col = pos + 1; for(row = 8; row > 1; row-- ) { if (board.getNumber(row,col) == 0) break; // break upon finding lowest unoccupied position } //convert to neopixel index to turn of that neopixel, but only if not all rows in 6x7 board are occupied if (row > 2) strip.setPixel(matrix2index(row,col), color); else return; if (color == red) // if it's red player's turn, { board.add( row, col, 1.0); // update matrix to have a matrix to check winner check_winner(); // check board state to see if the game has been won color = blue; // switch to the blue player } else // else, if it's blue player's turn, { board.add( row, col, 2.0); // update matrix to have a matrix to check winner check_winner(); // check board state to see if the game has been won color = red; // switch to the red player } } int main() { // initialize the matrix to 0 so that all rows and columns are unoccupied board << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // use internal pullups for pushbutton right.mode(PullUp); left.mode(PullUp); center.mode(PullUp); // delay for initial pullup to take effect wait(.05); // setup interrupt callback functions for a pb hit right.attach_deasserted(&right_hit_callback); // used to move player marker left.attach_deasserted(&left_hit_callback); // used to move player marker center.attach_deasserted(¢er_hit_callback); // used to drop player marker // start sampling inputs using interrupts right.setSampleFrequency(); left.setSampleFrequency(); center.setSampleFrequency(); wait(.01); float bright = 0.2; // 20% brightness is plenty for indoor visibility strip.setBrightness(bright); // set default brightness alloff(); // initialize all of the NeoPixel LEDs to be off while(1) { // if the game has been won, display the winning move display_winner(winmode,row,col,winningcolor); // flash the LED corresponding to the currently selected player marker location strip.setPixel(pos, color); strip.write(); wait(0.2); strip.setPixel(pos, 0, 0, 0); strip.write(); wait(0.2); } }
Please log in to post comments.