Toggle Switch puzzle but sequential

Yes, kind of sloppy with the WOKWI stuff, I'll try to do better.

the seven led strip is a standard size from Adafruit, i want to try to use the two outer leds as a "wrong answer" indicator. I might just ditch the strip and use the 45 LED ring altogether.

The idea is the switches are more "tactile" and would go along with a theme such as disarm a bomb, crack the launch code, that sort of thing. more immersion then anything. Plus, the switches in my picture above look really kinda cool. The led on the switch lights up when turned on and the covers turn the switch off when closed.

The next aim is to add a timer to countdown from something like 5 minutes while accumulating wrong guesses and factoring in correct puzzles. The simple plan is to run the puzzle and get as many right as one can with as few guesses as possible.

Not a finish to the game except when the timer runs out. This is more of a waiting room game while they wait until the actual room is ready, or something to aggravate my buddies on bar night.

Good/True random number generators are important for cryptography where it is important to consume lots of bits of good randomness. But for use-cases like this, you only need a few bits, which it's easy to get from user input or a floating pin.

What I dislike about the loop(){random();...} method is that it wastes entropy. If you consider it a stacked deck of cards, the 50th card won't change. The Arduino random() is a stacked deck of 2^31 cards, and if you know one of them, you know how the rest of the deal will go. If the 1000th loop gave random()= 522329230, then the millionth would match with if(random()==1227283347).

If whenever a user touches a button, you do something like randomSeed(random()+26) or randomSeed(micros()) it is like cutting the deck. It mixes the PRNG stream with some external randomness and makes the following cards unpredictable until you figure out where in the stack you are. If you are going to the trouble of picking a random card from an PRNGs stacked deck, cut the deck when you do it.

IMHO, a single cut of random()'s 2147483648 card deck would be adequate for a game like this, and if you are going through the trouble of monitoring user input for better randomness, cut again at UI events too.

Always good.

I did finally get how to solve it.


LOL. I've got giant bags of entropy around here, more than a life time supply and I've been hearing about it since forever, from one person or another.

Srsly, though, I appreciate your points, and have spent some enjoyable time letting the internet take me all over this variously.

a7

Thanks ALL, I think I have enough randomness and entropy going on in this project to make it into something. What I want to do now is add a timer and an OLED screen as well. Problem is, the way I know how is giving CLK and DIO conflicts. The OLED screen will be hooked up to the Serial clock and serial data ports. Am I not able to hook it up this way?

So far so good. Adjusting from the Wokwi sketch, I had to nix the INPUT_PULLUP and just call them INPUT as the PULLUP would light the LEDS on these toggles which I didn't want. Other then making some thing happen with the buzzer when the timer reaches 0, I have a working model. Just would like to get the OLED working. This is where I am having issues.

Here is the sketch with the OLED in it, but not added in the code.

// from learnSequencePuzzle.ino

// https://forum.arduino.cc/t/toggle-switch-puzzle-but-sequential/1091460
// https://wokwi.com/projects/357012577248058369

# define SEVEN   5    // puzzle size
# include <SPI.h>
/* Set Display Digits - 4 or 6 */
#define DIGITS 4

/* Digital Pins to TM1637 */
#define CLK 3
#define DIO 2

/* Set up 6-Digit Display */
#if DIGITS == 6
  #include <TM1637TinyDisplay6.h>
  TM1637TinyDisplay6 display(CLK, DIO);
  uint8_t dots = 0b01010000; // Add dots or colons (depends on display module)
#else

/* Set up 4-Digit Display */
  #include <TM1637TinyDisplay.h>
  TM1637TinyDisplay display(CLK, DIO);
  uint8_t dots = 0b01000000; // Add dots or colons (depends on display module)
#endif

/* Useful Constants */
#define SECS_PER_MIN  (60UL)
#define SECS_PER_HOUR (3600UL)
#define SECS_PER_DAY  (SECS_PER_HOUR * 24L)

