From 80373748bf05fde97796359b123ca4a538c864d9 Mon Sep 17 00:00:00 2001 From: Joseph Dodson Date: Tue, 28 Nov 2017 12:54:09 -0700 Subject: [PATCH 1/3] syncing files --- Board.cpp | 279 ------------------------------------------- Board.h | 129 -------------------- I2C.cpp | 25 ---- I2C.h | 111 ----------------- KeypadWrapper.cpp | 110 ----------------- KeypadWrapper.h | 30 ----- MasterController.ino | 193 ------------------------------ SlaveBoard.ino | 82 ------------- 8 files changed, 959 deletions(-) delete mode 100644 Board.cpp delete mode 100644 Board.h delete mode 100644 I2C.cpp delete mode 100644 I2C.h delete mode 100644 KeypadWrapper.cpp delete mode 100644 KeypadWrapper.h delete mode 100644 MasterController.ino delete mode 100644 SlaveBoard.ino diff --git a/Board.cpp b/Board.cpp deleted file mode 100644 index cea63fc..0000000 --- a/Board.cpp +++ /dev/null @@ -1,279 +0,0 @@ -#include "Board.h" - -void Board::bin(unsigned long n) { - unsigned long k; - for (int i = 31; i >= 0; --i) { - k = (unsigned long) 1 << i; - if (k & n) { - Serial.print("1"); - } - else { - Serial.print("0"); - } - } - Serial.println(); -} - -void Board::solve() { - Serial.println("Solution: "); - bool TEMP[RC] = {false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false - }; - mvm(R, GAME_BOARD, TEMP); - for (byte i = ZERO; i < RC; ++i) { - if (TEMP[i]) { - toggle(i); - Serial.println(i); - printSerial(); - } - } -} - -/* Call reset before */ -void Board::randomize() { - unsigned long minMoves = random(5, 25); - unsigned long randomBits = nrand25(minMoves); - unsigned long k; - bool TEMP[RC] = {false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false - }; - for (unsigned long i = 0; i < 25; ++i) { - k = 1 << i; - if (k & randomBits) { - TEMP[(byte) i] = true; - } - } - mvm(A, TEMP); -} - -/* - void Board::randomize(int difficulty) { - unsigned long minMoves = 0; - if (difficulty == 1) { - minMoves = random(5, 11); - } - else if (difficulty == 2) { - minMoves = random(10, 16); - } - else if (difficulty == 3) { - minMoves = random(15, 21); - } - else if (difficulty == 4) { - minMoves = random(20, 25); - } - else { - minMoves = random(5, 25); - } - Serial.print("Min Moves: "); - Serial.println(minMoves, DEC); - unsigned long randomBits = nrand25(minMoves); - Serial.print("Random Bits Integer: "); - Serial.println(randomBits, DEC); - Serial.print("Binary: "); - bin(randomBits); - Serial.print("Binary: "); - Serial.println(randomBits, BIN); - - unsigned long k; - - bool TEMP[RC] = {false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false - }; - for (unsigned long i = 0; i < 25; ++i) { - k = 1 << i; - if (k & randomBits) { - TEMP[(byte) i] = true; - } - } - mvm(A, TEMP); - }*/ - -/* Excludes n, so call with n + 1. */ -int Board::randto(int n) { - int r = random(0, n); - return r; -} - -void Board::shuffle(int *x, int n) { - for (int i = 0; i < n; ++i) { - int j = randto(25); - int tmp = x[i]; - x[i] = x[j]; - x[j] = tmp; - } -} - -/* Produces a "random" 25 bit integer with n bits set to 1. */ -unsigned long Board::nrand25(int n) { - unsigned long v = 0; - int pos[25] = {0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24 - }; - shuffle(pos, 25); - for (int i = 0; i < n; ++i) { - unsigned long k = 1; - v |= (k << pos[i]); - } - return v; -} - -/* All lights off. */ -void Board::reset() { - for (byte row = 0; row < RC; ++row) { - GAME_BOARD[row] = false; - } -} - -bool Board::isWin() { - for (byte row = 0; row < RC; ++row) { - if (GAME_BOARD[row]) { - return false; - } - } - return true; -} - -/* Corresponds to XOR. - +|0|1| - 0|0|1| - 1|1|0| -*/ -bool Board::add(bool p1, bool p2) { - - if (p1 && !p2 || !p1 && p2) { - return true; - } - else { - return false; - } -} - -/* Corresponds to AND. - x|0|1| - 0|0|0| - 1|0|1| -*/ -bool Board::multiply(bool p1, bool p2) { - if (p1 && p2) { - return true; - } - else { - return false; - } -} - -/* Matrix Vector Multiply */ -void Board::mvm(const bool(&mat)[RC][RC], bool(&vec)[RC]) { - for (byte i = 0; i < RC; ++i) { - GAME_BOARD[i] = dot(mat[i], vec); - } -} - -/* Matrix Vector Multiply */ -void Board::mvm(const bool(&mat)[RC][RC], bool(&vec)[RC], bool(&result)[RC]) { - for (byte i = 0; i < RC; ++i) { - result[i] = dot(mat[i], vec); - } -} - -/* 25x1 Vector Dot Product */ -bool Board::dot(const bool(&v1)[RC], bool(&v2)[RC]) { - bool temp[RC] = {false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false - }; - bool result = true; - for (byte i = 0; i < RC; ++i) { - temp[i] = multiply(v1[i], v2[i]); - } - for (byte i = 0; i < RC; ++i) { - if (i == 0) { - result = temp[0]; - } else { - result = add(result, temp[i]); - } - } - return result; -} - - -/* True if board is solvable, false if not. */ -bool Board::isSolvable() { - bool s1 = false; - bool s2 = false; - - s1 = dot(SOLVABLE1, GAME_BOARD); - s2 = dot(SOLVABLE2, GAME_BOARD); - - if (!s1 && !s2) { - return true; - } - else { - return false; - } -} - -/* Sets 0-indexed grid number to true/false without toggling adjacent squares */ -void Board::set(byte gridNum, bool state) { - GAME_BOARD[gridNum] = state; -} - -/* Toggles 0-indexed square and adjacent squares. */ -void Board::toggle(byte gridNum) { - /* Error checking for valid range? */ - /* Toggle the square itself. */ - GAME_BOARD[gridNum] = !GAME_BOARD[gridNum]; - - /* North Adjacent only when row > 4 */ - if (gridNum > FOUR) { - GAME_BOARD[gridNum - FIVE] = !GAME_BOARD[gridNum - FIVE]; - } - - /* South adjacent only when row < 20 */ - if (gridNum < TWENTY) { - GAME_BOARD[gridNum + FIVE] = !GAME_BOARD[gridNum + FIVE]; - } - - /* East adjacent only when row MOD 5 != 4 */ - if (gridNum % FIVE != FOUR) { - GAME_BOARD[gridNum + ONE] = !GAME_BOARD[gridNum + ONE]; - } - - /* West adjacent only when row MOD 5 != 0 */ - if (gridNum % FIVE != ZERO) { - GAME_BOARD[gridNum - ONE] = !GAME_BOARD[gridNum - ONE]; - } -} - -void Board::printSerial() { - for (byte i = 0; i < RC; ++i) { - if (GAME_BOARD[i]) { - Serial.print("| ON"); - } - else { - Serial.print("|OFF"); - } - if (i % FIVE == 4) { - Serial.println("|"); - } - } - Serial.println(); -} - - - - - - diff --git a/Board.h b/Board.h deleted file mode 100644 index 128dc04..0000000 --- a/Board.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - FALSE = OFF 0 - TRUE = ON 1 - - | 0| 1| 2| 3| 4| - | 5| 6| 7| 8| 9| - |10|11|12|13|14| - |15|16|17|18|19| - |20|21|22|23|24| - -*/ -#ifndef BOARD_LIGHTSOUT_H -#define BOARD_LIGHTSOUT_H - -#include "Arduino.h" - -class Board { - public: - static const byte FIVE = 5; - static const byte FOUR = 4; - static const byte ZERO = 0; - static const byte TWENTY = 20; - static const byte ONE = 1; - static const byte RC = 25; - - void randomize(); - int randto(int); - void shuffle(int *, int); - unsigned long nrand25(int); - - void set(byte, bool); /* Sets 0-indexed grid number to true/false without toggling adjacent squares */ - void toggle(byte); /* Toggle by 0-indexed grid number */ - bool isWin(); - bool isSolvable(); - void reset(); - void solve(); - - bool add(bool, bool); - bool multiply(bool, bool); - void mvm(const bool(&)[RC][RC], bool(&)[RC]); - void mvm(const bool(&)[RC][RC], bool(&)[RC], bool(&)[RC]); - bool dot(const bool(&)[RC], bool(&)[RC]); - - void printSerial(); - void bin(unsigned long); - - bool GAME_BOARD[RC] = {false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false - }; - - /* If board is orthogonal to these, then it is solvable. */ - const bool SOLVABLE1[RC] = {false, true, true, true, false, - true, false, true, false, true, - true, true, false, true, true, - true, false, true, false, true, - false, true, true, true, false - }; - - const bool SOLVABLE2[RC] = {true, false, true, false, true, - true, false, true, false, true, - false, false, false, false, false, - true, false, true, false, true, - true, false, true, false, true - }; - - const bool A[RC][RC] = {{true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, - {true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, - {false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, - {false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, - {false, false, false, true, true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, - {true, false, false, false, false, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, - {false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false}, - {false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false}, - {false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false}, - {false, false, false, false, true, false, false, false, true, true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false}, - {false, false, false, false, false, true, false, false, false, false, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false}, - {false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false}, - {false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false}, - {false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false}, - {false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, false, false, false, false, true, false, false, false, false, false}, - {false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, true, true, false, false, false, true, false, false, false, false}, - {false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false}, - {false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, false, false, false, false, true}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, true, true, false, false, false}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true} - }; - /* Product of the elementary matrices that make up the row operations for Gaussian elimination. */ - const bool R[RC][RC] = {{false, false, false, false, false, true, false, false, false, false, true, true, false, false, false, true, false, true, false, false, false, true, true, true, false}, - {false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, false, false, true, false, true, true, false, true, true}, - {false, false, false, true, false, false, false, false, true, true, false, false, true, true, false, false, true, false, true, false, true, true, true, false, true}, - {false, false, true, true, true, false, true, false, false, false, true, true, false, true, true, false, true, false, false, false, false, false, true, true, true}, - {false, false, false, true, true, false, false, true, false, true, false, true, true, true, false, true, false, false, false, false, true, false, true, true, false}, - {false, false, true, false, true, false, true, true, false, true, false, false, true, false, false, false, false, false, true, true, false, false, false, false, false}, - {false, false, true, false, false, false, true, true, true, false, true, true, false, false, true, false, true, false, false, true, false, false, true, true, false}, - {false, false, false, false, true, false, false, false, true, true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, true}, - {false, false, true, false, false, false, true, true, true, false, true, false, false, true, true, true, false, false, true, false, false, true, true, false, false}, - {false, false, true, false, true, false, true, true, false, true, true, false, true, false, true, true, true, false, false, false, true, false, false, false, true}, - {false, false, false, false, true, false, false, false, true, true, false, false, true, false, true, true, true, true, true, false, false, true, false, false, false}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false}, - {false, false, false, true, true, false, false, true, false, false, false, true, true, false, true, true, false, false, false, true, true, false, true, true, false}, - {false, false, true, true, true, false, true, false, true, false, true, true, true, false, false, false, false, false, true, false, true, true, false, true, true}, - {false, false, false, true, false, false, false, true, true, true, false, true, false, false, false, true, true, false, true, false, false, true, false, true, true}, - {false, false, true, false, false, false, true, true, true, false, true, false, false, false, true, true, false, true, false, true, true, false, true, false, false}, - {false, false, true, true, false, false, true, false, false, true, true, true, false, false, true, false, true, true, true, false, false, false, true, false, false}, - {false, false, true, false, true, false, true, true, false, true, true, false, true, false, false, true, true, false, true, true, true, false, false, false, false}, - {false, false, false, true, false, false, false, true, true, true, false, true, false, false, false, true, true, false, true, true, false, true, false, true, false}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true}, - {false, false, false, true, true, false, false, true, false, false, false, true, true, false, true, true, false, true, false, true, true, true, false, false, false}, - {false, false, true, true, true, false, true, false, true, false, true, true, true, false, false, false, false, false, false, false, true, true, true, false, false}, - {false, false, false, true, false, false, false, true, true, true, false, true, false, false, false, true, true, false, true, true, false, true, false, false, false}, - {true, false, true, false, true, true, false, true, false, true, false, false, false, false, false, true, false, true, false, true, true, false, true, false, true}, - {false, true, true, true, false, true, false, true, false, true, true, true, false, true, true, true, false, true, false, true, false, true, true, true, false} - }; -}; -#endif - - - - - - diff --git a/I2C.cpp b/I2C.cpp deleted file mode 100644 index e21f963..0000000 --- a/I2C.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "I2C.h" - -void I2C_Slave::init(void(*callback)()){ - Wire.begin(SLAVE_ADDR); - Wire.onReceive(callback); /* Register callback */ -} - -int I2C_Slave::available() { - return Wire.available(); -} - -EVENT I2C_Slave::read() { - return (EVENT) Wire.read(); -} - -void I2C_Master::init(){ - Wire.begin(); -} - -void I2C_Master::write(EVENT e) { - Wire.beginTransmission(SLAVE_ADDR); - Wire.write(e); - Wire.endTransmission(); -} - diff --git a/I2C.h b/I2C.h deleted file mode 100644 index fdf4873..0000000 --- a/I2C.h +++ /dev/null @@ -1,111 +0,0 @@ - -#ifndef I2C_COMM_H -#define I2C_COMM_H - -#include "Wire.h" -#include "Arduino.h" - - -/* - LEDs & Switches refer to same square on grid. - - | 1| 2| 3| 4| 5| - | 6| 7| 8| 9|10| - |11|12|13|14|15| - |16|17|18|19|20| - |21|22|23|24|25| -*/ - - -enum EVENT : byte { - /* THE EVENTS LISTED HERE MAP THE ENTIRE BYTE */ - - /* TOGGLE EVENTS */ - /* UPPER 3 BITS ARE 001 */ - /* DECIMAL RANGE 33 - 57 */ - TOGGLE0 = 33, - TOGGLE1 = 34, - TOGGLE2 = 35, - TOGGLE3 = 36, - TOGGLE4 = 37, - TOGGLE5 = 38, - TOGGLE6 = 39, - TOGGLE7 = 40, - TOGGLE8 = 41, - TOGGLE9 = 42, - TOGGLE10 = 43, - TOGGLE11 = 44, - TOGGLE12 = 45, - TOGGLE13 = 46, - TOGGLE14 = 47, - TOGGLE15 = 48, - TOGGLE16 = 49, - TOGGLE17 = 50, - TOGGLE18 = 51, - TOGGLE19 = 52, - TOGGLE20 = 53, - TOGGLE21 = 54, - TOGGLE22 = 55, - TOGGLE23 = 56, - TOGGLE24 = 57, - - /* We use these for game reset. Implies board is all false, so we are setting to true. */ - /* Do not toggle neighbors. */ - SET0 = 58, - SET1 = 59, - SET2 = 60, - SET3 = 61, - SET4 = 62, - SET5 = 63, - SET6 = 64, - SET7 = 65, - SET8 = 66, - SET9 = 67, - SET10 = 68, - SET11 = 69, - SET12 = 70, - SET13 = 71, - SET14 = 72, - SET15 = 73, - SET16 = 74, - SET17 = 75, - SET18 = 76, - SET19 = 77, - SET20 = 78, - SET21 = 79, - SET22 = 80, - SET23 = 81, - SET24 = 82, - /* GAME WON */ - WIN = 96, - - /* RESET/NEW GAME */ - RESET = 160, - - /* TRANSMISSION FINISH */ - FIN = 170, - - /* MASTER ERROR */ - M_ERROR = 224 -}; - - -class I2C_Slave { - public: - const byte SLAVE_ADDR = 27; - - void init(void(*callback)()); - int available(); - EVENT read(); -}; - -class I2C_Master { - public: - const byte SLAVE_ADDR = 27; - void init(); - void write(EVENT); - -}; - -#endif - diff --git a/KeypadWrapper.cpp b/KeypadWrapper.cpp deleted file mode 100644 index dd7bde2..0000000 --- a/KeypadWrapper.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "KeypadWrapper.h" - -KeypadWrapper::KeypadWrapper() { - kpd = Keypad(makeKeymap(KEY_MAP), ROW_PINS, COL_PINS, 5, 5); - kpd.setDebounceTime(100); -} - -KeypadWrapper::KeypadWrapper(byte *rpins, byte *cpins) { - for (byte i = 0; i < 5; ++i) { - ROW_PINS[i] = rpins[i]; - COL_PINS[i] = cpins[i]; - } - kpd = Keypad(makeKeymap(KEY_MAP), ROW_PINS, COL_PINS, 5, 5); - kpd.setDebounceTime(100); -} - -int KeypadWrapper::pollKeypad() { - if (kpd.getKeys()) { - int count = 0; - for (int i = 0; i < LIST_MAX; i++) { - if (kpd.key[i].kstate == HOLD) { - ++count; - if (count == 4) { - return -1; - } - } - else if (kpd.key[i].kstate == PRESSED) { - if (kpd.key[i].kchar == 'a') { - return 0; - } - else if (kpd.key[i].kchar == 'b') { - return 1; - } - else if (kpd.key[i].kchar == 'c') { - return 2; - } - else if (kpd.key[i].kchar == 'd') { - return 3; - } - else if (kpd.key[i].kchar == 'e') { - return 4; - } - else if (kpd.key[i].kchar == 'f') { - return 5; - } - else if (kpd.key[i].kchar == 'g') { - return 6; - } - else if (kpd.key[i].kchar == 'h') { - return 7; - } - else if (kpd.key[i].kchar == 'i') { - return 8; - } - else if (kpd.key[i].kchar == 'j') { - return 9; - } - else if (kpd.key[i].kchar == 'k') { - return 10; - } - else if (kpd.key[i].kchar == 'l') { - return 11; - } - else if (kpd.key[i].kchar == 'm') { - return 12; - } - else if (kpd.key[i].kchar == 'n') { - return 13; - } - else if (kpd.key[i].kchar == 'o') { - return 14; - } - else if (kpd.key[i].kchar == 'p') { - return 15; - } - else if (kpd.key[i].kchar == 'q') { - return 16; - } - else if (kpd.key[i].kchar == 'r') { - return 17; - } - else if (kpd.key[i].kchar == 's') { - return 18; - } - else if (kpd.key[i].kchar == 't') { - return 19; - } - else if (kpd.key[i].kchar == 'u') { - return 20; - } - else if (kpd.key[i].kchar == 'v') { - return 21; - } - else if (kpd.key[i].kchar == 'w') { - return 22; - } - else if (kpd.key[i].kchar == 'x') { - return 23; - } - else if (kpd.key[i].kchar == 'y') { - return 24; - } - } - } - } - else { - return 128; - } -} - diff --git a/KeypadWrapper.h b/KeypadWrapper.h deleted file mode 100644 index d7d402b..0000000 --- a/KeypadWrapper.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - Pushing and holding any four buttons at the same time will trigger a new game. -*/ - -#ifndef KEYPADWRAPPER_H -#define KEYPADWRAPPER_H - -#include "Keypad.h" - -class KeypadWrapper { - public: - KeypadWrapper(); - KeypadWrapper(byte *, byte *); - int pollKeypad(); - - private: - byte ROW_PINS[5] = {2, 3, 4, 5, 6}; - byte COL_PINS[5] = {7, 8, 9, 10, 11}; - char KEY_MAP [5][5] = {{'a', 'b', 'c', 'd', 'e'}, - {'f', 'g', 'h', 'i', 'j'}, - {'k', 'l', 'm', 'n', 'o'}, - {'p', 'q', 'r', 's', 't'}, - {'u', 'v', 'w', 'x', 'y'} - }; - Keypad &kpd; -}; - - -#endif - diff --git a/MasterController.ino b/MasterController.ino deleted file mode 100644 index e84cfcd..0000000 --- a/MasterController.ino +++ /dev/null @@ -1,193 +0,0 @@ -#include "I2C.h" -#include "Board.h" -#include "KeypadWrapper.h" - -bool inGame; -I2C_Master mcomm; -Board board; -KeypadWrapper kpdw; - -void gameReset() { - mcomm.write(RESET); - inGame = true; - board.reset(); - board.randomize(); - for (byte i = board.ZERO; i < board.RC; ++i) { - if (board.GAME_BOARD[i]) { - if (i == 0) { - mcomm.write(SET0); - } - else if (i == 1) { - mcomm.write(SET1); - } - else if (i == 2) { - mcomm.write(SET2); - } - else if (i == 3) { - mcomm.write(SET3); - } - else if (i == 4) { - mcomm.write(SET4); - } - else if (i == 5) { - mcomm.write(SET5); - } - else if (i == 6) { - mcomm.write(SET6); - } - else if (i == 7) { - mcomm.write(SET7); - } - else if (i == 8) { - mcomm.write(SET8); - } - else if (i == 9) { - mcomm.write(SET9); - } - else if (i == 10) { - mcomm.write(SET10); - } - else if (i == 11) { - mcomm.write(SET11); - } - else if (i == 12) { - mcomm.write(SET12); - } - else if (i == 13) { - mcomm.write(SET13); - } - else if (i == 14) { - mcomm.write(SET14); - } - else if (i == 15) { - mcomm.write(SET15); - } - else if (i == 16) { - mcomm.write(SET16); - } - else if (i == 17) { - mcomm.write(SET17); - } - else if (i == 18) { - mcomm.write(SET18); - } - else if (i == 19) { - mcomm.write(SET19); - } - else if (i == 20) { - mcomm.write(SET20); - } - else if (i == 21) { - mcomm.write(SET21); - } - else if (i == 22) { - mcomm.write(SET22); - } - else if (i == 23) { - mcomm.write(SET23); - } - else if (i == 24) { - mcomm.write(SET24); - } - } - } - mcomm.write(FIN); -} - -void setup() { - mcomm.init(); - inGame = false; -} - -void loop() { - int keyEvent = kpdw.pollKeypad(); - if (keyEvent == 128) {} - else if (keyEvent == -1) { - gameReset(); - } - else if (keyEvent >= 0 && keyEvent <= 24) { - if (keyEvent == 0) { - mcomm.write(TOGGLE0); - } - else if (keyEvent == 1) { - mcomm.write(TOGGLE1); - } - else if (keyEvent == 2) { - mcomm.write(TOGGLE2); - } - else if (keyEvent == 3) { - mcomm.write(TOGGLE3); - } - else if (keyEvent == 4) { - mcomm.write(TOGGLE4); - } - else if (keyEvent == 5) { - mcomm.write(TOGGLE5); - } - else if (keyEvent == 6) { - mcomm.write(TOGGLE6); - } - else if (keyEvent == 7) { - mcomm.write(TOGGLE7); - } - else if (keyEvent == 8) { - mcomm.write(TOGGLE8); - } - else if (keyEvent == 9) { - mcomm.write(TOGGLE9); - } - else if (keyEvent == 10) { - mcomm.write(TOGGLE10); - } - else if (keyEvent == 11) { - mcomm.write(TOGGLE11); - } - else if (keyEvent == 12) { - mcomm.write(TOGGLE12); - } - else if (keyEvent == 13) { - mcomm.write(TOGGLE13); - } - else if (keyEvent == 14) { - mcomm.write(TOGGLE14); - } - else if (keyEvent == 15) { - mcomm.write(TOGGLE15); - } - else if (keyEvent == 16) { - mcomm.write(TOGGLE16); - } - else if (keyEvent == 17) { - mcomm.write(TOGGLE17); - } - else if (keyEvent == 18) { - mcomm.write(TOGGLE18); - } - else if (keyEvent == 19) { - mcomm.write(TOGGLE19); - } - else if (keyEvent == 20) { - mcomm.write(TOGGLE20); - } - else if (keyEvent == 21) { - mcomm.write(TOGGLE21); - } - else if (keyEvent == 22) { - mcomm.write(TOGGLE22); - } - else if (keyEvent == 23) { - mcomm.write(TOGGLE23); - } - else if (keyEvent == 24) { - mcomm.write(TOGGLE24); - } - mcomm.write(FIN); - if (board.isWin()) { - mcomm.write(WIN); - inGame = false; - mcomm.write(FIN); - } - } - -} - diff --git a/SlaveBoard.ino b/SlaveBoard.ino deleted file mode 100644 index 6df9c27..0000000 --- a/SlaveBoard.ino +++ /dev/null @@ -1,82 +0,0 @@ -#include "I2C.h" -#include "LiquidCrystal_I2C.h" - -#define ON true -#define OFF false - -const int rowpin[] = {2,3,4,5,6}; //pins used for rows -const int colpin[] = {7,8,9,10,11}; //pins used for columns - -const uint8_t m_size = 5; - -//corresponds to current state of LEDs in matrix, 1 = on -bool state[m_size*m_size]; - -uint8_t cur_row = 0; - -I2C_Slave slave; -LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); - -void eventhandle(); - -void setup() { - for(int i = 0; i < m_size; ++i){ - pinMode(rowpin[i], OUTPUT); - pinMode(colpin[i], OUTPUT); - digitalWrite(rowpin[i], LOW); - digitalWrite(colpin[i], LOW); - } - for(int i = 0; i < m_size*m_size; ++i) state[i] = OFF; - lcd.begin(16,2); - slave.init(eventhandle); -} - -void loop() { - //turn off the other two rows - digitalWrite(rowpin[(cur_row+1)%m_size], LOW); - digitalWrite(rowpin[(cur_row+2)%m_size], LOW); - - //column = LOW lets current pass, HIGH blocks current - for(int col = 0; col < m_size; ++col) digitalWrite(colpin[col], !(state[(cur_row)*m_size+col])); - digitalWrite(rowpin[cur_row], HIGH); //set the current row to HIGH to light up the LEDs - cur_row = (cur_row+1)%m_size; //move to the next row -} - -void eventhandle(){ - EVENT event = slave.read(); - if(event >= 33 && event <= 57){ //toggle - uint8_t row = (event - TOGGLE0)/m_size; - uint8_t col = (event - TOGGLE0)%m_size; - uint8_t index = event - TOGGLE0; - - //toggle provided LED - state[index] = !state[index]; - - //toggle adjacent LEDs if applicable - if(row > 0) state[index-m_size] = !state[index-m_size]; - if(row < m_size-1) state[index+m_size] = !state[index+m_size]; - if(col > 0) state[index-1] = !state[index-1]; - if(col < m_size-1) state[index+1] = !state[index+1]; - } - else if(event >= 58 && event <= 82){ //set - state[event-SET0] = ON; - } - else{ - lcd.clear(); - switch(event){ - case WIN: - lcd.write("You win"); - break; - case RESET: - lcd.write("Resetting"); - for(byte i = 0; i < 25; ++i) state[i] = OFF; - break; - case M_ERROR: - lcd.write("Error"); - for(byte i = 0; i < 25; ++i) state[i] = OFF; - break; - default: lcd.write("Unexpected Error"); - } - } -} - From c3f5784da3f9a9f2114f6aa56438e16e01d73346 Mon Sep 17 00:00:00 2001 From: Joseph Dodson Date: Tue, 28 Nov 2017 12:56:11 -0700 Subject: [PATCH 2/3] syncing --- Board.cpp | 279 +++++++++++++++++++++++++++++++++++++++++++ Board.h | 129 ++++++++++++++++++++ I2C.cpp | 25 ++++ I2C.h | 111 +++++++++++++++++ KeypadWrapper.cpp | 110 +++++++++++++++++ KeypadWrapper.h | 30 +++++ MasterController.ino | 193 ++++++++++++++++++++++++++++++ SlaveBoard.ino | 82 +++++++++++++ 8 files changed, 959 insertions(+) create mode 100644 Board.cpp create mode 100644 Board.h create mode 100644 I2C.cpp create mode 100644 I2C.h create mode 100644 KeypadWrapper.cpp create mode 100644 KeypadWrapper.h create mode 100644 MasterController.ino create mode 100644 SlaveBoard.ino diff --git a/Board.cpp b/Board.cpp new file mode 100644 index 0000000..cea63fc --- /dev/null +++ b/Board.cpp @@ -0,0 +1,279 @@ +#include "Board.h" + +void Board::bin(unsigned long n) { + unsigned long k; + for (int i = 31; i >= 0; --i) { + k = (unsigned long) 1 << i; + if (k & n) { + Serial.print("1"); + } + else { + Serial.print("0"); + } + } + Serial.println(); +} + +void Board::solve() { + Serial.println("Solution: "); + bool TEMP[RC] = {false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false + }; + mvm(R, GAME_BOARD, TEMP); + for (byte i = ZERO; i < RC; ++i) { + if (TEMP[i]) { + toggle(i); + Serial.println(i); + printSerial(); + } + } +} + +/* Call reset before */ +void Board::randomize() { + unsigned long minMoves = random(5, 25); + unsigned long randomBits = nrand25(minMoves); + unsigned long k; + bool TEMP[RC] = {false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false + }; + for (unsigned long i = 0; i < 25; ++i) { + k = 1 << i; + if (k & randomBits) { + TEMP[(byte) i] = true; + } + } + mvm(A, TEMP); +} + +/* + void Board::randomize(int difficulty) { + unsigned long minMoves = 0; + if (difficulty == 1) { + minMoves = random(5, 11); + } + else if (difficulty == 2) { + minMoves = random(10, 16); + } + else if (difficulty == 3) { + minMoves = random(15, 21); + } + else if (difficulty == 4) { + minMoves = random(20, 25); + } + else { + minMoves = random(5, 25); + } + Serial.print("Min Moves: "); + Serial.println(minMoves, DEC); + unsigned long randomBits = nrand25(minMoves); + Serial.print("Random Bits Integer: "); + Serial.println(randomBits, DEC); + Serial.print("Binary: "); + bin(randomBits); + Serial.print("Binary: "); + Serial.println(randomBits, BIN); + + unsigned long k; + + bool TEMP[RC] = {false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false + }; + for (unsigned long i = 0; i < 25; ++i) { + k = 1 << i; + if (k & randomBits) { + TEMP[(byte) i] = true; + } + } + mvm(A, TEMP); + }*/ + +/* Excludes n, so call with n + 1. */ +int Board::randto(int n) { + int r = random(0, n); + return r; +} + +void Board::shuffle(int *x, int n) { + for (int i = 0; i < n; ++i) { + int j = randto(25); + int tmp = x[i]; + x[i] = x[j]; + x[j] = tmp; + } +} + +/* Produces a "random" 25 bit integer with n bits set to 1. */ +unsigned long Board::nrand25(int n) { + unsigned long v = 0; + int pos[25] = {0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24 + }; + shuffle(pos, 25); + for (int i = 0; i < n; ++i) { + unsigned long k = 1; + v |= (k << pos[i]); + } + return v; +} + +/* All lights off. */ +void Board::reset() { + for (byte row = 0; row < RC; ++row) { + GAME_BOARD[row] = false; + } +} + +bool Board::isWin() { + for (byte row = 0; row < RC; ++row) { + if (GAME_BOARD[row]) { + return false; + } + } + return true; +} + +/* Corresponds to XOR. + +|0|1| + 0|0|1| + 1|1|0| +*/ +bool Board::add(bool p1, bool p2) { + + if (p1 && !p2 || !p1 && p2) { + return true; + } + else { + return false; + } +} + +/* Corresponds to AND. + x|0|1| + 0|0|0| + 1|0|1| +*/ +bool Board::multiply(bool p1, bool p2) { + if (p1 && p2) { + return true; + } + else { + return false; + } +} + +/* Matrix Vector Multiply */ +void Board::mvm(const bool(&mat)[RC][RC], bool(&vec)[RC]) { + for (byte i = 0; i < RC; ++i) { + GAME_BOARD[i] = dot(mat[i], vec); + } +} + +/* Matrix Vector Multiply */ +void Board::mvm(const bool(&mat)[RC][RC], bool(&vec)[RC], bool(&result)[RC]) { + for (byte i = 0; i < RC; ++i) { + result[i] = dot(mat[i], vec); + } +} + +/* 25x1 Vector Dot Product */ +bool Board::dot(const bool(&v1)[RC], bool(&v2)[RC]) { + bool temp[RC] = {false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false + }; + bool result = true; + for (byte i = 0; i < RC; ++i) { + temp[i] = multiply(v1[i], v2[i]); + } + for (byte i = 0; i < RC; ++i) { + if (i == 0) { + result = temp[0]; + } else { + result = add(result, temp[i]); + } + } + return result; +} + + +/* True if board is solvable, false if not. */ +bool Board::isSolvable() { + bool s1 = false; + bool s2 = false; + + s1 = dot(SOLVABLE1, GAME_BOARD); + s2 = dot(SOLVABLE2, GAME_BOARD); + + if (!s1 && !s2) { + return true; + } + else { + return false; + } +} + +/* Sets 0-indexed grid number to true/false without toggling adjacent squares */ +void Board::set(byte gridNum, bool state) { + GAME_BOARD[gridNum] = state; +} + +/* Toggles 0-indexed square and adjacent squares. */ +void Board::toggle(byte gridNum) { + /* Error checking for valid range? */ + /* Toggle the square itself. */ + GAME_BOARD[gridNum] = !GAME_BOARD[gridNum]; + + /* North Adjacent only when row > 4 */ + if (gridNum > FOUR) { + GAME_BOARD[gridNum - FIVE] = !GAME_BOARD[gridNum - FIVE]; + } + + /* South adjacent only when row < 20 */ + if (gridNum < TWENTY) { + GAME_BOARD[gridNum + FIVE] = !GAME_BOARD[gridNum + FIVE]; + } + + /* East adjacent only when row MOD 5 != 4 */ + if (gridNum % FIVE != FOUR) { + GAME_BOARD[gridNum + ONE] = !GAME_BOARD[gridNum + ONE]; + } + + /* West adjacent only when row MOD 5 != 0 */ + if (gridNum % FIVE != ZERO) { + GAME_BOARD[gridNum - ONE] = !GAME_BOARD[gridNum - ONE]; + } +} + +void Board::printSerial() { + for (byte i = 0; i < RC; ++i) { + if (GAME_BOARD[i]) { + Serial.print("| ON"); + } + else { + Serial.print("|OFF"); + } + if (i % FIVE == 4) { + Serial.println("|"); + } + } + Serial.println(); +} + + + + + + diff --git a/Board.h b/Board.h new file mode 100644 index 0000000..128dc04 --- /dev/null +++ b/Board.h @@ -0,0 +1,129 @@ +/* + FALSE = OFF 0 + TRUE = ON 1 + + | 0| 1| 2| 3| 4| + | 5| 6| 7| 8| 9| + |10|11|12|13|14| + |15|16|17|18|19| + |20|21|22|23|24| + +*/ +#ifndef BOARD_LIGHTSOUT_H +#define BOARD_LIGHTSOUT_H + +#include "Arduino.h" + +class Board { + public: + static const byte FIVE = 5; + static const byte FOUR = 4; + static const byte ZERO = 0; + static const byte TWENTY = 20; + static const byte ONE = 1; + static const byte RC = 25; + + void randomize(); + int randto(int); + void shuffle(int *, int); + unsigned long nrand25(int); + + void set(byte, bool); /* Sets 0-indexed grid number to true/false without toggling adjacent squares */ + void toggle(byte); /* Toggle by 0-indexed grid number */ + bool isWin(); + bool isSolvable(); + void reset(); + void solve(); + + bool add(bool, bool); + bool multiply(bool, bool); + void mvm(const bool(&)[RC][RC], bool(&)[RC]); + void mvm(const bool(&)[RC][RC], bool(&)[RC], bool(&)[RC]); + bool dot(const bool(&)[RC], bool(&)[RC]); + + void printSerial(); + void bin(unsigned long); + + bool GAME_BOARD[RC] = {false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false + }; + + /* If board is orthogonal to these, then it is solvable. */ + const bool SOLVABLE1[RC] = {false, true, true, true, false, + true, false, true, false, true, + true, true, false, true, true, + true, false, true, false, true, + false, true, true, true, false + }; + + const bool SOLVABLE2[RC] = {true, false, true, false, true, + true, false, true, false, true, + false, false, false, false, false, + true, false, true, false, true, + true, false, true, false, true + }; + + const bool A[RC][RC] = {{true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, true, true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {true, false, false, false, false, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, true, false, false, false, true, true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, false, true, false, false, false, false, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false}, + {false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, false, false, false, false, true, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, true, true, false, false, false, true, false, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, false, false, false, false, true}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, true, true, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true} + }; + /* Product of the elementary matrices that make up the row operations for Gaussian elimination. */ + const bool R[RC][RC] = {{false, false, false, false, false, true, false, false, false, false, true, true, false, false, false, true, false, true, false, false, false, true, true, true, false}, + {false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, false, false, true, false, true, true, false, true, true}, + {false, false, false, true, false, false, false, false, true, true, false, false, true, true, false, false, true, false, true, false, true, true, true, false, true}, + {false, false, true, true, true, false, true, false, false, false, true, true, false, true, true, false, true, false, false, false, false, false, true, true, true}, + {false, false, false, true, true, false, false, true, false, true, false, true, true, true, false, true, false, false, false, false, true, false, true, true, false}, + {false, false, true, false, true, false, true, true, false, true, false, false, true, false, false, false, false, false, true, true, false, false, false, false, false}, + {false, false, true, false, false, false, true, true, true, false, true, true, false, false, true, false, true, false, false, true, false, false, true, true, false}, + {false, false, false, false, true, false, false, false, true, true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, true}, + {false, false, true, false, false, false, true, true, true, false, true, false, false, true, true, true, false, false, true, false, false, true, true, false, false}, + {false, false, true, false, true, false, true, true, false, true, true, false, true, false, true, true, true, false, false, false, true, false, false, false, true}, + {false, false, false, false, true, false, false, false, true, true, false, false, true, false, true, true, true, true, true, false, false, true, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false}, + {false, false, false, true, true, false, false, true, false, false, false, true, true, false, true, true, false, false, false, true, true, false, true, true, false}, + {false, false, true, true, true, false, true, false, true, false, true, true, true, false, false, false, false, false, true, false, true, true, false, true, true}, + {false, false, false, true, false, false, false, true, true, true, false, true, false, false, false, true, true, false, true, false, false, true, false, true, true}, + {false, false, true, false, false, false, true, true, true, false, true, false, false, false, true, true, false, true, false, true, true, false, true, false, false}, + {false, false, true, true, false, false, true, false, false, true, true, true, false, false, true, false, true, true, true, false, false, false, true, false, false}, + {false, false, true, false, true, false, true, true, false, true, true, false, true, false, false, true, true, false, true, true, true, false, false, false, false}, + {false, false, false, true, false, false, false, true, true, true, false, true, false, false, false, true, true, false, true, true, false, true, false, true, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true}, + {false, false, false, true, true, false, false, true, false, false, false, true, true, false, true, true, false, true, false, true, true, true, false, false, false}, + {false, false, true, true, true, false, true, false, true, false, true, true, true, false, false, false, false, false, false, false, true, true, true, false, false}, + {false, false, false, true, false, false, false, true, true, true, false, true, false, false, false, true, true, false, true, true, false, true, false, false, false}, + {true, false, true, false, true, true, false, true, false, true, false, false, false, false, false, true, false, true, false, true, true, false, true, false, true}, + {false, true, true, true, false, true, false, true, false, true, true, true, false, true, true, true, false, true, false, true, false, true, true, true, false} + }; +}; +#endif + + + + + + diff --git a/I2C.cpp b/I2C.cpp new file mode 100644 index 0000000..e21f963 --- /dev/null +++ b/I2C.cpp @@ -0,0 +1,25 @@ +#include "I2C.h" + +void I2C_Slave::init(void(*callback)()){ + Wire.begin(SLAVE_ADDR); + Wire.onReceive(callback); /* Register callback */ +} + +int I2C_Slave::available() { + return Wire.available(); +} + +EVENT I2C_Slave::read() { + return (EVENT) Wire.read(); +} + +void I2C_Master::init(){ + Wire.begin(); +} + +void I2C_Master::write(EVENT e) { + Wire.beginTransmission(SLAVE_ADDR); + Wire.write(e); + Wire.endTransmission(); +} + diff --git a/I2C.h b/I2C.h new file mode 100644 index 0000000..fdf4873 --- /dev/null +++ b/I2C.h @@ -0,0 +1,111 @@ + +#ifndef I2C_COMM_H +#define I2C_COMM_H + +#include "Wire.h" +#include "Arduino.h" + + +/* + LEDs & Switches refer to same square on grid. + + | 1| 2| 3| 4| 5| + | 6| 7| 8| 9|10| + |11|12|13|14|15| + |16|17|18|19|20| + |21|22|23|24|25| +*/ + + +enum EVENT : byte { + /* THE EVENTS LISTED HERE MAP THE ENTIRE BYTE */ + + /* TOGGLE EVENTS */ + /* UPPER 3 BITS ARE 001 */ + /* DECIMAL RANGE 33 - 57 */ + TOGGLE0 = 33, + TOGGLE1 = 34, + TOGGLE2 = 35, + TOGGLE3 = 36, + TOGGLE4 = 37, + TOGGLE5 = 38, + TOGGLE6 = 39, + TOGGLE7 = 40, + TOGGLE8 = 41, + TOGGLE9 = 42, + TOGGLE10 = 43, + TOGGLE11 = 44, + TOGGLE12 = 45, + TOGGLE13 = 46, + TOGGLE14 = 47, + TOGGLE15 = 48, + TOGGLE16 = 49, + TOGGLE17 = 50, + TOGGLE18 = 51, + TOGGLE19 = 52, + TOGGLE20 = 53, + TOGGLE21 = 54, + TOGGLE22 = 55, + TOGGLE23 = 56, + TOGGLE24 = 57, + + /* We use these for game reset. Implies board is all false, so we are setting to true. */ + /* Do not toggle neighbors. */ + SET0 = 58, + SET1 = 59, + SET2 = 60, + SET3 = 61, + SET4 = 62, + SET5 = 63, + SET6 = 64, + SET7 = 65, + SET8 = 66, + SET9 = 67, + SET10 = 68, + SET11 = 69, + SET12 = 70, + SET13 = 71, + SET14 = 72, + SET15 = 73, + SET16 = 74, + SET17 = 75, + SET18 = 76, + SET19 = 77, + SET20 = 78, + SET21 = 79, + SET22 = 80, + SET23 = 81, + SET24 = 82, + /* GAME WON */ + WIN = 96, + + /* RESET/NEW GAME */ + RESET = 160, + + /* TRANSMISSION FINISH */ + FIN = 170, + + /* MASTER ERROR */ + M_ERROR = 224 +}; + + +class I2C_Slave { + public: + const byte SLAVE_ADDR = 27; + + void init(void(*callback)()); + int available(); + EVENT read(); +}; + +class I2C_Master { + public: + const byte SLAVE_ADDR = 27; + void init(); + void write(EVENT); + +}; + +#endif + diff --git a/KeypadWrapper.cpp b/KeypadWrapper.cpp new file mode 100644 index 0000000..dd7bde2 --- /dev/null +++ b/KeypadWrapper.cpp @@ -0,0 +1,110 @@ +#include "KeypadWrapper.h" + +KeypadWrapper::KeypadWrapper() { + kpd = Keypad(makeKeymap(KEY_MAP), ROW_PINS, COL_PINS, 5, 5); + kpd.setDebounceTime(100); +} + +KeypadWrapper::KeypadWrapper(byte *rpins, byte *cpins) { + for (byte i = 0; i < 5; ++i) { + ROW_PINS[i] = rpins[i]; + COL_PINS[i] = cpins[i]; + } + kpd = Keypad(makeKeymap(KEY_MAP), ROW_PINS, COL_PINS, 5, 5); + kpd.setDebounceTime(100); +} + +int KeypadWrapper::pollKeypad() { + if (kpd.getKeys()) { + int count = 0; + for (int i = 0; i < LIST_MAX; i++) { + if (kpd.key[i].kstate == HOLD) { + ++count; + if (count == 4) { + return -1; + } + } + else if (kpd.key[i].kstate == PRESSED) { + if (kpd.key[i].kchar == 'a') { + return 0; + } + else if (kpd.key[i].kchar == 'b') { + return 1; + } + else if (kpd.key[i].kchar == 'c') { + return 2; + } + else if (kpd.key[i].kchar == 'd') { + return 3; + } + else if (kpd.key[i].kchar == 'e') { + return 4; + } + else if (kpd.key[i].kchar == 'f') { + return 5; + } + else if (kpd.key[i].kchar == 'g') { + return 6; + } + else if (kpd.key[i].kchar == 'h') { + return 7; + } + else if (kpd.key[i].kchar == 'i') { + return 8; + } + else if (kpd.key[i].kchar == 'j') { + return 9; + } + else if (kpd.key[i].kchar == 'k') { + return 10; + } + else if (kpd.key[i].kchar == 'l') { + return 11; + } + else if (kpd.key[i].kchar == 'm') { + return 12; + } + else if (kpd.key[i].kchar == 'n') { + return 13; + } + else if (kpd.key[i].kchar == 'o') { + return 14; + } + else if (kpd.key[i].kchar == 'p') { + return 15; + } + else if (kpd.key[i].kchar == 'q') { + return 16; + } + else if (kpd.key[i].kchar == 'r') { + return 17; + } + else if (kpd.key[i].kchar == 's') { + return 18; + } + else if (kpd.key[i].kchar == 't') { + return 19; + } + else if (kpd.key[i].kchar == 'u') { + return 20; + } + else if (kpd.key[i].kchar == 'v') { + return 21; + } + else if (kpd.key[i].kchar == 'w') { + return 22; + } + else if (kpd.key[i].kchar == 'x') { + return 23; + } + else if (kpd.key[i].kchar == 'y') { + return 24; + } + } + } + } + else { + return 128; + } +} + diff --git a/KeypadWrapper.h b/KeypadWrapper.h new file mode 100644 index 0000000..d7d402b --- /dev/null +++ b/KeypadWrapper.h @@ -0,0 +1,30 @@ +/* + Pushing and holding any four buttons at the same time will trigger a new game. +*/ + +#ifndef KEYPADWRAPPER_H +#define KEYPADWRAPPER_H + +#include "Keypad.h" + +class KeypadWrapper { + public: + KeypadWrapper(); + KeypadWrapper(byte *, byte *); + int pollKeypad(); + + private: + byte ROW_PINS[5] = {2, 3, 4, 5, 6}; + byte COL_PINS[5] = {7, 8, 9, 10, 11}; + char KEY_MAP [5][5] = {{'a', 'b', 'c', 'd', 'e'}, + {'f', 'g', 'h', 'i', 'j'}, + {'k', 'l', 'm', 'n', 'o'}, + {'p', 'q', 'r', 's', 't'}, + {'u', 'v', 'w', 'x', 'y'} + }; + Keypad &kpd; +}; + + +#endif + diff --git a/MasterController.ino b/MasterController.ino new file mode 100644 index 0000000..e84cfcd --- /dev/null +++ b/MasterController.ino @@ -0,0 +1,193 @@ +#include "I2C.h" +#include "Board.h" +#include "KeypadWrapper.h" + +bool inGame; +I2C_Master mcomm; +Board board; +KeypadWrapper kpdw; + +void gameReset() { + mcomm.write(RESET); + inGame = true; + board.reset(); + board.randomize(); + for (byte i = board.ZERO; i < board.RC; ++i) { + if (board.GAME_BOARD[i]) { + if (i == 0) { + mcomm.write(SET0); + } + else if (i == 1) { + mcomm.write(SET1); + } + else if (i == 2) { + mcomm.write(SET2); + } + else if (i == 3) { + mcomm.write(SET3); + } + else if (i == 4) { + mcomm.write(SET4); + } + else if (i == 5) { + mcomm.write(SET5); + } + else if (i == 6) { + mcomm.write(SET6); + } + else if (i == 7) { + mcomm.write(SET7); + } + else if (i == 8) { + mcomm.write(SET8); + } + else if (i == 9) { + mcomm.write(SET9); + } + else if (i == 10) { + mcomm.write(SET10); + } + else if (i == 11) { + mcomm.write(SET11); + } + else if (i == 12) { + mcomm.write(SET12); + } + else if (i == 13) { + mcomm.write(SET13); + } + else if (i == 14) { + mcomm.write(SET14); + } + else if (i == 15) { + mcomm.write(SET15); + } + else if (i == 16) { + mcomm.write(SET16); + } + else if (i == 17) { + mcomm.write(SET17); + } + else if (i == 18) { + mcomm.write(SET18); + } + else if (i == 19) { + mcomm.write(SET19); + } + else if (i == 20) { + mcomm.write(SET20); + } + else if (i == 21) { + mcomm.write(SET21); + } + else if (i == 22) { + mcomm.write(SET22); + } + else if (i == 23) { + mcomm.write(SET23); + } + else if (i == 24) { + mcomm.write(SET24); + } + } + } + mcomm.write(FIN); +} + +void setup() { + mcomm.init(); + inGame = false; +} + +void loop() { + int keyEvent = kpdw.pollKeypad(); + if (keyEvent == 128) {} + else if (keyEvent == -1) { + gameReset(); + } + else if (keyEvent >= 0 && keyEvent <= 24) { + if (keyEvent == 0) { + mcomm.write(TOGGLE0); + } + else if (keyEvent == 1) { + mcomm.write(TOGGLE1); + } + else if (keyEvent == 2) { + mcomm.write(TOGGLE2); + } + else if (keyEvent == 3) { + mcomm.write(TOGGLE3); + } + else if (keyEvent == 4) { + mcomm.write(TOGGLE4); + } + else if (keyEvent == 5) { + mcomm.write(TOGGLE5); + } + else if (keyEvent == 6) { + mcomm.write(TOGGLE6); + } + else if (keyEvent == 7) { + mcomm.write(TOGGLE7); + } + else if (keyEvent == 8) { + mcomm.write(TOGGLE8); + } + else if (keyEvent == 9) { + mcomm.write(TOGGLE9); + } + else if (keyEvent == 10) { + mcomm.write(TOGGLE10); + } + else if (keyEvent == 11) { + mcomm.write(TOGGLE11); + } + else if (keyEvent == 12) { + mcomm.write(TOGGLE12); + } + else if (keyEvent == 13) { + mcomm.write(TOGGLE13); + } + else if (keyEvent == 14) { + mcomm.write(TOGGLE14); + } + else if (keyEvent == 15) { + mcomm.write(TOGGLE15); + } + else if (keyEvent == 16) { + mcomm.write(TOGGLE16); + } + else if (keyEvent == 17) { + mcomm.write(TOGGLE17); + } + else if (keyEvent == 18) { + mcomm.write(TOGGLE18); + } + else if (keyEvent == 19) { + mcomm.write(TOGGLE19); + } + else if (keyEvent == 20) { + mcomm.write(TOGGLE20); + } + else if (keyEvent == 21) { + mcomm.write(TOGGLE21); + } + else if (keyEvent == 22) { + mcomm.write(TOGGLE22); + } + else if (keyEvent == 23) { + mcomm.write(TOGGLE23); + } + else if (keyEvent == 24) { + mcomm.write(TOGGLE24); + } + mcomm.write(FIN); + if (board.isWin()) { + mcomm.write(WIN); + inGame = false; + mcomm.write(FIN); + } + } + +} + diff --git a/SlaveBoard.ino b/SlaveBoard.ino new file mode 100644 index 0000000..6df9c27 --- /dev/null +++ b/SlaveBoard.ino @@ -0,0 +1,82 @@ +#include "I2C.h" +#include "LiquidCrystal_I2C.h" + +#define ON true +#define OFF false + +const int rowpin[] = {2,3,4,5,6}; //pins used for rows +const int colpin[] = {7,8,9,10,11}; //pins used for columns + +const uint8_t m_size = 5; + +//corresponds to current state of LEDs in matrix, 1 = on +bool state[m_size*m_size]; + +uint8_t cur_row = 0; + +I2C_Slave slave; +LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); + +void eventhandle(); + +void setup() { + for(int i = 0; i < m_size; ++i){ + pinMode(rowpin[i], OUTPUT); + pinMode(colpin[i], OUTPUT); + digitalWrite(rowpin[i], LOW); + digitalWrite(colpin[i], LOW); + } + for(int i = 0; i < m_size*m_size; ++i) state[i] = OFF; + lcd.begin(16,2); + slave.init(eventhandle); +} + +void loop() { + //turn off the other two rows + digitalWrite(rowpin[(cur_row+1)%m_size], LOW); + digitalWrite(rowpin[(cur_row+2)%m_size], LOW); + + //column = LOW lets current pass, HIGH blocks current + for(int col = 0; col < m_size; ++col) digitalWrite(colpin[col], !(state[(cur_row)*m_size+col])); + digitalWrite(rowpin[cur_row], HIGH); //set the current row to HIGH to light up the LEDs + cur_row = (cur_row+1)%m_size; //move to the next row +} + +void eventhandle(){ + EVENT event = slave.read(); + if(event >= 33 && event <= 57){ //toggle + uint8_t row = (event - TOGGLE0)/m_size; + uint8_t col = (event - TOGGLE0)%m_size; + uint8_t index = event - TOGGLE0; + + //toggle provided LED + state[index] = !state[index]; + + //toggle adjacent LEDs if applicable + if(row > 0) state[index-m_size] = !state[index-m_size]; + if(row < m_size-1) state[index+m_size] = !state[index+m_size]; + if(col > 0) state[index-1] = !state[index-1]; + if(col < m_size-1) state[index+1] = !state[index+1]; + } + else if(event >= 58 && event <= 82){ //set + state[event-SET0] = ON; + } + else{ + lcd.clear(); + switch(event){ + case WIN: + lcd.write("You win"); + break; + case RESET: + lcd.write("Resetting"); + for(byte i = 0; i < 25; ++i) state[i] = OFF; + break; + case M_ERROR: + lcd.write("Error"); + for(byte i = 0; i < 25; ++i) state[i] = OFF; + break; + default: lcd.write("Unexpected Error"); + } + } +} + From b7850efff68cf3e7620faf75e7b966a101621ed8 Mon Sep 17 00:00:00 2001 From: Joseph Dodson Date: Sun, 3 Dec 2017 21:59:47 -0700 Subject: [PATCH 3/3] final integration --- Board.cpp | 279 --------------- Board.h | 129 ------- KeypadWrapper.cpp | 110 ------ KeypadWrapper.h | 30 -- MasterController.ino | 193 ---------- MasterController/Board.cpp | 368 ++++++++++++++++++++ MasterController/Board.h | 71 ++++ I2C.cpp => MasterController/I2C.cpp | 0 I2C.h => MasterController/I2C.h | 0 MasterController/KeypadWrapper.cpp | 30 ++ MasterController/KeypadWrapper.h | 30 ++ MasterController/MasterController.ino | 119 +++++++ MasterController/globals.h | 1 + SlaveBoard/I2C.cpp | 25 ++ SlaveBoard/I2C.h | 111 ++++++ SlaveBoard.ino => SlaveBoard/SlaveBoard.ino | 21 +- 16 files changed, 765 insertions(+), 752 deletions(-) delete mode 100644 Board.cpp delete mode 100644 Board.h delete mode 100644 KeypadWrapper.cpp delete mode 100644 KeypadWrapper.h delete mode 100644 MasterController.ino create mode 100644 MasterController/Board.cpp create mode 100644 MasterController/Board.h rename I2C.cpp => MasterController/I2C.cpp (100%) rename I2C.h => MasterController/I2C.h (100%) create mode 100644 MasterController/KeypadWrapper.cpp create mode 100644 MasterController/KeypadWrapper.h create mode 100644 MasterController/MasterController.ino create mode 100644 MasterController/globals.h create mode 100644 SlaveBoard/I2C.cpp create mode 100644 SlaveBoard/I2C.h rename SlaveBoard.ino => SlaveBoard/SlaveBoard.ino (82%) diff --git a/Board.cpp b/Board.cpp deleted file mode 100644 index cea63fc..0000000 --- a/Board.cpp +++ /dev/null @@ -1,279 +0,0 @@ -#include "Board.h" - -void Board::bin(unsigned long n) { - unsigned long k; - for (int i = 31; i >= 0; --i) { - k = (unsigned long) 1 << i; - if (k & n) { - Serial.print("1"); - } - else { - Serial.print("0"); - } - } - Serial.println(); -} - -void Board::solve() { - Serial.println("Solution: "); - bool TEMP[RC] = {false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false - }; - mvm(R, GAME_BOARD, TEMP); - for (byte i = ZERO; i < RC; ++i) { - if (TEMP[i]) { - toggle(i); - Serial.println(i); - printSerial(); - } - } -} - -/* Call reset before */ -void Board::randomize() { - unsigned long minMoves = random(5, 25); - unsigned long randomBits = nrand25(minMoves); - unsigned long k; - bool TEMP[RC] = {false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false - }; - for (unsigned long i = 0; i < 25; ++i) { - k = 1 << i; - if (k & randomBits) { - TEMP[(byte) i] = true; - } - } - mvm(A, TEMP); -} - -/* - void Board::randomize(int difficulty) { - unsigned long minMoves = 0; - if (difficulty == 1) { - minMoves = random(5, 11); - } - else if (difficulty == 2) { - minMoves = random(10, 16); - } - else if (difficulty == 3) { - minMoves = random(15, 21); - } - else if (difficulty == 4) { - minMoves = random(20, 25); - } - else { - minMoves = random(5, 25); - } - Serial.print("Min Moves: "); - Serial.println(minMoves, DEC); - unsigned long randomBits = nrand25(minMoves); - Serial.print("Random Bits Integer: "); - Serial.println(randomBits, DEC); - Serial.print("Binary: "); - bin(randomBits); - Serial.print("Binary: "); - Serial.println(randomBits, BIN); - - unsigned long k; - - bool TEMP[RC] = {false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false - }; - for (unsigned long i = 0; i < 25; ++i) { - k = 1 << i; - if (k & randomBits) { - TEMP[(byte) i] = true; - } - } - mvm(A, TEMP); - }*/ - -/* Excludes n, so call with n + 1. */ -int Board::randto(int n) { - int r = random(0, n); - return r; -} - -void Board::shuffle(int *x, int n) { - for (int i = 0; i < n; ++i) { - int j = randto(25); - int tmp = x[i]; - x[i] = x[j]; - x[j] = tmp; - } -} - -/* Produces a "random" 25 bit integer with n bits set to 1. */ -unsigned long Board::nrand25(int n) { - unsigned long v = 0; - int pos[25] = {0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24 - }; - shuffle(pos, 25); - for (int i = 0; i < n; ++i) { - unsigned long k = 1; - v |= (k << pos[i]); - } - return v; -} - -/* All lights off. */ -void Board::reset() { - for (byte row = 0; row < RC; ++row) { - GAME_BOARD[row] = false; - } -} - -bool Board::isWin() { - for (byte row = 0; row < RC; ++row) { - if (GAME_BOARD[row]) { - return false; - } - } - return true; -} - -/* Corresponds to XOR. - +|0|1| - 0|0|1| - 1|1|0| -*/ -bool Board::add(bool p1, bool p2) { - - if (p1 && !p2 || !p1 && p2) { - return true; - } - else { - return false; - } -} - -/* Corresponds to AND. - x|0|1| - 0|0|0| - 1|0|1| -*/ -bool Board::multiply(bool p1, bool p2) { - if (p1 && p2) { - return true; - } - else { - return false; - } -} - -/* Matrix Vector Multiply */ -void Board::mvm(const bool(&mat)[RC][RC], bool(&vec)[RC]) { - for (byte i = 0; i < RC; ++i) { - GAME_BOARD[i] = dot(mat[i], vec); - } -} - -/* Matrix Vector Multiply */ -void Board::mvm(const bool(&mat)[RC][RC], bool(&vec)[RC], bool(&result)[RC]) { - for (byte i = 0; i < RC; ++i) { - result[i] = dot(mat[i], vec); - } -} - -/* 25x1 Vector Dot Product */ -bool Board::dot(const bool(&v1)[RC], bool(&v2)[RC]) { - bool temp[RC] = {false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false - }; - bool result = true; - for (byte i = 0; i < RC; ++i) { - temp[i] = multiply(v1[i], v2[i]); - } - for (byte i = 0; i < RC; ++i) { - if (i == 0) { - result = temp[0]; - } else { - result = add(result, temp[i]); - } - } - return result; -} - - -/* True if board is solvable, false if not. */ -bool Board::isSolvable() { - bool s1 = false; - bool s2 = false; - - s1 = dot(SOLVABLE1, GAME_BOARD); - s2 = dot(SOLVABLE2, GAME_BOARD); - - if (!s1 && !s2) { - return true; - } - else { - return false; - } -} - -/* Sets 0-indexed grid number to true/false without toggling adjacent squares */ -void Board::set(byte gridNum, bool state) { - GAME_BOARD[gridNum] = state; -} - -/* Toggles 0-indexed square and adjacent squares. */ -void Board::toggle(byte gridNum) { - /* Error checking for valid range? */ - /* Toggle the square itself. */ - GAME_BOARD[gridNum] = !GAME_BOARD[gridNum]; - - /* North Adjacent only when row > 4 */ - if (gridNum > FOUR) { - GAME_BOARD[gridNum - FIVE] = !GAME_BOARD[gridNum - FIVE]; - } - - /* South adjacent only when row < 20 */ - if (gridNum < TWENTY) { - GAME_BOARD[gridNum + FIVE] = !GAME_BOARD[gridNum + FIVE]; - } - - /* East adjacent only when row MOD 5 != 4 */ - if (gridNum % FIVE != FOUR) { - GAME_BOARD[gridNum + ONE] = !GAME_BOARD[gridNum + ONE]; - } - - /* West adjacent only when row MOD 5 != 0 */ - if (gridNum % FIVE != ZERO) { - GAME_BOARD[gridNum - ONE] = !GAME_BOARD[gridNum - ONE]; - } -} - -void Board::printSerial() { - for (byte i = 0; i < RC; ++i) { - if (GAME_BOARD[i]) { - Serial.print("| ON"); - } - else { - Serial.print("|OFF"); - } - if (i % FIVE == 4) { - Serial.println("|"); - } - } - Serial.println(); -} - - - - - - diff --git a/Board.h b/Board.h deleted file mode 100644 index 128dc04..0000000 --- a/Board.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - FALSE = OFF 0 - TRUE = ON 1 - - | 0| 1| 2| 3| 4| - | 5| 6| 7| 8| 9| - |10|11|12|13|14| - |15|16|17|18|19| - |20|21|22|23|24| - -*/ -#ifndef BOARD_LIGHTSOUT_H -#define BOARD_LIGHTSOUT_H - -#include "Arduino.h" - -class Board { - public: - static const byte FIVE = 5; - static const byte FOUR = 4; - static const byte ZERO = 0; - static const byte TWENTY = 20; - static const byte ONE = 1; - static const byte RC = 25; - - void randomize(); - int randto(int); - void shuffle(int *, int); - unsigned long nrand25(int); - - void set(byte, bool); /* Sets 0-indexed grid number to true/false without toggling adjacent squares */ - void toggle(byte); /* Toggle by 0-indexed grid number */ - bool isWin(); - bool isSolvable(); - void reset(); - void solve(); - - bool add(bool, bool); - bool multiply(bool, bool); - void mvm(const bool(&)[RC][RC], bool(&)[RC]); - void mvm(const bool(&)[RC][RC], bool(&)[RC], bool(&)[RC]); - bool dot(const bool(&)[RC], bool(&)[RC]); - - void printSerial(); - void bin(unsigned long); - - bool GAME_BOARD[RC] = {false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false, - false, false, false, false, false - }; - - /* If board is orthogonal to these, then it is solvable. */ - const bool SOLVABLE1[RC] = {false, true, true, true, false, - true, false, true, false, true, - true, true, false, true, true, - true, false, true, false, true, - false, true, true, true, false - }; - - const bool SOLVABLE2[RC] = {true, false, true, false, true, - true, false, true, false, true, - false, false, false, false, false, - true, false, true, false, true, - true, false, true, false, true - }; - - const bool A[RC][RC] = {{true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, - {true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, - {false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, - {false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, - {false, false, false, true, true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, - {true, false, false, false, false, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, - {false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false}, - {false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false}, - {false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false}, - {false, false, false, false, true, false, false, false, true, true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false}, - {false, false, false, false, false, true, false, false, false, false, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false}, - {false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false}, - {false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false}, - {false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false}, - {false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, false, false, false, false, true, false, false, false, false, false}, - {false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, true, true, false, false, false, true, false, false, false, false}, - {false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false}, - {false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, false, false, false, false, true}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, true, true, false, false, false}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true} - }; - /* Product of the elementary matrices that make up the row operations for Gaussian elimination. */ - const bool R[RC][RC] = {{false, false, false, false, false, true, false, false, false, false, true, true, false, false, false, true, false, true, false, false, false, true, true, true, false}, - {false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, false, false, true, false, true, true, false, true, true}, - {false, false, false, true, false, false, false, false, true, true, false, false, true, true, false, false, true, false, true, false, true, true, true, false, true}, - {false, false, true, true, true, false, true, false, false, false, true, true, false, true, true, false, true, false, false, false, false, false, true, true, true}, - {false, false, false, true, true, false, false, true, false, true, false, true, true, true, false, true, false, false, false, false, true, false, true, true, false}, - {false, false, true, false, true, false, true, true, false, true, false, false, true, false, false, false, false, false, true, true, false, false, false, false, false}, - {false, false, true, false, false, false, true, true, true, false, true, true, false, false, true, false, true, false, false, true, false, false, true, true, false}, - {false, false, false, false, true, false, false, false, true, true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, true}, - {false, false, true, false, false, false, true, true, true, false, true, false, false, true, true, true, false, false, true, false, false, true, true, false, false}, - {false, false, true, false, true, false, true, true, false, true, true, false, true, false, true, true, true, false, false, false, true, false, false, false, true}, - {false, false, false, false, true, false, false, false, true, true, false, false, true, false, true, true, true, true, true, false, false, true, false, false, false}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false}, - {false, false, false, true, true, false, false, true, false, false, false, true, true, false, true, true, false, false, false, true, true, false, true, true, false}, - {false, false, true, true, true, false, true, false, true, false, true, true, true, false, false, false, false, false, true, false, true, true, false, true, true}, - {false, false, false, true, false, false, false, true, true, true, false, true, false, false, false, true, true, false, true, false, false, true, false, true, true}, - {false, false, true, false, false, false, true, true, true, false, true, false, false, false, true, true, false, true, false, true, true, false, true, false, false}, - {false, false, true, true, false, false, true, false, false, true, true, true, false, false, true, false, true, true, true, false, false, false, true, false, false}, - {false, false, true, false, true, false, true, true, false, true, true, false, true, false, false, true, true, false, true, true, true, false, false, false, false}, - {false, false, false, true, false, false, false, true, true, true, false, true, false, false, false, true, true, false, true, true, false, true, false, true, false}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true}, - {false, false, false, true, true, false, false, true, false, false, false, true, true, false, true, true, false, true, false, true, true, true, false, false, false}, - {false, false, true, true, true, false, true, false, true, false, true, true, true, false, false, false, false, false, false, false, true, true, true, false, false}, - {false, false, false, true, false, false, false, true, true, true, false, true, false, false, false, true, true, false, true, true, false, true, false, false, false}, - {true, false, true, false, true, true, false, true, false, true, false, false, false, false, false, true, false, true, false, true, true, false, true, false, true}, - {false, true, true, true, false, true, false, true, false, true, true, true, false, true, true, true, false, true, false, true, false, true, true, true, false} - }; -}; -#endif - - - - - - diff --git a/KeypadWrapper.cpp b/KeypadWrapper.cpp deleted file mode 100644 index dd7bde2..0000000 --- a/KeypadWrapper.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "KeypadWrapper.h" - -KeypadWrapper::KeypadWrapper() { - kpd = Keypad(makeKeymap(KEY_MAP), ROW_PINS, COL_PINS, 5, 5); - kpd.setDebounceTime(100); -} - -KeypadWrapper::KeypadWrapper(byte *rpins, byte *cpins) { - for (byte i = 0; i < 5; ++i) { - ROW_PINS[i] = rpins[i]; - COL_PINS[i] = cpins[i]; - } - kpd = Keypad(makeKeymap(KEY_MAP), ROW_PINS, COL_PINS, 5, 5); - kpd.setDebounceTime(100); -} - -int KeypadWrapper::pollKeypad() { - if (kpd.getKeys()) { - int count = 0; - for (int i = 0; i < LIST_MAX; i++) { - if (kpd.key[i].kstate == HOLD) { - ++count; - if (count == 4) { - return -1; - } - } - else if (kpd.key[i].kstate == PRESSED) { - if (kpd.key[i].kchar == 'a') { - return 0; - } - else if (kpd.key[i].kchar == 'b') { - return 1; - } - else if (kpd.key[i].kchar == 'c') { - return 2; - } - else if (kpd.key[i].kchar == 'd') { - return 3; - } - else if (kpd.key[i].kchar == 'e') { - return 4; - } - else if (kpd.key[i].kchar == 'f') { - return 5; - } - else if (kpd.key[i].kchar == 'g') { - return 6; - } - else if (kpd.key[i].kchar == 'h') { - return 7; - } - else if (kpd.key[i].kchar == 'i') { - return 8; - } - else if (kpd.key[i].kchar == 'j') { - return 9; - } - else if (kpd.key[i].kchar == 'k') { - return 10; - } - else if (kpd.key[i].kchar == 'l') { - return 11; - } - else if (kpd.key[i].kchar == 'm') { - return 12; - } - else if (kpd.key[i].kchar == 'n') { - return 13; - } - else if (kpd.key[i].kchar == 'o') { - return 14; - } - else if (kpd.key[i].kchar == 'p') { - return 15; - } - else if (kpd.key[i].kchar == 'q') { - return 16; - } - else if (kpd.key[i].kchar == 'r') { - return 17; - } - else if (kpd.key[i].kchar == 's') { - return 18; - } - else if (kpd.key[i].kchar == 't') { - return 19; - } - else if (kpd.key[i].kchar == 'u') { - return 20; - } - else if (kpd.key[i].kchar == 'v') { - return 21; - } - else if (kpd.key[i].kchar == 'w') { - return 22; - } - else if (kpd.key[i].kchar == 'x') { - return 23; - } - else if (kpd.key[i].kchar == 'y') { - return 24; - } - } - } - } - else { - return 128; - } -} - diff --git a/KeypadWrapper.h b/KeypadWrapper.h deleted file mode 100644 index d7d402b..0000000 --- a/KeypadWrapper.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - Pushing and holding any four buttons at the same time will trigger a new game. -*/ - -#ifndef KEYPADWRAPPER_H -#define KEYPADWRAPPER_H - -#include "Keypad.h" - -class KeypadWrapper { - public: - KeypadWrapper(); - KeypadWrapper(byte *, byte *); - int pollKeypad(); - - private: - byte ROW_PINS[5] = {2, 3, 4, 5, 6}; - byte COL_PINS[5] = {7, 8, 9, 10, 11}; - char KEY_MAP [5][5] = {{'a', 'b', 'c', 'd', 'e'}, - {'f', 'g', 'h', 'i', 'j'}, - {'k', 'l', 'm', 'n', 'o'}, - {'p', 'q', 'r', 's', 't'}, - {'u', 'v', 'w', 'x', 'y'} - }; - Keypad &kpd; -}; - - -#endif - diff --git a/MasterController.ino b/MasterController.ino deleted file mode 100644 index e84cfcd..0000000 --- a/MasterController.ino +++ /dev/null @@ -1,193 +0,0 @@ -#include "I2C.h" -#include "Board.h" -#include "KeypadWrapper.h" - -bool inGame; -I2C_Master mcomm; -Board board; -KeypadWrapper kpdw; - -void gameReset() { - mcomm.write(RESET); - inGame = true; - board.reset(); - board.randomize(); - for (byte i = board.ZERO; i < board.RC; ++i) { - if (board.GAME_BOARD[i]) { - if (i == 0) { - mcomm.write(SET0); - } - else if (i == 1) { - mcomm.write(SET1); - } - else if (i == 2) { - mcomm.write(SET2); - } - else if (i == 3) { - mcomm.write(SET3); - } - else if (i == 4) { - mcomm.write(SET4); - } - else if (i == 5) { - mcomm.write(SET5); - } - else if (i == 6) { - mcomm.write(SET6); - } - else if (i == 7) { - mcomm.write(SET7); - } - else if (i == 8) { - mcomm.write(SET8); - } - else if (i == 9) { - mcomm.write(SET9); - } - else if (i == 10) { - mcomm.write(SET10); - } - else if (i == 11) { - mcomm.write(SET11); - } - else if (i == 12) { - mcomm.write(SET12); - } - else if (i == 13) { - mcomm.write(SET13); - } - else if (i == 14) { - mcomm.write(SET14); - } - else if (i == 15) { - mcomm.write(SET15); - } - else if (i == 16) { - mcomm.write(SET16); - } - else if (i == 17) { - mcomm.write(SET17); - } - else if (i == 18) { - mcomm.write(SET18); - } - else if (i == 19) { - mcomm.write(SET19); - } - else if (i == 20) { - mcomm.write(SET20); - } - else if (i == 21) { - mcomm.write(SET21); - } - else if (i == 22) { - mcomm.write(SET22); - } - else if (i == 23) { - mcomm.write(SET23); - } - else if (i == 24) { - mcomm.write(SET24); - } - } - } - mcomm.write(FIN); -} - -void setup() { - mcomm.init(); - inGame = false; -} - -void loop() { - int keyEvent = kpdw.pollKeypad(); - if (keyEvent == 128) {} - else if (keyEvent == -1) { - gameReset(); - } - else if (keyEvent >= 0 && keyEvent <= 24) { - if (keyEvent == 0) { - mcomm.write(TOGGLE0); - } - else if (keyEvent == 1) { - mcomm.write(TOGGLE1); - } - else if (keyEvent == 2) { - mcomm.write(TOGGLE2); - } - else if (keyEvent == 3) { - mcomm.write(TOGGLE3); - } - else if (keyEvent == 4) { - mcomm.write(TOGGLE4); - } - else if (keyEvent == 5) { - mcomm.write(TOGGLE5); - } - else if (keyEvent == 6) { - mcomm.write(TOGGLE6); - } - else if (keyEvent == 7) { - mcomm.write(TOGGLE7); - } - else if (keyEvent == 8) { - mcomm.write(TOGGLE8); - } - else if (keyEvent == 9) { - mcomm.write(TOGGLE9); - } - else if (keyEvent == 10) { - mcomm.write(TOGGLE10); - } - else if (keyEvent == 11) { - mcomm.write(TOGGLE11); - } - else if (keyEvent == 12) { - mcomm.write(TOGGLE12); - } - else if (keyEvent == 13) { - mcomm.write(TOGGLE13); - } - else if (keyEvent == 14) { - mcomm.write(TOGGLE14); - } - else if (keyEvent == 15) { - mcomm.write(TOGGLE15); - } - else if (keyEvent == 16) { - mcomm.write(TOGGLE16); - } - else if (keyEvent == 17) { - mcomm.write(TOGGLE17); - } - else if (keyEvent == 18) { - mcomm.write(TOGGLE18); - } - else if (keyEvent == 19) { - mcomm.write(TOGGLE19); - } - else if (keyEvent == 20) { - mcomm.write(TOGGLE20); - } - else if (keyEvent == 21) { - mcomm.write(TOGGLE21); - } - else if (keyEvent == 22) { - mcomm.write(TOGGLE22); - } - else if (keyEvent == 23) { - mcomm.write(TOGGLE23); - } - else if (keyEvent == 24) { - mcomm.write(TOGGLE24); - } - mcomm.write(FIN); - if (board.isWin()) { - mcomm.write(WIN); - inGame = false; - mcomm.write(FIN); - } - } - -} - diff --git a/MasterController/Board.cpp b/MasterController/Board.cpp new file mode 100644 index 0000000..a742d18 --- /dev/null +++ b/MasterController/Board.cpp @@ -0,0 +1,368 @@ +#include "Board.h" + + /* If board is orthogonal to these, then it is solvable. */ + const bool SOLVABLE1[25] = {false, true, true, true, false, + true, false, true, false, true, + true, true, false, true, true, + true, false, true, false, true, + false, true, true, true, false + }; + + const bool SOLVABLE2[25] = {true, false, true, false, true, + true, false, true, false, true, + false, false, false, false, false, + true, false, true, false, true, + true, false, true, false, true + }; + + const bool A[25][25] = {{true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, true, true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {true, false, false, false, false, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, true, false, false, false, true, true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, false, true, false, false, false, false, true, true, false, false, false, true, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false, false}, + {false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, false, false, false, false, true, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, true, true, false, false, false, true, false, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, true, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, false, false, false, false, true}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, true, true, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true} + }; + + /* Product of the elementary matrices that make up the row operations for Gaussian elimination. */ + const bool R[25][25] = {{false, false, false, false, false, true, false, false, false, false, true, true, false, false, false, true, false, true, false, false, false, true, true, true, false}, + {false, false, false, false, false, false, true, false, false, false, true, true, true, false, false, false, false, false, true, false, true, true, false, true, true}, + {false, false, false, true, false, false, false, false, true, true, false, false, true, true, false, false, true, false, true, false, true, true, true, false, true}, + {false, false, true, true, true, false, true, false, false, false, true, true, false, true, true, false, true, false, false, false, false, false, true, true, true}, + {false, false, false, true, true, false, false, true, false, true, false, true, true, true, false, true, false, false, false, false, true, false, true, true, false}, + {false, false, true, false, true, false, true, true, false, true, false, false, true, false, false, false, false, false, true, true, false, false, false, false, false}, + {false, false, true, false, false, false, true, true, true, false, true, true, false, false, true, false, true, false, false, true, false, false, true, true, false}, + {false, false, false, false, true, false, false, false, true, true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, true}, + {false, false, true, false, false, false, true, true, true, false, true, false, false, true, true, true, false, false, true, false, false, true, true, false, false}, + {false, false, true, false, true, false, true, true, false, true, true, false, true, false, true, true, true, false, false, false, true, false, false, false, true}, + {false, false, false, false, true, false, false, false, true, true, false, false, true, false, true, true, true, true, true, false, false, true, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false, false}, + {false, false, false, true, true, false, false, true, false, false, false, true, true, false, true, true, false, false, false, true, true, false, true, true, false}, + {false, false, true, true, true, false, true, false, true, false, true, true, true, false, false, false, false, false, true, false, true, true, false, true, true}, + {false, false, false, true, false, false, false, true, true, true, false, true, false, false, false, true, true, false, true, false, false, true, false, true, true}, + {false, false, true, false, false, false, true, true, true, false, true, false, false, false, true, true, false, true, false, true, true, false, true, false, false}, + {false, false, true, true, false, false, true, false, false, true, true, true, false, false, true, false, true, true, true, false, false, false, true, false, false}, + {false, false, true, false, true, false, true, true, false, true, true, false, true, false, false, true, true, false, true, true, true, false, false, false, false}, + {false, false, false, true, false, false, false, true, true, true, false, true, false, false, false, true, true, false, true, true, false, true, false, true, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true}, + {false, false, false, true, true, false, false, true, false, false, false, true, true, false, true, true, false, true, false, true, true, true, false, false, false}, + {false, false, true, true, true, false, true, false, true, false, true, true, true, false, false, false, false, false, false, false, true, true, true, false, false}, + {false, false, false, true, false, false, false, true, true, true, false, true, false, false, false, true, true, false, true, true, false, true, false, false, false}, + {true, false, true, false, true, true, false, true, false, true, false, false, false, false, false, true, false, true, false, true, true, false, true, false, true}, + {false, true, true, true, false, true, false, true, false, true, true, true, false, true, true, true, false, true, false, true, false, true, true, true, false} + }; + +void Board::bin(unsigned long n) { + unsigned long k; + for (int i = 31; i >= 0; --i) { + k = (unsigned long) 1 << i; + if (k & n) { + Serial.print("1"); + } + else { + Serial.print("0"); + } + } + Serial.println(); +} + +void Board::solve() { + Serial.println("Solution: "); + bool TEMP[RC] = {false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false + }; + + mvm(R, GAME_BOARD, TEMP); + for (byte i = ZERO; i < RC; ++i) { + if (TEMP[i]) { + toggle(i); + Serial.println(i); + printSerial(); + } + } +} + +void Board::setsolution(){ + bool TEMP[RC] = {false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false + }; + mvm(R, GAME_BOARD, TEMP); + for (byte i = ZERO; i < RC; ++i) { + solution = "hello"; + } +} + +/* Call reset before */ +void Board::randomize() { + + unsigned long minMoves = random(5, 25); + unsigned long randomBits = nrand25(minMoves); + unsigned long k; + bool TEMP[RC] = {false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false + }; + for (unsigned long i = 0; i < 25; ++i) { + k = 1 << i; + if (k & randomBits) { + TEMP[(byte) i] = true; + } + } + mvm(A, TEMP); + for (int i = 0; i < RC; ++i){ + INITIAL_BOARD[i] = GAME_BOARD[i]; + } + //setsolution(); +} + +/* + void Board::randomize(int difficulty) { + unsigned long minMoves = 0; + if (difficulty == 1) { + minMoves = random(5, 11); + } + else if (difficulty == 2) { + minMoves = random(10, 16); + } + else if (difficulty == 3) { + minMoves = random(15, 21); + } + else if (difficulty == 4) { + minMoves = random(20, 25); + } + else { + minMoves = random(5, 25); + } + Serial.print("Min Moves: "); + Serial.println(minMoves, DEC); + unsigned long randomBits = nrand25(minMoves); + Serial.print("Random Bits Integer: "); + Serial.println(randomBits, DEC); + Serial.print("Binary: "); + bin(randomBits); + Serial.print("Binary: "); + Serial.println(randomBits, BIN); + + unsigned long k; + + bool TEMP[RC] = {false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false + }; + for (unsigned long i = 0; i < 25; ++i) { + k = 1 << i; + if (k & randomBits) { + TEMP[(byte) i] = true; + } + } + mvm(A, TEMP); + }*/ + +/* Excludes n, so call with n + 1. */ +int Board::randto(int n) { + int r = random(0, n); + return r; +} + +void Board::shuffle(int *x, int n) { + for (int i = 0; i < n; ++i) { + int j = randto(25); + int tmp = x[i]; + x[i] = x[j]; + x[j] = tmp; + } +} + +/* Produces a "random" 25 bit integer with n bits set to 1. */ +unsigned long Board::nrand25(int n) { + unsigned long v = 0; + int pos[25] = {0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24 + }; + shuffle(pos, 25); + for (int i = 0; i < n; ++i) { + unsigned long k = 1; + v |= (k << pos[i]); + } + return v; +} + +/* All lights off. */ +void Board::reset() { + for (byte row = 0; row < RC; ++row) { + INITIAL_BOARD[row] = GAME_BOARD[row] = false; + } +} + +bool Board::isWin() { + for (byte row = 0; row < RC; ++row) { + if (GAME_BOARD[row]) { + return false; + } + } + return true; +} + +/* Corresponds to XOR. + +|0|1| + 0|0|1| + 1|1|0| +*/ +bool Board::add(bool p1, bool p2) { + + if (p1 && !p2 || !p1 && p2) { + return true; + } + else { + return false; + } +} + +/* Corresponds to AND. + x|0|1| + 0|0|0| + 1|0|1| +*/ +bool Board::multiply(bool p1, bool p2) { + if (p1 && p2) { + return true; + } + else { + return false; + } +} + +/* Matrix Vector Multiply */ +void Board::mvm(const bool(&mat)[RC][RC], bool(&vec)[RC]) { + for (byte i = 0; i < RC; ++i) { + GAME_BOARD[i] = dot(mat[i], vec); + } +} + +/* Matrix Vector Multiply */ +void Board::mvm(const bool(&mat)[RC][RC], bool(&vec)[RC], bool(&result)[RC]) { + for (byte i = 0; i < RC; ++i) { + result[i] = dot(mat[i], vec); + } +} + +/* 25x1 Vector Dot Product */ +bool Board::dot(const bool(&v1)[RC], bool(&v2)[RC]) { + bool temp[RC] = {false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false + }; + bool result = true; + for (byte i = 0; i < RC; ++i) { + temp[i] = multiply(v1[i], v2[i]); + } + for (byte i = 0; i < RC; ++i) { + if (i == 0) { + result = temp[0]; + } else { + result = add(result, temp[i]); + } + } + return result; +} + + +/* True if board is solvable, false if not. */ +bool Board::isSolvable() { + bool s1 = false; + bool s2 = false; + + s1 = dot(SOLVABLE1, GAME_BOARD); + s2 = dot(SOLVABLE2, GAME_BOARD); + + if (!s1 && !s2) { + return true; + } + else { + return false; + } +} + +/* Sets 0-indexed grid number to true/false without toggling adjacent squares */ +void Board::set(byte gridNum, bool state) { + GAME_BOARD[gridNum] = state; +} + +/* Toggles 0-indexed square and adjacent squares. */ +void Board::toggle(byte gridNum) { + /* Error checking for valid range? */ + /* Toggle the square itself. */ + GAME_BOARD[gridNum] = !GAME_BOARD[gridNum]; + + /* North Adjacent only when row > 4 */ + if (gridNum > FOUR) { + GAME_BOARD[gridNum - FIVE] = !GAME_BOARD[gridNum - FIVE]; + } + + /* South adjacent only when row < 20 */ + if (gridNum < TWENTY) { + GAME_BOARD[gridNum + FIVE] = !GAME_BOARD[gridNum + FIVE]; + } + + /* East adjacent only when row MOD 5 != 4 */ + if (gridNum % FIVE != FOUR) { + GAME_BOARD[gridNum + ONE] = !GAME_BOARD[gridNum + ONE]; + } + + /* West adjacent only when row MOD 5 != 0 */ + if (gridNum % FIVE != ZERO) { + GAME_BOARD[gridNum - ONE] = !GAME_BOARD[gridNum - ONE]; + } +} + +void Board::printSerial() { + for (byte i = 0; i < RC; ++i) { + if (GAME_BOARD[i]) { + Serial.print("| ON"); + } + else { + Serial.print("|OFF"); + } + if (i % FIVE == 4) { + Serial.println("|"); + } + } + Serial.println(); +} + + + + + + diff --git a/MasterController/Board.h b/MasterController/Board.h new file mode 100644 index 0000000..2e91579 --- /dev/null +++ b/MasterController/Board.h @@ -0,0 +1,71 @@ +/* + FALSE = OFF 0 + TRUE = ON 1 + + | 0| 1| 2| 3| 4| + | 5| 6| 7| 8| 9| + |10|11|12|13|14| + |15|16|17|18|19| + |20|21|22|23|24| + +*/ +#ifndef BOARD_LIGHTSOUT_H +#define BOARD_LIGHTSOUT_H + +#include "Arduino.h" + + + +class Board { + public: + static const byte FIVE = 5; + static const byte FOUR = 4; + static const byte ZERO = 0; + static const byte TWENTY = 20; + static const byte ONE = 1; + static const byte RC = 25; + + void randomize(); + int randto(int); + void shuffle(int *, int); + unsigned long nrand25(int); + String solution; + + void set(byte, bool); /* Sets 0-indexed grid number to true/false without toggling adjacent squares */ + void toggle(byte); /* Toggle by 0-indexed grid number */ + bool isWin(); + bool isSolvable(); + void reset(); + void solve(); + void setsolution(); + + bool add(bool, bool); + bool multiply(bool, bool); + void mvm(const bool(&)[RC][RC], bool(&)[RC]); + void mvm(const bool(&)[RC][RC], bool(&)[RC], bool(&)[RC]); + bool dot(const bool(&)[RC], bool(&)[RC]); + + void printSerial(); + void bin(unsigned long); + + bool GAME_BOARD[RC] = {false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false + }; + + bool INITIAL_BOARD[RC] = {false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false + }; +}; +#endif + + + + + + diff --git a/I2C.cpp b/MasterController/I2C.cpp similarity index 100% rename from I2C.cpp rename to MasterController/I2C.cpp diff --git a/I2C.h b/MasterController/I2C.h similarity index 100% rename from I2C.h rename to MasterController/I2C.h diff --git a/MasterController/KeypadWrapper.cpp b/MasterController/KeypadWrapper.cpp new file mode 100644 index 0000000..0810b6c --- /dev/null +++ b/MasterController/KeypadWrapper.cpp @@ -0,0 +1,30 @@ +//#include "KeypadWrapper.h" +// +//KeypadWrapper::KeypadWrapper() { +// _kpd = Keypad(makeKeymap(KEY_MAP), ROW_PINS, COL_PINS, 5, 5); +// _kpd.setDebounceTime(100); +//} +// +//KeypadWrapper::KeypadWrapper(byte *rpins, byte *cpins) { +// for (byte i = 0; i < 5; ++i) { +// ROW_PINS[i] = rpins[i]; +// COL_PINS[i] = cpins[i]; +// } +// _kpd = Keypad(makeKeymap(KEY_MAP), ROW_PINS, COL_PINS, 5, 5); +// _kpd.setDebounceTime(100); +//} +// +//int KeypadWrapper::pollKeypad() { +// if (_kpd.getKeys()) { +// int count = 0; +// for (int i = 0; i < LIST_MAX; i++) { +// if (_kpd.key[i].kstate == HOLD) { +// ++count; +// if (count == 4) return -1; +// } +// else if (_kpd.key[i].kstate == PRESSED) return _kpd.key[i].kchar; +// } +// } +// else return 128; +//} + diff --git a/MasterController/KeypadWrapper.h b/MasterController/KeypadWrapper.h new file mode 100644 index 0000000..2fc310a --- /dev/null +++ b/MasterController/KeypadWrapper.h @@ -0,0 +1,30 @@ +/* + Pushing and holding any four buttons at the same time will trigger a new game. +*/ + +#ifndef KEYPADWRAPPER_H +#define KEYPADWRAPPER_H + +//#include "Keypad.h" +// +//class KeypadWrapper { +// public: +// KeypadWrapper(); +// KeypadWrapper(byte *, byte *); +// int pollKeypad(); +// +// private: +// byte ROW_PINS[5] = {6,5,4,3,2}; +// byte COL_PINS[5] = {11, 10, 9, 8, 7}; +// char KEY_MAP [5][5] = {{'a', 'b', 'c', 'd', 'e'}, +// {'f', 'g', 'h', 'i', 'j'}, +// {'k', 'l', 'm', 'n', 'o'}, +// {'p', 'q', 'r', 's', 't'}, +// {'u', 'v', 'w', 'x', 'y'} +// }; +// Keypad _kpd; +//}; + + +#endif + diff --git a/MasterController/MasterController.ino b/MasterController/MasterController.ino new file mode 100644 index 0000000..e70b26f --- /dev/null +++ b/MasterController/MasterController.ino @@ -0,0 +1,119 @@ +#include "I2C.h" +#include "Board.h" +#include +#include +#include + +LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); + +const byte ROWS = 5; +const byte COLS = 5; + +char hexaKeys[ROWS][COLS] = { + {'a','b','c','d','e'}, + {'f','g','h','i','j'}, + {'k','l','m','n','o'}, + {'p','q','r','s','t'}, + {'u','v','w','x','y'} +}; + +byte rowPins[ROWS] = {6,5,4,3,2}; +byte colPins[COLS] = {11,10,9,8,7}; +bool sol[25]; +bool ingame = false; +int score; +int hscore; +long long last_score_update = millis();; +long long start_time = millis(); +int moves = 0; + +Keypad kpad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); + +I2C_Master mcomm; +Board board; + +int pollKeypad(); +void gameReset(); +void findsolution(); +void initlcd(); + +void setup() { + lcd.begin(16,2); + initlcd(); + score = 0; + randomSeed(analogRead(0)); + mcomm.init(); + gameReset(); +} +void loop() { + if (millis() - last_score_update > 1000 && ingame){ + last_score_update = millis(); + score = max(0,9999 - moves*10*((.5*(millis()-start_time))/1000)); + lcd.setCursor(7,0); lcd.print(" "); lcd.setCursor(7,0); + lcd.print(score); + } + + int keyEvent = pollKeypad(); + if (keyEvent == 128) {} + else if (keyEvent == -1) { + gameReset(); + } + else if (keyEvent >= 0 && keyEvent <= 24) { + moves++; + mcomm.write(TOGGLE0+keyEvent); + board.toggle(keyEvent); + if (board.isWin()) { + ingame = false; + lcd.clear(); + lcd.print("You win!"); + if(score > hscore) { + lcd.setCursor(0,1); + lcd.print("New High Score!"); + EEPROM.write(0, 1); + EEPROM.put(1, score); + } + mcomm.write(WIN); + } + } +} + +int pollKeypad() { + if (kpad.getKeys()) { + int count = 0; + for (int i = 0; i < LIST_MAX; i++) { + if (kpad.key[i].kstate == HOLD) { + ++count; + if (count == 2) return -1; + } + else if (kpad.key[i].kstate == PRESSED) return kpad.key[i].kchar - 97; + } + } + + else return 128; +} + +void gameReset() { + mcomm.write(RESET); + board.reset(); + board.randomize(); + for (byte i = board.ZERO; i < board.RC; ++i) { + if (board.GAME_BOARD[i]) mcomm.write(SET0+i); + } + initlcd(); + moves = 0; + start_time = millis(); + last_score_update = -1000; + ingame = true; +} + +void initlcd(){ + lcd.clear(); + lcd.print("Score: 0"); + lcd.setCursor(0, 1); + lcd.print("Hscore: "); + if(EEPROM.read(0) == 0) hscore = 0; + else EEPROM.get(1, hscore); + lcd.print(hscore); +} + + diff --git a/MasterController/globals.h b/MasterController/globals.h new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/MasterController/globals.h @@ -0,0 +1 @@ + diff --git a/SlaveBoard/I2C.cpp b/SlaveBoard/I2C.cpp new file mode 100644 index 0000000..e21f963 --- /dev/null +++ b/SlaveBoard/I2C.cpp @@ -0,0 +1,25 @@ +#include "I2C.h" + +void I2C_Slave::init(void(*callback)()){ + Wire.begin(SLAVE_ADDR); + Wire.onReceive(callback); /* Register callback */ +} + +int I2C_Slave::available() { + return Wire.available(); +} + +EVENT I2C_Slave::read() { + return (EVENT) Wire.read(); +} + +void I2C_Master::init(){ + Wire.begin(); +} + +void I2C_Master::write(EVENT e) { + Wire.beginTransmission(SLAVE_ADDR); + Wire.write(e); + Wire.endTransmission(); +} + diff --git a/SlaveBoard/I2C.h b/SlaveBoard/I2C.h new file mode 100644 index 0000000..fdf4873 --- /dev/null +++ b/SlaveBoard/I2C.h @@ -0,0 +1,111 @@ + +#ifndef I2C_COMM_H +#define I2C_COMM_H + +#include "Wire.h" +#include "Arduino.h" + + +/* + LEDs & Switches refer to same square on grid. + + | 1| 2| 3| 4| 5| + | 6| 7| 8| 9|10| + |11|12|13|14|15| + |16|17|18|19|20| + |21|22|23|24|25| +*/ + + +enum EVENT : byte { + /* THE EVENTS LISTED HERE MAP THE ENTIRE BYTE */ + + /* TOGGLE EVENTS */ + /* UPPER 3 BITS ARE 001 */ + /* DECIMAL RANGE 33 - 57 */ + TOGGLE0 = 33, + TOGGLE1 = 34, + TOGGLE2 = 35, + TOGGLE3 = 36, + TOGGLE4 = 37, + TOGGLE5 = 38, + TOGGLE6 = 39, + TOGGLE7 = 40, + TOGGLE8 = 41, + TOGGLE9 = 42, + TOGGLE10 = 43, + TOGGLE11 = 44, + TOGGLE12 = 45, + TOGGLE13 = 46, + TOGGLE14 = 47, + TOGGLE15 = 48, + TOGGLE16 = 49, + TOGGLE17 = 50, + TOGGLE18 = 51, + TOGGLE19 = 52, + TOGGLE20 = 53, + TOGGLE21 = 54, + TOGGLE22 = 55, + TOGGLE23 = 56, + TOGGLE24 = 57, + + /* We use these for game reset. Implies board is all false, so we are setting to true. */ + /* Do not toggle neighbors. */ + SET0 = 58, + SET1 = 59, + SET2 = 60, + SET3 = 61, + SET4 = 62, + SET5 = 63, + SET6 = 64, + SET7 = 65, + SET8 = 66, + SET9 = 67, + SET10 = 68, + SET11 = 69, + SET12 = 70, + SET13 = 71, + SET14 = 72, + SET15 = 73, + SET16 = 74, + SET17 = 75, + SET18 = 76, + SET19 = 77, + SET20 = 78, + SET21 = 79, + SET22 = 80, + SET23 = 81, + SET24 = 82, + /* GAME WON */ + WIN = 96, + + /* RESET/NEW GAME */ + RESET = 160, + + /* TRANSMISSION FINISH */ + FIN = 170, + + /* MASTER ERROR */ + M_ERROR = 224 +}; + + +class I2C_Slave { + public: + const byte SLAVE_ADDR = 27; + + void init(void(*callback)()); + int available(); + EVENT read(); +}; + +class I2C_Master { + public: + const byte SLAVE_ADDR = 27; + void init(); + void write(EVENT); + +}; + +#endif + diff --git a/SlaveBoard.ino b/SlaveBoard/SlaveBoard.ino similarity index 82% rename from SlaveBoard.ino rename to SlaveBoard/SlaveBoard.ino index 6df9c27..9f5eb0b 100644 --- a/SlaveBoard.ino +++ b/SlaveBoard/SlaveBoard.ino @@ -1,5 +1,4 @@ #include "I2C.h" -#include "LiquidCrystal_I2C.h" #define ON true #define OFF false @@ -11,11 +10,16 @@ const uint8_t m_size = 5; //corresponds to current state of LEDs in matrix, 1 = on bool state[m_size*m_size]; + +//bool state[m_size*m_size] = { 0,1,1,0,1, +// 1,1,0,1,1, +// 0,0,1,0,0, +// 1,0,0,1,1, +// 1,1,1,1,1 }; uint8_t cur_row = 0; I2C_Slave slave; -LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); void eventhandle(); @@ -27,14 +31,12 @@ void setup() { digitalWrite(colpin[i], LOW); } for(int i = 0; i < m_size*m_size; ++i) state[i] = OFF; - lcd.begin(16,2); slave.init(eventhandle); } void loop() { - //turn off the other two rows - digitalWrite(rowpin[(cur_row+1)%m_size], LOW); - digitalWrite(rowpin[(cur_row+2)%m_size], LOW); + //turn off the other rows + for(int i = 1; i < m_size; ++i) digitalWrite(rowpin[(cur_row+i)%m_size], LOW); //column = LOW lets current pass, HIGH blocks current for(int col = 0; col < m_size; ++col) digitalWrite(colpin[col], !(state[(cur_row)*m_size+col])); @@ -62,20 +64,17 @@ void eventhandle(){ state[event-SET0] = ON; } else{ - lcd.clear(); switch(event){ case WIN: - lcd.write("You win"); break; case RESET: - lcd.write("Resetting"); for(byte i = 0; i < 25; ++i) state[i] = OFF; break; case M_ERROR: - lcd.write("Error"); for(byte i = 0; i < 25; ++i) state[i] = OFF; break; - default: lcd.write("Unexpected Error"); + default: + break; } } }