// https://wokwi.com/projects/374394134602244097
// https://forum.arduino.cc/t/cutting-wires-in-sequence-out-of-sequence/1162990
/**
* "Cut The Wires" defuse bomb puzzle
*
* Players must "cut" the correct wires in order(via releasing alligator clips) to stop
* the ticking clock. If the clock reaches zero (after 60 minutes), the bomb "explodes"
* with sound effects. If wires are "cut" out of order, the ticking will get faster.
*/
#define DEBUG
// CONSTANTS
const byte numWires = 5;
const int wirePins[numWires] = {2, 3, 4, 5, 6};
// Define the number of steps in the sequence that the player must follow
// GLOBALS
int lastState[numWires];
// What is the order in which wires need to be cut
// 0 indicates the wire should not be cut
int wiresToCut[numWires] = {0, 1, 2, 3, 4}; // (blue, red, yellow, green)
byte wiresCutCounter = 1;
// Keep track of the current state of the device
enum State {Inactive, Active, Defused, Exploded};
State state = State::Inactive;
//This is the timestamp at which the bomb will detonate
//It is calculated by adding on the specified number of minutes in the game time
// to the value of millis() when the code is initialised.
unsigned long detonationTime;
//The game length (in minutes)
int gameDuration = 60;
void Activate() {
state = State::Active;
// Set the detonation time to the appropriate time in the future
// detonationTime = millis() + (unsigned long)gameDuration*60*1000;
detonationTime = millis() + 30000; // twenty-five seconds
Serial.println("Bomb activated!");
}
void Deactivate() {
state = State::Inactive;
Serial.println("inactive. is that mean dead now until reset?");
}
void Detonate() {
state = State::Exploded;
}
void setup() {
Serial.begin(9600);
Serial.println("restarted\n\n");
// Initialise wire pins
for(int i=0; i<numWires; i++) {
pinMode(wirePins[i], INPUT_PULLUP);
lastState[i] = digitalRead(wirePins[i]);
}
// Set the detonation time to the appropriate time in the future
detonationTime = millis() + (unsigned long)gameDuration*60*1000;
// Print the initial state of the wires
for(int i=0; i<numWires; i++) {
Serial.println(F("Wire "));
Serial.print(i);
Serial.println(digitalRead(wirePins[i])? " Unconnected" : " Connected");
}
// Arm the bomb!
Activate();
};
void loop() {
delay(25); // was there a bouncing problem? this killed it if there was
// First, see if any of the wires have been recently cut
for(int i=0; i<numWires; i++) {
// If the previous reading was LOW, but now it's HIGH, that means this wire must have been cut
if(digitalRead(wirePins[i]) == HIGH && lastState[i] == LOW) {
Serial.println("Wire ");
Serial.print(i);
Serial.println(" cut");
lastState[i] = HIGH;
// Was this the correct wire to cut?
if(wiresCutCounter == wiresToCut[i]) {
// Go on to the next counter
wiresCutCounter++;
}
// Incorrect wire cut
else {
// Play faster ticking sound effect
Serial.println(" WRONG WIRE");
}
}
// If the previous reading was LOW, but now it's HIGH, that means this wire must just have been cut
else if(digitalRead(wirePins[i]) == LOW && lastState[i] == HIGH) {
Serial.println(" Wire ");
Serial.println(i);
Serial.println( " reconnected");
lastState[i] = LOW;
}
}
// Now, test the current state of all wires against the solution state
//First, assume that the correct wires have all been cut
bool allWiresCut = true;
// Then, loop over the wires array
for(int i=0; i<numWires; i++) {
// Every wire that has a number > 0 in the wiresToCut array should be cut (at some point), after which they will read HIGH,
// So if any of them still read LOW, that means that there is at least one wire still to be cut
if (wiresToCut[i] !=0 && lastState[i] == LOW) {
allWiresCut = false;
}
}
// What to do next depends on the current state of the device
if(state == State::Active) {
// Retrieve the current timestamp
unsigned long currentTime = millis();
if(currentTime > detonationTime) {
Detonate();
Serial.println("time is up, so BOOM!");
}
else if(allWiresCut == true ) {
Deactivate();
Serial.println("Bomb defused!");
}
else {
}
}
}