/* Useful Macros for time (s) */
#define numberOfSeconds(_time_) (_time_ % SECS_PER_MIN)
#define numberOfMinutes(_time_) ((_time_ / SECS_PER_MIN) % SECS_PER_MIN)
#define numberOfHours(_time_) (( _time_% SECS_PER_DAY) / SECS_PER_HOUR)
#define elapsedDays(_time_) ( _time_ / SECS_PER_DAY)
#define hmsToMillis(_h_, _m_, _s_) ((_h_ * SECS_PER_HOUR) + (_m_ * SECS_PER_MIN) + _s_ ) * 1000ul;

/* Global Variables in milliseconds */
unsigned long startTime;
unsigned long lastLoopTime;
unsigned long countDown;

# include <Adafruit_NeoPixel.h>

# define LED_PIN    A2
# define LED_COUNT  SEVEN
# define LED_PIN2    A5
# define LED_COUNT2  45

Adafruit_NeoPixel disaply(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip(LED_COUNT2, LED_PIN2, 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] = {9, 10, 11, 12, 13};
// This pin will be driven LOW to release a lock when puzzle is solved
const byte lockPin = A3;
const byte lockPin2 = A4;

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);
      // Set the lock pin as output and secure the lock
  pinMode(lockPin, OUTPUT);
  digitalWrite(lockPin, HIGH);
  pinMode(lockPin2, OUTPUT);
  digitalWrite(lockPin2, LOW);

  disaply.begin();
  disaply.show();
  strip.clear();
  strip.begin();


  reset();
  runState = RUNNING;
  newCombo0();

  display.begin();
  display.setBrightness(BRIGHT_HIGH);

  // Record Epoch - Same as Timer Reset
  startTime = millis();

  // Set countdown timer in h, m, s
  int Hour = 0;
  int Min = 05;
  int Sec = 00;
  countDown = hmsToMillis(Hour, Min, Sec);
  pinMode(lockPin, OUTPUT); 
  digitalWrite(lockPin, HIGH);  
}

unsigned char nIn = 0;    // number of correct steps taken sofa

void loop() {

  unsigned long timeNow = millis();
  unsigned long timeElapsed = timeNow - startTime;  // amount of time since start
  unsigned long counter = countDown - timeElapsed; // current state of countdown

  // Update Display - every 10ms
  if (timeNow - lastLoopTime >= 10) {
    lastLoopTime = timeNow; // remember last time we displayed

    if (timeElapsed >= countDown) {
      // If we hit zero - flash every second
      unsigned long since = (long)((timeElapsed - countDown) / 500);
      if (since % 2) {
        display.clear();
        // Release the lock
        digitalWrite(lockPin, LOW);       
      }
      else {
        display.showNumberDec(000000, dots, true);
      }
    }
    else {
      // Compute the values
      unsigned long HOURS = numberOfHours(counter / 1000);
      unsigned long MINUTES = numberOfMinutes(counter / 1000);
      unsigned long SECONDS = numberOfSeconds(counter / 1000);
      unsigned long MILLISECONDS = (counter % 1000) / 10;

      // Convert time values to integer to display
      if (HOURS > 0) {
        // Display M:S.hs if timer is below one hour
        display.showNumberDec(HOURS, dots, true, 2, 0);
        display.showNumberDec(MINUTES, dots, true, 2, 2);
#if DIGITS == 6
        display.showNumberDec(MILLISECONDS, 0, true, 2, 4);
#endif
      }

      if (HOURS <= 0 && (MINUTES >0)) {
        // Display M:S.hs if timer is below one hour
        display.showNumberDec(MINUTES, dots, true, 2, 0);
        display.showNumberDec(SECONDS, dots, true, 2, 2);
#if DIGITS == 6
        display.showNumberDec(MILLISECONDS, dots, true, 2, 4);
#endif
      }

      else if (HOURS <= 0 && (MINUTES <=0 && (SECONDS >=0))) {
        // Display M:S.hs if timer is below one hour
        display.showNumberDec(SECONDS, dots, true, 2, 0);
        display.showNumberDec(MILLISECONDS, 0, true, 2, 2);
#if DIGITS == 6
        display.showNumberDec(MILLISECONDS, 0, true, 2, 4);
#endif
      } else {
        // Display H:M:S if timer is above one hour
        display.showNumberDec(HOURS, dots, true, 2, 0);
        display.showNumberDec(MINUTES, dots, true, 2, 2);
#if DIGITS == 6
        display.showNumberDec(SECONDS, 0, true, 2, 4);
#endif
      }
    }
  }



  unsigned char pKey = scanKeys();

    random();    

  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;
          // Release the lock
          digitalWrite(lockPin, LOW);
          theaterChase(strip.Color(255, 255, 255), 100, 3, 5); // White, full brightness          
        }
      }
      else {
    Serial.print("             BZZZT!");
        runState = FAULT;
        // Sound the Buzzer
        theaterChase(strip.Color(255, 0, 0), 100, 3, 5); // RED CHASE         
        digitalWrite(lockPin2, HIGH);  
        delay (1000);
        digitalWrite(lockPin2, LOW);                  
      }
      break;
    case FAULT:
      badFlash();
      if (keysum() == 0) {
        reset();
        displayDisplay();
        runState = START;
      }
      break;
    case SUCCESS:
      reward();
      if (pKey != NOKEY) {
        newCombo0();
        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();
    digitalWrite(A0, LOW);
  }
}

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;
  digitalWrite(A1, LOW);
}

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 ? 0x000000 : 0x00ff00);
      strip.fill(tt >= nIn ? 0x000000 : 0x00ff00, combo[tt] *9, 9);
    } else {
      disaply.setPixelColor(tt, lastSwitch[tt] ? 0xff0000 : 0x000000);
      strip.fill(lastSwitch[tt] ? 0xff0000 : 0x000000, tt *9, 9);
    }
  }

  disaply.show();
  strip.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;
}



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();
}

