Electronic Puzzle Box Game
Players complete timed challenges to beat the game.
Components and supplies
Push Button
Breadboard - 400 contacts
Multicolored Dupont Wire
Box of 100 pcs M.O. 10 VAL. trimmer resistors from 500 to 1 Mohm
Arduino Nano
Panel Mount 1K potentiometer (Breadboard Friendly) - 1K Linear
matrix 4x4 keypad
LED(Light Emitting Diode) White,Green,Red,Yellow,Blue Color
Mini breadboard - White
piezo speaker
16x2 LCD display with I²C interface
Tools and machines
Soldering kit
Hot Glue Gun
Apps and platforms
tinkercad circuits
Arduino IDE
Project description
Code
Electronic Puzzle Box
cpp
1// C++ code 2// 3 4#include <Keypad.h> 5 6 7#include <LiquidCrystal_I2C.h> 8 9LiquidCrystal_I2C lcd_1(0x27, 16, 2); 10 int start = 0; 11 12 bool lose = 0; 13 14 long startMillis = millis(); 15 long currentMillis; 16 int const period = 500; 17 18 long startMillis2 = millis(); 19 long currentMillis2; 20 int const period2 = 1000; 21 22 int seconds = 59; 23 int minutes = 1; 24 25 int lives = 3; 26 int tasks = 11; 27 28 int speakerPin = 13; 29 30 int pressure = 100; 31 int buttonTimer = 0; 32 33const int buttonPin = A0; // Pin where the button is connected 34 35int potentiometerPin = A1; 36 37int lockCode; 38int lockScore = 0; 39int ledLockPin = 10; 40int lockPeriod = 2500; 41int lockDistance; 42 43int lockstartMillis = millis(); 44 45const int ROW_NUM = 4; //four rows 46const int COLUMN_NUM = 4; //four columns 47 48const int stringLength = 5; // Change this to generate a longer or shorter string 49char result[stringLength + 1]; // +1 for the null terminator 50 51const int morseSpeakerPin = 11; 52const unsigned long dotDuration = 200; // 200 ms 53const unsigned long dashDuration = 600; // 600 ms 54 55bool morseActive = false; 56unsigned long morseStartTime = 0; 57unsigned long morseDuration = 0; 58 59int startTime2 = millis(); 60 61char inputBuffer[6]; // You can adjust size as needed 62int inputIndex = 0; 63 64 65int failures = 0; 66 67int pauseCounter = 0; 68 69char keys[ROW_NUM][COLUMN_NUM] = { 70 {'1','2','3', 'A'}, 71 {'4','5','6', 'B'}, 72 {'7','8','9', 'C'}, 73 {'*','0','#', 'D'} 74}; 75 76byte pin_rows[ROW_NUM] = {9, 8, 7, 6}; //connect to the row pinouts of the keypad 77byte pin_column[COLUMN_NUM] = {5, 4, 3, 2}; //connect to the column pinouts of the keypad 78 79Keypad keypad = Keypad( makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM ); 80 81void setup() 82{ 83 lcd_1.backlight(); 84 pinMode(buttonPin, INPUT); 85 pinMode(speakerPin, OUTPUT); 86 pinMode(12, OUTPUT); 87 pinMode(potentiometerPin, INPUT); 88 pinMode(ledLockPin, OUTPUT); 89 90 randomSeed(analogRead(A3)); 91 92 lcd_1.begin(16, 2); 93 Serial.begin(9600); 94 95 lcd_1.setCursor(0, 0); 96 lcd_1.print(minutes); 97 lcd_1.print(":"); 98 lcd_1.print(seconds); 99 100 101 lcd_1.setCursor(9, 0); 102 lcd_1.print("Lives:"); 103 lcd_1.print(lives); 104 long startTime2 = millis(); 105 106 const char charset[] = "0123456789ABCD"; 107 int charsetLength = sizeof(charset) - 1; 108 109 for (int i = 0; i < stringLength; i++) { 110 int index = random(charsetLength); 111 result[i] = charset[index]; 112 } 113 114 result[stringLength] = '\0'; // Null-terminate the string 115 116 Serial.println("Generated random string:"); 117 Serial.println(result); 118 119 lockCode = random(1, 1024); 120 121 122 123 124} 125 126 127void loop() 128{ 129 130 131 while(start == 0){ 132 lcd_1.clear(); 133 lcd_1.setCursor(0,0); 134 lcd_1.print("Press button to"); 135 lcd_1.setCursor(0,1); 136 lcd_1.print("start."); 137 delay(100); 138 lcd_1.clear(); 139 int reading = digitalRead(buttonPin); 140 if(reading== HIGH){ 141 start++; 142 } 143 } 144 145 146 for(int i = 0; i < stringLength; i++){ 147 if(result[i] == 'A'){ 148 morseDot(); 149 morseDash(); 150 nonDelay(); 151 nonDelay(); 152 } 153 if(result[i] == 'B'){ 154 morseDash(); 155 morseDot(); 156 morseDot(); 157 morseDot(); 158 nonDelay(); 159 nonDelay(); 160 } 161 if(result[i] == 'C'){ 162 morseDash(); 163 morseDot(); 164 morseDash(); 165 morseDot(); 166 nonDelay(); 167 nonDelay(); 168 } 169 if(result[i] == 'D'){ 170 morseDash(); 171 morseDot(); 172 morseDot(); 173 nonDelay(); 174 nonDelay(); 175 } 176 if(result[i] == '0'){ 177 morseDash(); 178 morseDash(); 179 morseDash(); 180 morseDash(); 181 morseDash(); 182 nonDelay(); 183 nonDelay(); 184 } 185 if(result[i] == '1'){ 186 morseDot(); 187 morseDash(); 188 morseDash(); 189 morseDash(); 190 morseDash(); 191 nonDelay(); 192 nonDelay(); 193 } 194 if(result[i] == '2'){ 195 morseDot(); 196 morseDot(); 197 morseDash(); 198 morseDash(); 199 morseDash(); 200 nonDelay(); 201 nonDelay(); 202 } 203 if(result[i] == '3'){ 204 morseDot(); 205 morseDot(); 206 morseDot(); 207 morseDash(); 208 morseDash(); 209 nonDelay(); 210 nonDelay(); 211 } 212 if(result[i] == '4'){ 213 morseDot(); 214 morseDot(); 215 morseDot(); 216 morseDot(); 217 morseDash(); 218 nonDelay(); 219 nonDelay(); 220 } 221 if(result[i] == '5'){ 222 morseDot(); 223 morseDot(); 224 morseDot(); 225 morseDot(); 226 morseDot(); 227 nonDelay(); 228 nonDelay(); 229 } 230 if(result[i] == '6'){ 231 morseDash(); 232 morseDot(); 233 morseDot(); 234 morseDot(); 235 morseDot(); 236 nonDelay(); 237 nonDelay(); 238 } 239 if(result[i] == '7'){ 240 morseDash(); 241 morseDash(); 242 morseDot(); 243 morseDot(); 244 morseDot(); 245 nonDelay(); 246 nonDelay(); 247 } 248 if(result[i] == '8'){ 249 morseDash(); 250 morseDash(); 251 morseDash(); 252 morseDot(); 253 morseDot(); 254 nonDelay(); 255 nonDelay(); 256 } 257 if(result[i] == '9'){ 258 morseDash(); 259 morseDash(); 260 morseDash(); 261 morseDash(); 262 morseDot(); 263 nonDelay(); 264 nonDelay(); 265 } 266 267 pauseCounter++; 268 Serial.println(pauseCounter); 269 270 if(pauseCounter >= 5){ 271 nonDelay(); 272 nonDelay(); 273 nonDelay(); 274 pauseCounter = 0; 275 } 276 277 278 } 279} 280 281void morseDot() { 282 tone(morseSpeakerPin, 440, 200); 283 nonDelay(); 284} 285 286void morseDash() { 287 tone(morseSpeakerPin, 220, 400); 288 nonDelay(); 289} 290 291void nonDelay() { 292 293 294 if(tasks == 0){ 295 296 lcd_1.clear(); 297 lcd_1.print("Bomb defused!"); 298 delay(500); 299 300 while(tasks == 0){ 301 302 int reading = digitalRead(buttonPin); 303 if(reading == HIGH){ 304 305 randomSeed(analogRead(A3)); 306 307 minutes= 1; 308 seconds =59; 309 lives = 3; 310 pressure = 100; 311 tasks = 11; 312 lockScore = 0; 313 314 lcd_1.clear(); 315 lcd_1.setCursor(0, 0); 316 lcd_1.print(minutes); 317 lcd_1.print(":"); 318 319 lcd_1.print(seconds); 320 321 322 lcd_1.setCursor(9, 0); 323 lcd_1.print("Lives:"); 324 lcd_1.print(lives); 325 long startTime2 = millis(); 326 327 const char charset[] = "0123456789ABCD"; 328 int charsetLength = sizeof(charset) - 1; 329 330 for (int i = 0; i < stringLength; i++) { 331 int index = random(charsetLength); 332 result[i] = charset[index]; 333 } 334 335 result[stringLength] = '\0'; // Null-terminate the string 336 337 Serial.println("Generated random string:"); 338 Serial.println(result); 339 340 lockCode = random(1, 1024); 341 } 342 } 343 344 } 345 346 if(lose==1){ 347 lcd_1.clear(); 348 lcd_1.print("You blew up!"); 349 lcd_1.setCursor(0,1); 350 lcd_1.print("Restart?"); 351 352 while(lose == 1){ 353 int reading = digitalRead(buttonPin); 354 if(reading == HIGH){ 355 lose = 0; 356 randomSeed(analogRead(A3)); 357 358 minutes= 1; 359 seconds =59; 360 lives = 3; 361 pressure = 100; 362 tasks = 11; 363 lockScore = 0; 364 365 lcd_1.clear(); 366 lcd_1.setCursor(0, 0); 367 lcd_1.print(minutes); 368 lcd_1.print(":"); 369 370 lcd_1.print(seconds); 371 372 373 lcd_1.setCursor(9, 0); 374 lcd_1.print("Lives:"); 375 lcd_1.print(lives); 376 long startTime2 = millis(); 377 378 const char charset[] = "0123456789ABCD"; 379 int charsetLength = sizeof(charset) - 1; 380 381 for (int i = 0; i < stringLength; i++) { 382 int index = random(charsetLength); 383 result[i] = charset[index]; 384 } 385 386 result[stringLength] = '\0'; // Null-terminate the string 387 388 Serial.println("Generated random string:"); 389 Serial.println(result); 390 391 lockCode = random(1, 1024); 392 } 393 } 394 } 395 396 if(lives == 0){ 397 lose=1; 398 } 399 400 if(pressure>=1000){ 401 lose=1; 402 } 403 404 if(pressure<=0){ 405 lose=1; 406 delay(500); 407 } 408 409 currentMillis2 = millis(); 410 if (currentMillis2 - startMillis2 >= period2) //test whether the period has elapsed 411 { 412 seconds = seconds - 1; 413 lcd_1.setCursor(0,0); 414 lcd_1.print(minutes); 415 lcd_1.print(":"); 416 if(seconds < 10){ 417 lcd_1.print("0"); 418 } 419 lcd_1.print(seconds); 420 startMillis2 = currentMillis2; 421 422 if(seconds == 0){ 423 minutes--; 424 seconds=60; 425 } 426 } 427 428 lcd_1.setCursor(9, 0); 429 lcd_1.print("Lives:"); 430 lcd_1.print(lives); 431 432 currentMillis = millis(); //get the current "time" (actually the number of milliseconds since the program started) 433 if (currentMillis - startMillis >= period) //test whether the period has elapsed 434 { 435 digitalWrite(speakerPin, !digitalRead(speakerPin)); //if so, change the state of the LED. Uses a neat trick to change the state 436 startMillis = currentMillis; //IMPORTANT to save the start time of the current LED state. 437 } 438 439 440 unsigned long waitTime = 600; 441 unsigned long startTime = millis(); 442 443 444 445 446 //Serial.println(lockScore); 447 //Serial.println(lockDistance); 448 449 450 lcd_1.setCursor(9,1); 451 452 lcd_1.print("Mod:"); 453 lcd_1.print(tasks); 454 455 if(tasks<10){ 456 lcd_1.setCursor(14, 1); 457 lcd_1.print(" "); 458 } 459 460 lcd_1.setCursor(0,1); 461 lcd_1.print("Pres:"); 462 463 lcd_1.print(pressure); 464 if(pressure < 100){ 465 lcd_1.setCursor(7,1); 466 lcd_1.print(" "); 467 } 468 if(pressure < 10){ 469 lcd_1.setCursor(6,1); 470 lcd_1.print(" "); 471 } 472 473 while (millis() - startTime < waitTime) { 474 int lockInput = analogRead(potentiometerPin); 475 int lockDistance = abs(lockCode-lockInput); 476 int brightness = (1024 - lockDistance); 477 478 479 if(minutes<0){ 480 lose=1; 481 } 482 483 brightness = map(brightness, 0, 1024, 0, 255); 484 485 analogWrite(ledLockPin, brightness); 486 487 488 if(lockDistance <= 100){ 489 int lockcurrentMillis = millis(); 490 491 if(lockcurrentMillis - lockstartMillis >= lockPeriod){ 492 if (lockScore <10){ 493 lockScore++; 494 tasks--; 495 } 496 lockCode = random(1, 1024); 497 lockstartMillis = lockcurrentMillis; 498 } 499 } 500 501 502 int reading = digitalRead(buttonPin); 503 //Serial.println(reading); 504 505 506static unsigned long lastPressureInc = 0; 507static unsigned long lastPressureDec = 0; 508 509unsigned long now = millis(); 510 511if (reading == HIGH) { 512 if (now - lastPressureDec >= 20) { // e.g., reduce pressure once per second while held 513 pressure--; 514 lastPressureDec = now; 515 } 516} else { 517 if (now - lastPressureInc >= 30) { // e.g., increase pressure every 2 sec if not pressed 518 pressure++; 519 lastPressureInc = now; 520 } 521} 522 523 524 char key = keypad.getKey(); // non-blocking read 525 if (key) { 526 //Serial.print("Interrupt Key Pressed: "); 527 528 529 //Serial.println(key); 530 531 532 533 if (inputIndex < sizeof(inputBuffer) - 1) { // prevent overflow 534 inputBuffer[inputIndex++] = key; 535 inputBuffer[inputIndex] = '\0'; // keep string null-terminated 536 Serial.print("Current input buffer: "); 537 Serial.println(inputBuffer); 538 lcd_1.clear(); 539 lcd_1.print(inputBuffer); 540 delay(500); 541 lcd_1.clear(); 542 543 if (inputIndex == stringLength) { // Only check after full code entered 544 if (strcmp(inputBuffer, result) == 0) { 545 // Correct code 546 tasks--; 547 lcd_1.clear(); 548 lcd_1.setCursor(0, 0); 549 lcd_1.print("Correct Code!"); 550 delay(300); 551 lcd_1.clear(); 552 lcd_1.setCursor(0,0); 553 lcd_1.print(minutes); 554 lcd_1.print(":"); 555 if(seconds < 10){ 556 lcd_1.print("0"); 557 } 558 lcd_1.print(seconds); 559 560 } else { 561 // Incorrect code 562 lives--; 563 lcd_1.clear(); 564 lcd_1.setCursor(0, 0); 565 lcd_1.print("Wrong Code!"); 566 delay(300); 567 lcd_1.clear(); 568 lcd_1.setCursor(0,0); 569 lcd_1.print(minutes); 570 lcd_1.print(":"); 571 if(seconds < 10){ 572 lcd_1.print("0"); 573 } 574 lcd_1.print(seconds); 575 } 576 577 // Clear buffer for next attempt 578 inputIndex = 0; 579 inputBuffer[0] = '\0'; 580 } 581} 582 583 } 584 } 585}
Documentation
Circuit Schematic
Screenshot 2025-06-15 175239.png

Front side
The screw is used to hold the top panel in place.
IMG_7195.jpeg

Inside the box
IMG_7201.jpeg

Top side
The LCD and top is held by zip ties.
IMG_7198.jpeg

Wired up Arduino
IMG_7209.jpeg

Video
IMG_7217.mov
Comments
Only logged in users can leave comments