Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!
The QB Box Project

The QB Box Project

Experience the perfect blend of challenge and simplicity with the QB Box, a modern take on the iconic 1978 handheld "video game." This DIY light-based game captivates your mind while keeping you engaged without overwhelming complexity. Ideal for gamers and enthusiasts who appreciate a touch of nostalgia with a contemporary twist.

You can built it on your own, buy a kit and build it, or buy the completed version.

Purchase The QB Box Kit HERE.

Purchase The QB Box Built Version HERE.


Assembly and Usage Guide:

Parts Checklist:

  • TPU Button Cover [Download]
  • PLA Enclosure [Download]
  • PLA Battery Cover [Download]
  • QB Box PCB (Printed Circuit Board)
  • Toggle Switch
  • 9 x Light Buttons
  • 9 x Resistors (1K Ohm each)
  • Buzzer
  • Connector for 9V Battery
  • 2 sets of 15-Pin Header Pins (Female and Male)
  • Arduino Nano or Nano Clone
  • Battery (9V)
QB Box Parts

Pre-Assembly Note:​

If you bought the kit from HackMakeMod, your Nano comes preloaded with the QB Box code. Otherwise, you can grab the code at the bottom of this article.

image5_1024x1024.jpg

Component Soldering:​

Begin with soldering the 9 resistors

QB Box Resistors

QB Box Resistors2




Next solder the 9 light buttons IMPORTANT: Ensure the RED paint on each button corresponds to the negative (-) marking on the PCB.

QB Box Buttons




Inspect the buttons after soldering to ensure they are all sitting straight and flush.

image6_35bc727f-69a9-4a37-9e7e-7fe3ec91d7ed_1024x1024.jpg



Carefully push both sets of the male and female header pins together.

Header Pins



Place the female headers on the PCB.

image28_1024x1024.jpg



Then place the Nano on top so the short side of the male header pins come through the holes on the Nano, making sure the USB port is facing up and toward the edge of the PCB.

image9_1024x1024.jpg



Flip the PCB over and solder the header pins to the board. You can use a rubber band to hold it in place.

image23_1024x1024.jpg



Solder the buzzer (Polarity does not matter)

image4_1024x1024.jpg



Connect the 9V battery connector, with the red wire to VCC and black wire to GND.

image10_1024x1024.jpg

Temporarily remove the Nano.

image19_1024x1024.jpg



Route the 9V connector between the header pins and reinstall the Nano ensuring the USB port is towards the edge of the PCB.

image11_1024x1024.jpg


image1_1024x1024.jpg



Initial Testing:​

Temporarily connect the battery and test each light button. (NOTE: the lights will not all come on immediately since they start in a random pattern) Disconnect the battery after testing.

image20_1024x1024.jpg


The 3D Enclosure:​

QB Box 3D Printed Enclosure

If you purchased the kit from HackMakeMod, it includes these 3D printed parts. Otherwise, If you'd like to print any of these parts yourself for any reason the STL files can be downloaded here...

Toggle Switch Installation:​

Fit the toggle switch into the larger rectangular hole in the enclosure, ensuring the conductor pins are above the Nano and the “O” marking is closest to the edge.

image30_1024x1024.jpg


image21_1024x1024.jpg




PLA Enclosure Assembly:​

Align the PCB edge (with Nano USB port) with the corresponding edge inside the PLA Main Enclosure.

image13_1024x1024.jpg




Pivot the PCB assembly down until it "clicks" into place.

image24_1024x1024.jpg




Battery Connector:​

Cut the RED wire near the top edge of the case from the PCB to the 9V connector.

image25_1024x1024.jpg




Strip a small section of these two ends. Add a little solder to the connection terminals on the switch.

image29_1024x1024.jpg



Solder these wires to the respective conductor pins on the toggle switch. Be careful to avoid melting the enclosure with the soldering iron.

image2_1024x1024.jpg



TPU Button Cover Installation:​

Flip over the enclosure and fit the TPU Button Cover over the light buttons.

image15_1024x1024.jpg



Final Connections:​

Reconnect the battery to the 9v connector and place it on the battery shelf in the enclosure.

image16_1024x1024.jpg




Closing the Enclosure:​

Secure the build by attaching the PLA Bottom Cover.

image17_1024x1024.jpg



Enjoy Your QB Box!​

Your QB Box is ready for use. Remember, patience and precision are crucial during assembly. If you encounter any issues, revisit your connections and check all your solder joints.

Power-On_1024x1024.jpg




Code:

Arduino Code:
// QB Box Magic Square V1.3
// A simple game, called Magic Square, I loved to play in the 1980s.
// This was one of multiple games availableon "Merlin The Electronic Wizard."
// https://en.wikipedia.org/wiki/Merlin_(console)
// I modified it slightly. On the original the goal was to get all lights
// lit except for the center. On my version, you must get all 9 lights to be lit.
// Enjoy! Chad Kapper / HackMakeMod 10//21
//
// V1.1
// -Added battery save timer
// -Changed Column PINs
//
// V1.2
// -Changed PINs for everything to give lights 2, 4, 5, 6, and 8 the ability to fade
//
// V1.3
// -Silent Mode (Hold button for 3 sec)
// -Changed LED Connection Order
//
// Orientation: ON/OFF Rocker Switch is the bottom
// A0 -> R1 (Keypad) Orange Solid
// A1 -> C1 (Keypad) Orange Stripe
// A2 -> R2 (Keypad) Blue Solid
// A3 -> C2 (Keypad) Blue Stripe
// A4 -> R3 (Keypad) Green Solid
// A5 -> C3 (Keypad) Green Stripe
// A6 -> NC
// A7 -> Leave open for RANDOM SEED
// 2 -> LED 7
// 3 ~> LED 4
// 4 -> LED 1
// 5 ~> LED 8
// 6 ~> LED 5
// 7 -> Not Used
// 8 -> LED 9
// 9 ~> LED 2
// 10 ~> LED 6
// 11 ~> Buzzer
// 12 -> LED 3
//
// Keep in mind the led[8] array is numbered like this because "0" is first in an array function.
// | 0 | 1 | 2 |
// | 3 | 4 | 5 |
// | 6 | 7 | 8 |

#include <Keypad.h>

char oneButton;

// Establishes the keypad...
const byte ROWS = 3;
const byte COLS = 3;
char keys[ROWS][COLS] =
{
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'}
};
byte rowPins[ROWS] = {A0, A2, A4};                                 //connect to the row pinouts of the keypad
byte colPins[COLS] = {A1, A3, A5};                                 //connect to the column pinouts of the keypad

Keypad nineSquare(makeKeymap(keys), rowPins, colPins, ROWS, COLS); //initialize an instance of class nineSquare

const int ledPin[9] = {4, 9, 12, 3, 6, 10, 2, 5, 8};  //Uses pins for the LED outputs
int led[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};  //Declares a variable for 9 LEDs
int buzzer = 11;

int moveCounter = 0;
unsigned long time;
unsigned long forgotten = 300000; //Amount of time of inactivity before sounding power save buzzer 1000 = 1 sec.
unsigned long buzDelay = 40;

//----------------------------SETUP----------------------------//
void setup()
{
 
  Serial.begin(9600);
 
  for (byte i = 0; i < 9; i = i + 1)            //A 'for loop' saves time and typing to assign values to all the arrays
  {                                             //Using the same 'i' variable to assign values on all four lines
  pinMode(ledPin[i], OUTPUT);                   //Setting pins as outputs (LOW 0v / HIGH +5v)
  digitalWrite(ledPin[i], LOW);                 //Setting pins to the OFF state.
  led[i] = LOW;                                 //Setting the LED variables to the OFF state.
  }
 
  pinMode(buzzer, OUTPUT);
  randomSeed(analogRead(A6));                   //This makes 'random' much more RANDOM
  Serial.print("Waking up...");                 //Start logging the program
 
  nineSquare.setHoldTime(3000);                 //Amount of time to activate silent mode.
 
  randomPat();                                  //Starts off the game with a random pattern.
  buTone();                                     //Cool little start tone.
}

//+++++++++++++++++++++++++++++LOOP+++++++++++++++++++++++++++++//