/*
* Fills a strip with a specific color, starting at 0 and continuing
* until the entire strip is filled. Takes two arguments:
* 
*     1. the color to use in the fill
*     2. the amount of time to wait after writing each LED
*/
void colorWipe(uint32_t color, unsigned long wait) {
	for (unsigned int i = 0; i < strip.numPixels(); i++) {
		strip.setPixelColor(i, color);
		strip.show();
		delay(wait);
	}
}

/*
* Runs a marquee style "chase" sequence. Takes three arguments:
*
*     1. the color to use in the chase
*     2. the amount of time to wait between frames
*     3. the number of LEDs in each 'chase' group
*     3. the number of chases sequences to perform
*/
void theaterChase(uint32_t color, unsigned long wait, unsigned int groupSize, unsigned int numChases) {
	for (unsigned int chase = 0; chase < numChases; chase++) {
		for (unsigned int pos = 0; pos < groupSize; pos++) {
			strip.clear();  // turn off all LEDs
			for (unsigned int i = pos; i < strip.numPixels(); i += groupSize) {
				strip.setPixelColor(i, color);  // turn on the current group
			}
			strip.show();
			delay(wait);
		}
	}
}

/*
* Simple rainbow animation, iterating through all 8-bit hues. LED color changes
* based on position in the strip. Takes two arguments:
* 
*     1. the amount of time to wait between frames
*     2. the number of rainbows to loop through
*/
void rainbow(unsigned long wait, unsigned int numLoops) {
	for (unsigned int count = 0; count < numLoops; count++) {
		// iterate through all 8-bit hues, using 16-bit values for granularity
		for (unsigned long firstPixelHue = 0; firstPixelHue < 65536; firstPixelHue += 256) {
			for (unsigned int i = 0; i < strip.numPixels(); i++) {
				unsigned long pixelHue = firstPixelHue + (i * 65536UL / strip.numPixels()); // vary LED hue based on position
				strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));  // assign color, using gamma curve for a more natural look
			}
			strip.show();
			delay(wait);
		}
	}  
}

and here it is throwing up mad errors.

// from learnSequencePuzzle.ino

// https://forum.arduino.cc/t/toggle-switch-puzzle-but-sequential/1091460
// https://wokwi.com/projects/357012577248058369

