ECE 4180 Lab 4 - Magic Square game
Overview
Dhru Desai and I made a simple "magic square" game using the 12-key touchpad for input controls and the uLCD as output. The object of the game is to illuminate all nine lights using a combination of button presses. Each button corresponds to one light, and pressing a button toggles its light as well as some of the lights around it. The effects of pressing a corner, side, or middle button are shown in the picture below. The actual button pressed is represented by the red light, while the blue lights represent the other affected spaces.
Implementation
The game begins with all lights off when the mbed is powered up. If the player successfully illuminates all nine lights, a congratulatory message is displayed. After a victory, the board is reset to a random configuration. The player can also reset the board by pressing the '0' key.
The following picture shows the mapping of the keys to the lights.
Components
Connections
mbed | uLCD | Touchpad |
---|---|---|
5V=VU | 5V | |
Gnd | Gnd | |
TX=P28 | RX | |
RX=P27 | TX | |
P29 | Reset | |
P9 | SDA | |
P10 | SCL | |
P26 | IRQ |
Remember to put pull-up resistors to Vout on the SDA and SCL lines
Program
Import programTouchPuzzle_full
4180 Lab 4 v1.0
Code
Touch Puzzle main.cpp
/* Dhruvin Desai and Joseph Sobchuk fallInterrupt() and API for mpr121 written by Anthony Buckton in 2011 */ #include <mbed.h> #include <mpr121.h> // Thanks to Anthony Buckton #include "uLCD_4DGL.h" uLCD_4DGL uLCD(p28,p27,p29); // Create the interrupt receiver object on pin 26 InterruptIn interrupt(p26); // Setup the i2c bus on pins 9 and 10 I2C i2c(p9, p10); // Setup the Mpr121: // constructor(i2c object, i2c address of the mpr121) Mpr121 mpr121(&i2c, Mpr121::ADD_VSS); int on [9] = {0,0,0,0,0,0,0,0,0}; int key; int radius = 15; int initpos = 23; // Initial x and y shift from the edge of the display int shift = 40; // Space in between each circle // Function to invert any specified circle void invert(int on [9], int circleN) { switch (circleN) { case 1: if (on[0] == 0) { // If circle 1 is off then Fill 1st Circle uLCD.filled_circle(initpos, initpos, radius, RED); // Fill 1st Circle on[0] = 1; // Then change status of circle 1 to on } else if (on[0] == 1) { // If circle 1 is on then erase 1st circle uLCD.filled_circle(initpos, initpos, radius, BLACK); uLCD.circle(initpos, initpos, radius, RED); // Erase 1st Circle on[0] = 0; } break; case 2: if (on[1] == 0) { uLCD.filled_circle(initpos + shift, initpos, radius, RED); // Fill 2nd Circle on[1] = 1; } else if (on[1] == 1) { uLCD.filled_circle(initpos + shift, initpos, radius, BLACK); uLCD.circle(initpos + shift, initpos, radius, RED); // Erase 2nd Circle on[1] = 0; } break; case 3: if (on[2] == 0) { uLCD.filled_circle(initpos + 2*shift, initpos, radius, RED); on[2] = 1; } else if (on[2] == 1) { uLCD.filled_circle(initpos + 2*shift, initpos, radius, BLACK); uLCD.circle(initpos + 2*shift, initpos, radius, RED); on[2] = 0; } break; case 4: if (on[3] == 0) { uLCD.filled_circle(initpos, initpos + shift, radius, RED); // Fill 4th Circle on[3] = 1; } else if (on[3] == 1) { uLCD.filled_circle(initpos, initpos + shift, radius, BLACK); uLCD.circle(initpos, initpos + shift, radius, RED); // Erase 4th Circle on[3] = 0; } break; case 5: if (on[4] == 0) { uLCD.filled_circle(initpos + shift, initpos + shift, radius, RED); // Fill 5th Circle on[4] = 1; } else if (on[4] == 1) { uLCD.filled_circle(initpos + shift, initpos + shift, radius, BLACK); uLCD.circle(initpos + shift, initpos + shift, radius, RED); // Erase 5th Circle on[4] = 0; } break; case 6: if (on[5] == 0) { uLCD.filled_circle(initpos + 2*shift, initpos + shift, radius, RED); // Fill 6th Circle on[5] = 1; } else if (on[5] == 1) { uLCD.filled_circle(initpos + 2*shift, initpos + shift, radius, BLACK); uLCD.circle(initpos + 2*shift, initpos + shift, radius, RED); // Erase 6th Circle on[5] = 0; } break; case 7: if (on[6] == 0) { uLCD.filled_circle(initpos, initpos + 2*shift, radius, RED); // Fill 7th Circle on[6] = 1; } else if (on[6] == 1) { uLCD.filled_circle(initpos, initpos + 2*shift, radius, BLACK); // Erase 7th Circle uLCD.circle(initpos, initpos + 2*shift, radius, RED); on[6] = 0; } break; case 8: if (on[7] == 0) { uLCD.filled_circle(initpos + shift, initpos + 2*shift, radius, RED); // Fill 8th Circle on[7] = 1; } else if (on[7] == 1) { uLCD.filled_circle(initpos + shift, initpos + 2*shift, radius, BLACK); // Erase 8th Circle uLCD.circle(initpos + shift, initpos + 2*shift, radius, RED); on[7] = 0; } break; case 9: if (on[8] == 0) { uLCD.filled_circle(initpos + 2*shift, initpos + 2*shift, radius, RED); // Fill 9th Circle on[8] = 1; } else if (on[8] == 1) { uLCD.filled_circle(initpos + 2*shift, initpos + 2*shift, radius, BLACK); uLCD.circle(initpos + 2*shift, initpos + 2*shift, radius, RED); // Erase 9th Circle on[8] = 0; } break; } } void pushButton(int on [9],int key_code) { // The winning combination of buttons is 0,2,4,8 (1,3,5,9 in key_codes) // The rest of the buttons are programmed to give bogus combinations to confuse the player, but one of them might coincidently win the game. switch (key_code) { case 2: invert(on,7); invert(on,4); invert(on,5); invert(on,8); break; case 3: invert(on,7); invert(on,4); invert(on,1); break; case 4: invert(on,2); invert(on,4); invert(on,5); invert(on,1); break; case 6: invert(on,9); invert(on,7); invert(on,8); break; case 7: invert(on,2); invert(on,5); invert(on,4); invert(on,8); invert(on,6); break; case 8: invert(on,1); invert(on,2); invert(on,3); break; case 10: invert(on,8); invert(on,9); invert(on,5); invert(on,6); break; case 11: invert(on,9); invert(on,6); invert(on,3); break; case 12: invert(on,2); invert(on,3); invert(on,6); invert(on,5); break; } } // Key hit/release interrupt routine thanks to Anthony Buckton void fallInterrupt() { int key_code = 0; int i = 0; int value = mpr121.read(0x00); value += mpr121.read(0x01) << 8; // LED demo mod i = 0; // puts key number out to LEDs for demo for (i=0; i<12; i++) { if (((value>>i)&0x01)==1) { key_code=i+1; } } key = key_code; } int main() { int j; uLCD.rectangle(0,0,127,127,WHITE); // Draw border // Draw empty circles in correct positions uLCD.circle(initpos, initpos, radius, RED); uLCD.circle(initpos + shift, initpos, radius, RED); uLCD.circle(initpos + 2*shift, initpos, radius, RED); uLCD.circle(initpos, initpos + shift, radius, RED); uLCD.circle(initpos + shift, initpos + shift, radius, RED); uLCD.circle(initpos + 2*shift, initpos + shift, radius, RED); uLCD.circle(initpos, initpos + 2*shift, radius, RED); uLCD.circle(initpos + shift, initpos + 2*shift, radius, RED); uLCD.circle(initpos + 2*shift, initpos + 2*shift, radius, RED); interrupt.fall(&fallInterrupt); interrupt.mode(PullUp); while (1) { // Call pushButton once button is pressed by passing the key of the button pushed and the status of the circles if(key != 0) { pushButton(on, key); if(key != 1)key = 0; } // If all circles are filled, then print You win!!! Reset the mbed if (key == 1 || (on[0] && on[1] && on[2] && on[3] && on[4] && on[5] && on[6] && on[7] && on[8])) { uLCD.locate(5,5); if(key != 1) uLCD.printf("You Win!!!"); uLCD.locate(0,7); uLCD.printf("Resetting the game"); wait(3); for (j = 0; j < 9; j++) { on[j] = rand() % 2; } uLCD.filled_rectangle(0,0,127,127,BLACK);// Erase Everything uLCD.rectangle(0,0,127,127,WHITE); // Draw border // Draw empty circles in correct positions uLCD.circle(initpos, initpos, radius, RED); uLCD.circle(initpos + shift, initpos, radius, RED); uLCD.circle(initpos + 2*shift, initpos, radius, RED); uLCD.circle(initpos, initpos + shift, radius, RED); uLCD.circle(initpos + shift, initpos + shift, radius, RED); uLCD.circle(initpos + 2*shift, initpos + shift, radius, RED); uLCD.circle(initpos, initpos + 2*shift, radius, RED); uLCD.circle(initpos + shift, initpos + 2*shift, radius, RED); uLCD.circle(initpos + 2*shift, initpos + 2*shift, radius, RED); //Make sure they match the array for(j = 0; j < 9; j++) { invert(on,j); } } //wait(0.2); // Used wait to eliminate multiple presses of button. <- Done somewhere else } }
Demonstration
Please log in to post comments.