// from learnSequencePuzzle.ino
// https://forum.arduino.cc/t/toggle-switch-puzzle-but-sequential/1091460
// https://wokwi.com/projects/357012577248058369
# define SEVEN 7 // puzzle size
# include <Adafruit_NeoPixel.h>
# define LED_PIN A2
# define LED_COUNT SEVEN
Adafruit_NeoPixel disaply(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
unsigned char combo[SEVEN];
unsigned char lastSwitch[SEVEN];
enum Runstate {START, RUNNING, FAULT, SUCCESS} runState;
# define redLED A1 // bad
# define greenLED A0 // good
# define NOKEY 99 // impossible key value as a flag
const byte inputPin[SEVEN] = {2, 3, 4, 5, 6, 7, 8, };
void setup() {
Serial.begin(115200); Serial.println("HE LL O!\n");
for (unsigned char ii = 0; ii < SEVEN; ii++) {
pinMode(inputPin[ii], INPUT_PULLUP);
lastSwitch[ii] = digitalRead(inputPin[ii]);
}
pinMode(greenLED, OUTPUT);
pinMode(redLED, OUTPUT);
disaply.begin();
disaply.show();
reset();
runState = RUNNING;
newCombo();
}
unsigned char nIn = 0; // number of correct steps taken sofa
void loop() {
unsigned char pKey = scanKeys();
switch (runState) {
case RUNNING:
if (pKey == NOKEY)
return;
// presst a key, all key are valid so
if (pKey == combo[nIn]) {
nIn++;
displayDisplay();
goodFlash();
if (nIn == SEVEN) {
Serial.println("You are in!");
runState = SUCCESS;
}
}
else {
Serial.print(" BZZZT!");
runState = FAULT;
}
break;
case FAULT:
badFlash();
if (keysum() == 0) {
reset();
displayDisplay();
runState = START;
}
break;
case SUCCESS:
reward();
if (pKey != NOKEY) {
newCombo();
reset();
displayDisplay();
runState = FAULT;
}
break;
case START:
runState = RUNNING;
break;
default:
runState = START;
break;
}
}
void goodFlash()
{
digitalWrite(A1, HIGH);
delay(100);
digitalWrite(A1, LOW);
displayDisplay();
}
void badFlash()
{
static uint32_t last = 0;
const int interval = 50;
if (millis() - last >= interval) {
last = millis();
digitalWrite(A0, !digitalRead(A0));
displayDisplay();
}
}
void reward()
{
static uint32_t last = 0;
const int interval = 600;
static bool off = true;
if (millis() - last < interval) return;
last = millis();
if (off) { // turn on
nIn = SEVEN; displayDisplay();
digitalWrite(A1, HIGH);
} else {
digitalWrite(A1, LOW);
nIn = 0; displayDisplay();
off = true;
}
}
void reset()
{
nIn = 0;
}
void displayDisplay()
{
for (unsigned char tt = 0; tt < SEVEN; tt++) {
// disaply.setPixelColor(tt, tt >= nIn ? 0x001010 : 0x00ff00);
if (runState != FAULT) {
disaply.setPixelColor(combo[tt], tt >= nIn ? 0x001010 : 0x00ff00);
} else {
disaply.setPixelColor(tt, lastSwitch[tt] ? 0xff0000 : 0x001010);
}
}
disaply.show();
}
// scanKeysO looks for a button going pressed
// scanKeys just looks for a change of state
unsigned char scanKeys()
{
// printf("scan keys ");
unsigned char newKeyQ = NOKEY;
static unsigned long lastTime;
unsigned char currentKey = NOKEY;
unsigned long now = millis();
if (now - lastTime < 40) // too soon to look at anything
return currentKey;
lastTime = now;
for (unsigned char ii = 0; ii < SEVEN; ii++) {
unsigned char aSwitch = digitalRead(inputPin[ii]);
if (aSwitch != lastSwitch[ii]) {
currentKey = ii;
lastSwitch[ii] = aSwitch;
}
}
return currentKey;
}
int keysum() {
int retval = 0;
for (unsigned char ii = 0 ; ii < SEVEN; ii++) {
retval += lastSwitch[ii];
}
return retval;
}
unsigned char scanKeys0()
{
// printf("scan keys ");
unsigned char newKeyQ = NOKEY;
static unsigned long lastTime;
static unsigned char wasPressed = 0;
char isPressed = 0;
unsigned char currentKey = NOKEY;
unsigned long now = millis();
if (now - lastTime < 40)
return currentKey;
for (unsigned char ii = 0; ii < SEVEN; ii++) {
if (!digitalRead(inputPin[ii])) {
newKeyQ = ii;
isPressed = 1;
}
}
if (isPressed != wasPressed) {
lastTime = now;
if (isPressed)
currentKey = newKeyQ;
wasPressed = isPressed;
}
return currentKey;
}
// newCombo0 creates a random scfamble
// newCombo gets the "next" scramble from a pre-conceived list
# define NCOMBOS 4
unsigned char theCombinations[][7] = {
{0, 1, 2, 3, 4, 5, 6},
{6, 5, 4, 3, 2, 1, 0},
{4, 1, 2, 0, 5, 6, 3},
{0, 5, 4, 6, 2, 1, 3},
};
void newCombo()
{
static unsigned char serveNext;
for (unsigned char ii = 0; ii < SEVEN; ii++)
combo[ii] = theCombinations[serveNext][ii];
serveNext++;
if (serveNext >= NCOMBOS) serveNext = 0;
// return; // if you do not want to print the combination!
for (unsigned char ii = 0; ii < SEVEN; ii++) {
Serial.print(combo[ii]);
Serial.print(" ");
}
Serial.println();
}
void newCombo0()
{
for (unsigned char ii = 0; ii < SEVEN; ii++)
combo[ii] = ii;
for (int ii = 0; ii < 5000; ii++) {
unsigned char tt = random(SEVEN);
unsigned char ss = random(SEVEN);
unsigned char temp;
temp = combo[tt];
combo[tt] = combo[ss];
combo[ss] = temp;
}
// return; // if you do not want to print the combination!
for (unsigned char ii = 0; ii < SEVEN; ii++) {
Serial.print(combo[ii]);
Serial.print(" ");
}
Serial.println();
}