# define SEVEN   5    // puzzle size
# include <SPI.h>
# include <Adafruit_SSD1306.h>


# define SCREEN_WIDTH 128 // OLED display width, in pixels
# define SCREEN_HEIGHT 32 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

* Set Display Digits - 4 or 6 */
#define DIGITS 4

/* Digital Pins to TM1637 */
#define CLK 3
#define DIO 2

/* Set up 6-Digit Display */
#if DIGITS == 6
  #include <TM1637TinyDisplay6.h>
  TM1637TinyDisplay6 display(CLK, DIO);
  uint8_t dots = 0b01010000; // Add dots or colons (depends on display module)
#else

/* Set up 4-Digit Display */
  #include <TM1637TinyDisplay.h>
  TM1637TinyDisplay display(CLK, DIO);
  uint8_t dots = 0b01000000; // Add dots or colons (depends on display module)
#endif

/* Useful Constants */
#define SECS_PER_MIN  (60UL)
#define SECS_PER_HOUR (3600UL)
#define SECS_PER_DAY  (SECS_PER_HOUR * 24L)

/* Useful Macros for time (s) */
#define numberOfSeconds(_time_) (_time_ % SECS_PER_MIN)
#define numberOfMinutes(_time_) ((_time_ / SECS_PER_MIN) % SECS_PER_MIN)
#define numberOfHours(_time_) (( _time_% SECS_PER_DAY) / SECS_PER_HOUR)
#define elapsedDays(_time_) ( _time_ / SECS_PER_DAY)
#define hmsToMillis(_h_, _m_, _s_) ((_h_ * SECS_PER_HOUR) + (_m_ * SECS_PER_MIN) + _s_ ) * 1000ul;

/* Global Variables in milliseconds */
unsigned long startTime;
unsigned long lastLoopTime;
unsigned long countDown;

# include <Adafruit_NeoPixel.h>

# define LED_PIN    A2
# define LED_COUNT  SEVEN
# define LED_PIN2    A5
# define LED_COUNT2  45

Adafruit_NeoPixel disaply(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip(LED_COUNT2, LED_PIN2, 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] = {9, 10, 11, 12, 13};
// This pin will be driven LOW to release a lock when puzzle is solved
const byte lockPin = A3;
const byte lockPin2 = A4;

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);
      // Set the lock pin as output and secure the lock
  pinMode(lockPin, OUTPUT);
  digitalWrite(lockPin, HIGH);
  pinMode(lockPin2, OUTPUT);
  digitalWrite(lockPin2, LOW);

  disaply.begin();
  disaply.show();
  strip.clear();
  strip.begin();

  // Clear the display and show it.
  display.clearDisplay();
  display.display();

  display.setCursor(0, 0);
  display.setTextSize(1); // Draw normal-scale text
  display.setTextColor(SSD1306_WHITE);
  display.print(F("Throw The Switches"));
  display.setCursor(0, 20);
  display.setTextSize(1); // Draw normal-scale text
  display.setTextColor(SSD1306_WHITE);
  display.print(F("In Proper Order"));
  display.display();
  delay(5000); // Pause for 5 seconds
  display.clearDisplay();
  display.setCursor(0, 0);


  reset();
  runState = RUNNING;
  newCombo0();

  display.begin();
  display.setBrightness(BRIGHT_HIGH);

  // Record Epoch - Same as Timer Reset
  startTime = millis();

  // Set countdown timer in h, m, s
  int Hour = 0;
  int Min = 01;
  int Sec = 10;
  countDown = hmsToMillis(Hour, Min, Sec);
  pinMode(lockPin, OUTPUT); 
  digitalWrite(lockPin, HIGH);  
}

unsigned char nIn = 0;    // number of correct steps taken sofa