void loop()
{
  oneButton = nineSquare.getState();
   if (oneButton == HOLD)                        // Silent mode
  {
   buzzer = 7;
    }
 
  oneButton = nineSquare.getKey();
  if (oneButton)
  {
    moveCounter++;
    time = millis();
  }
 
  if (oneButton == '1') // makes sure a key is actually pressed, equal to (oneButton != NO_KEY)
  {
    led[0] = !led[0];
    led[1] = !led[1];
    led[3] = !led[3];
    led[4] = !led[4];
    buTone();
    printLayout();
    }
 
  if (oneButton == '2') // makes sure a key is actually pressed, equal to (oneButton != NO_KEY)
  {
    led[0] = !led[0];
    led[1] = !led[1];
    led[2] = !led[2];
    buTone();
    printLayout();
  }
 
  if (oneButton == '3') // makes sure a key is actually pressed, equal to (oneButton != NO_KEY)
  {
    led[2] = !led[2];
    led[1] = !led[1];
    led[5] = !led[5];
    led[4] = !led[4];//Invert the state of the LED then...
    buTone();
    printLayout();
    }
      if (oneButton == '4') // makes sure a key is actually pressed, equal to (oneButton != NO_KEY)
  {
    led[0] = !led[0];
    led[3] = !led[3];
    led[6] = !led[6];
    buTone();
    printLayout();
    }
 
  if (oneButton == '5') // makes sure a key is actually pressed, equal to (oneButton != NO_KEY)
  {
    led[1] = !led[1];
    led[3] = !led[3];
    led[4] = !led[4];
    led[5] = !led[5];
    led[7] = !led[7];
    buTone();
    printLayout();
  }
 
  if (oneButton == '6') // makes sure a key is actually pressed, equal to (oneButton != NO_KEY)
  {
    led[2] = !led[2];
    led[5] = !led[5];
    led[8] = !led[8];
    buTone();
    printLayout();
    }
      if (oneButton == '7') // makes sure a key is actually pressed, equal to (oneButton != NO_KEY)
  {
    led[3] = !led[3];
    led[4] = !led[4];
    led[6] = !led[6];
    led[7] = !led[7];
    buTone();
    printLayout();
    }
 
  if (oneButton == '8') // makes sure a key is actually pressed, equal to (oneButton != NO_KEY)
  {
  led[6] = !led[6];
  led[7] = !led[7];
  led[8] = !led[8];
  buTone();
  printLayout();
  }
 
  if (oneButton == '9') // makes sure a key is actually pressed, equal to (oneButton != NO_KEY)
  {
  led[4] = !led[4];
  led[5] = !led[5];
  led[7] = !led[7];
  led[8] = !led[8];
  buTone();
  printLayout();
    }
 
for (byte i = 0; i < 9; i = i + 1)            //A 'for loop' saves time and typing to assign values to all the arrays
  {
  digitalWrite(ledPin[i], led[i]);                  //Apply that state
  }
 
if (led[0] && led[1] && led[2] && led[3] && led[4] && led[5] && led[6] && led[7] && led[8])
  {
    winner();
    delay(100);
    for(int x = 0; x < 2; x++)
    {
      for(int i = 0; i < 6; i++)
      {
        tone(buzzer, 100 * i); // Send .2 KHz sound signal...
        delay(100);        // ...for 0.1 sec
        noTone(buzzer);     // Stop sound...
        for(int a = 0; a < 9; a++)
        {
          led[a] = !led[a];
          digitalWrite(ledPin[a], led[a]);
          delay(1);
        }

      }

    }
    randomPat();
    buTone();
  }
  delay(10);

  if (millis() - time > forgotten)
  {
    buTone();
  }
}

void allOFF()
{
  for(int a = 0; a < 9; a++)
  {
    led[a] = LOW;
    digitalWrite(ledPin[a], led[a]);
   }
}

void allON()
{
  for(int a = 0; a < 9; a++)
  {
    led[a] = HIGH;
    digitalWrite(ledPin[a], led[a]);
  }
}

void randomPat()
{
  Serial.print("Random: ");
  for(int a = 0; a < 9; a++)
  {
    int randy = random(2);
    led[a] = randy;
    if(randy == (led[0] && led[1] && led[2] && led[3] && led[4] && led[5] && led[6] && led[7] && led[8]))
    {
      led[8] = !led[8];
    }
    digitalWrite(ledPin[a], led[a]);
    Serial.print(randy);
  }
  Serial.println(" ");
}

void buTone()
{
    tone(buzzer, 400, 10);
    delay(10);
    tone(buzzer, 1500, 10);
    delay(10);
    tone(buzzer, 600, 30);
    delay(10);

}

void winner()
{
    tone(buzzer, 500, 10);
    delay(30);
    tone(buzzer, 700, 10);
    delay(30);
    tone(buzzer, 900, 20);
    delay(40);
    tone(buzzer, 1100, 20);
    delay(40);
    tone(buzzer, 1300, 40);
    delay(50);
    tone(buzzer, 1500, 40);
    delay(50);
    Serial.println("!!WINNER!!");
    Serial.print(moveCounter);
    Serial.println(" Moves");
    moveCounter = 0;
}

void printLayout()
{
  Serial.print("Pattern: ");
  Serial.println(oneButton);
  Serial.print(led[0]);
  Serial.print("  ");
  Serial.print(led[1]);
  Serial.print("  ");
  Serial.println(led[2]);
  Serial.print(led[3]);
  Serial.print("  ");
  Serial.print(led[4]);
  Serial.print("  ");
  Serial.println(led[5]);
  Serial.print(led[6]);
  Serial.print("  ");
  Serial.print(led[7]);
  Serial.print("  ");
  Serial.println(led[8]);
  Serial.println();
}

3D Parts:

Wiring Diagram:

QB Box Wiring Diagram


Overview and Updates:

QB Box Magic Square V1.3 is a modern twist on the 1980s "Magic Square" game from "Merlin The Electronic Wizard."

Additional Features:

  • Battery save timer (Will buzz after left unattended for 3 min)
  • Silent Mode (activated by holding a button for 3 seconds)
Gameplay: Unlike the original where the goal was to light all but the center, in this version, you aim to light all 9.


Happy building and gaming with your QB Box!
Author
HackMakeMod
Views
242
First release
Last update

Ratings

More projects from HackMakeMod

Back
Top