void loop() {

  unsigned long timeNow = millis();
  unsigned long timeElapsed = timeNow - startTime;  // amount of time since start
  unsigned long counter = countDown - timeElapsed; // current state of countdown

  // Update Display - every 10ms
  if (timeNow - lastLoopTime >= 10) {
    lastLoopTime = timeNow; // remember last time we displayed

    if (timeElapsed >= countDown) {
      // If we hit zero - flash every second
      unsigned long since = (long)((timeElapsed - countDown) / 500);
      if (since % 2) {
        display.clear();
        // Release the lock
        digitalWrite(lockPin, LOW);       
      }
      else {
        display.showNumberDec(000000, dots, true);
      }
    }
    else {
      // Compute the values
      unsigned long HOURS = numberOfHours(counter / 1000);
      unsigned long MINUTES = numberOfMinutes(counter / 1000);
      unsigned long SECONDS = numberOfSeconds(counter / 1000);
      unsigned long MILLISECONDS = (counter % 1000) / 10;

      // Convert time values to integer to display
      if (HOURS > 0) {
        // Display M:S.hs if timer is below one hour
        display.showNumberDec(HOURS, dots, true, 2, 0);
        display.showNumberDec(MINUTES, dots, true, 2, 2);
#if DIGITS == 6
        display.showNumberDec(MILLISECONDS, 0, true, 2, 4);
#endif
      }

      if (HOURS <= 0 && (MINUTES >0)) {
        // Display M:S.hs if timer is below one hour
        display.showNumberDec(MINUTES, dots, true, 2, 0);
        display.showNumberDec(SECONDS, dots, true, 2, 2);
#if DIGITS == 6
        display.showNumberDec(MILLISECONDS, dots, true, 2, 4);
#endif
      }

      else if (HOURS <= 0 && (MINUTES <=0 && (SECONDS >=0))) {
        // Display M:S.hs if timer is below one hour
        display.showNumberDec(SECONDS, dots, true, 2, 0);
        display.showNumberDec(MILLISECONDS, 0, true, 2, 2);
#if DIGITS == 6
        display.showNumberDec(MILLISECONDS, 0, true, 2, 4);
#endif
      } else {
        // Display H:M:S if timer is above one hour
        display.showNumberDec(HOURS, dots, true, 2, 0);
        display.showNumberDec(MINUTES, dots, true, 2, 2);
#if DIGITS == 6
        display.showNumberDec(SECONDS, 0, true, 2, 4);
#endif
      }
    }
  }



  unsigned char pKey = scanKeys();

    random();    

  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;
          display.clearDisplay();
          display.display();
          display.setCursor(0, 0);
          display.setTextSize(1); // Draw normal-scale text
          display.setTextColor(SSD1306_WHITE);
          display.print(F("All SWITCHES CORRECT"));
          display.setCursor(0, 20);
          display.setTextSize(1); // Draw normal-scale text
          display.setTextColor(SSD1306_WHITE);
          display.print(F("RESET AND POWERING UP"));
          display.display();          
          // Release the lock
          digitalWrite(lockPin, LOW);
          theaterChase(strip.Color(255, 255, 255), 100, 3, 5); // White, full brightness          
        }
      }
      else {
    Serial.print("             BZZZT!");
        runState = FAULT;
          display.clearDisplay();
          display.display();
          display.setCursor(0, 0);
          display.setTextSize(1); // Draw normal-scale text
          display.setTextColor(SSD1306_WHITE);
          display.print(F("OVERLOAD!!!!"));
          display.setCursor(0, 20);
          display.setTextSize(1); // Draw normal-scale text
          display.setTextColor(SSD1306_WHITE);
          display.print(F("RESET ALL SWITCHES"));
          display.display();
          delay(5000); // Pause for 5 seconds
          display.clearDisplay();
          display.display();
          display.setCursor(0, 0);
          display.setTextSize(1); // Draw normal-scale text
          display.setTextColor(SSD1306_WHITE);
          display.print(F("Throw The Switches"));
          display.setCursor(0, 20);
          display.setTextSize(1); // Draw normal-scale text
          display.setTextColor(SSD1306_WHITE);
          display.print(F("In Proper Order"));
          display.display();        
        // Sound the Buzzer
        theaterChase(strip.Color(255, 0, 0), 100, 3, 5); // RED CHASE         
        digitalWrite(lockPin2, HIGH);  
        delay (1000);
        digitalWrite(lockPin2, LOW);                  
      }
      break;
    case FAULT:
      badFlash();
      if (keysum() == 0) {
        reset();
        displayDisplay();
        runState = START;
      }
      break;
    case SUCCESS:
      reward();
      if (pKey != NOKEY) {
        newCombo0();
        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();
    digitalWrite(A0, LOW);
  }
}

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;
  digitalWrite(A1, LOW);
}

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 ? 0x000000 : 0x00ff00);
      strip.fill(tt >= nIn ? 0x000000 : 0x00ff00, combo[tt] *9, 9);
    } else {
      disaply.setPixelColor(tt, lastSwitch[tt] ? 0xff0000 : 0x000000);
      strip.fill(lastSwitch[tt] ? 0xff0000 : 0x000000, tt *9, 9);
    }
  }

  disaply.show();
  strip.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;
}



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();
}

/*
* Fills a strip with a specific color, starting at 0 and continuing
* until the entire strip is filled. Takes two arguments:
* 
*     1. the color to use in the fill
*     2. the amount of time to wait after writing each LED
*/
void colorWipe(uint32_t color, unsigned long wait) {
	for (unsigned int i = 0; i < strip.numPixels(); i++) {
		strip.setPixelColor(i, color);
		strip.show();
		delay(wait);
	}
}

/*
* Runs a marquee style "chase" sequence. Takes three arguments:
*
*     1. the color to use in the chase
*     2. the amount of time to wait between frames
*     3. the number of LEDs in each 'chase' group
*     3. the number of chases sequences to perform
*/
void theaterChase(uint32_t color, unsigned long wait, unsigned int groupSize, unsigned int numChases) {
	for (unsigned int chase = 0; chase < numChases; chase++) {
		for (unsigned int pos = 0; pos < groupSize; pos++) {
			strip.clear();  // turn off all LEDs
			for (unsigned int i = pos; i < strip.numPixels(); i += groupSize) {
				strip.setPixelColor(i, color);  // turn on the current group
			}
			strip.show();
			delay(wait);
		}
	}
}

/*
* Simple rainbow animation, iterating through all 8-bit hues. LED color changes
* based on position in the strip. Takes two arguments:
* 
*     1. the amount of time to wait between frames
*     2. the number of rainbows to loop through
*/
void rainbow(unsigned long wait, unsigned int numLoops) {
	for (unsigned int count = 0; count < numLoops; count++) {
		// iterate through all 8-bit hues, using 16-bit values for granularity
		for (unsigned long firstPixelHue = 0; firstPixelHue < 65536; firstPixelHue += 256) {
			for (unsigned int i = 0; i < strip.numPixels(); i++) {
				unsigned long pixelHue = firstPixelHue + (i * 65536UL / strip.numPixels()); // vary LED hue based on position
				strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));  // assign color, using gamma curve for a more natural look
			}
			strip.show();
			delay(wait);
		}
	}  
}

I'm not sure if it is the callout for Display and I need to call the OLED something else, but even when I did that it still gave the CLK and DIO duplicate errors.

These objects have to have different names. How else is the compiler supposed to know which you are talking about?

TM1637TinyDisplay6 display(CLK, DIO);

// and

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

There's a missing slash on line 18.

There may be more, dunno.

a7

That's what I figured, must be something else though. Now I get past the errors and it just seems to be looping, not even getting out the "hello" message.

You have made errors in accurately copying what works in examples into your code.

At least:

You need to call display1's begin() method before you can use any of its other functionality. You had no call to begin().

You need to call strip's begin() method before you can use any of its other functionality. You called clear() before begin().

The repeated H EL L was your sketch freaking out and restarting over and over, never made it out of setup.

On a tablet under the umbrella I just kept moving

for (; ; );

, a hard freeze, further along in setup() to find where it started. To freak out.

Primitive but effective.

a7

Thanks, Missed the display1 's begin ().

Ill take more stabs at it tomorrow.