DIY Arduino LCD-Keypad Maths Game(Mathopia)

Last updated on February 23rd, 2024 at 12:19 pm

Tutorial:

Watch this step-by-step tutorial and follow along :

Components required

  1. Keypad
Keypad
Keypad

2. Arduino UNO

Arduino Uno
Arduino Uno

3. LCD(16X2)

LCD 16x2
LCD 16×2

4. Buzzer

Buzzer
Buzzer

5. Potentiometer 10kohm

Potentiometer
Potentiometer

Circuit diagram

Circuit Diagram of Mathopia
Circuit Diagram of Mathopia

Note: This project was made in tinkered. You can copy the file and start playing with it right away(it’s free!)

TinkerCad file link: https://www.tinkercad.com/things/bdbevDoAaA1

Program

/*
 **************************************************Mathopia**********************************************************
 *  
 *      Created on: May 27, 2020
 *      Author:Ankit Negi      
 *      
 *      Youtube: www.youtube.com/theelectronicguy
 *      Website: www.eTechnophiles.com
 */

#include <LiquidCrystal.h>//LCD library
LiquidCrystal lcd(6,5,4,3,2,1);//lcd(RS,En,D4,D5,D6,D7)
#include<EEPROM.h>

//A0 pin is used to reset the board
#define PINtoRESET A0// connected to reset pin of Uno
// define inputs
#define ip_1 7
#define ip_2 8
#define ip_3 9
#define ip_4 10
// define outputs
#define op_1 11
#define op_2 12
#define op_3 13
// Buzzer
#define BUZZER A1

// variable to store random number
int randNumber = 0;

unsigned long startMillis;  //time, when a question is given
unsigned long currentMillis;//current time
const unsigned long period = 10000;// time to answer the question

// Array of questions
String problems[20] = {
  "3 X 6 + 116 =", "19 - 34 X 61= ", "100 / 25 X 25= ", "99 - 56 X 225/5", "-3 + 2x = 11", "4x + 6 = -10" , "x + 9 = 18 - 2x", "2x + 6 = 4x - 2",
  "-x-1 = 221 + 2x" , "15 + 5x = 0", "17x-12 = 114+3x", "2x-10 = 10-3x",  "12x + 60 = 144", "-10x-19 = 19-8x", "6/2 + 7 X 4 =", "4 + 82X(30/5) =",
  "3(125-?) = 3", "x% of 5=6% of 40", "616+ ? +333=255", "[6-{4-(8-6+3)}]"
};
//Array of real solutions
int solutions[20] = {
  134, -2055, 100, -2421, 7, -4, 3, 4, -74, -3, 9, 4, 7, -19, 31, 496, 124, 48, -694, 7
};

//Array to store the typed solution
char keypad[10] = {1, 10, 10, 10, 10, 10, 10, 10, 10, 10};

//solution counter to be used in various functions
int solcounter = 0;

void setup() {
  //uncomment this while uploading the code for the first time
  /*
   EEPROM.write(0,0);
   EEPROM.write(1,0);*/
   
  // if analog input pin A2 is unconnected, random analog
  // noise will cause the call to randomSeed() to generate
  // different seed numbers each time the sketch runs.
  // randomSeed() will then shuffle the random function.
  randomSeed(analogRead(A2));

  pinMode(PINtoRESET, INPUT);    // set A0 pin as input
  digitalWrite(PINtoRESET, LOW); // if set high, board will reset

  lcd.begin(16, 2);

  //set pins as output
  for (int i = op_1; i <= op_3; i++)
    pinMode(i, OUTPUT);

  //set pins as input
  pinMode(ip_1, INPUT_PULLUP);
  pinMode(ip_2, INPUT_PULLUP);
  pinMode(ip_3, INPUT_PULLUP);
  pinMode(ip_4, INPUT_PULLUP);

  initiate_Game();//  call the function to initiate game
  start_Game();// call the function for the first question
}

void loop() {

  for (int i = op_1; i <= op_3; i++)
    digitalWrite(i, HIGH);

  // start checking for the pressed button in each column one by one
  column1();

  column2();

  column3();

  // compare the time elapsed since the question is displayed
  currentMillis = millis();
  if ((currentMillis - startMillis) > period)
  { // if time elapsed is > the period specified
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Out of Time!");
    lcd.setCursor(0, 1);
    //print the user score
    lcd.print("Your Score =");
    lcd.print(solcounter);
    if(solcounter>EEPROM.read(0)){        
          EEPROM.write(0,solcounter);
    }
  
    //this code prevents program from printing the "welcoming message" for 10 consecutive resets or shut down 
    if (EEPROM.read(1)>9){  
       EEPROM.write(1,0);     
      }else{ 
        int x= EEPROM.read(1);       
        EEPROM.write(1,++x);    
      }
    
    /*
       Play this tone sequence when the answer is wrong or player is out of time
    */
    tone(BUZZER, 440, 200);
    delay(200);
    // turn off tone function for pin A2:
    noTone(BUZZER);
    tone(BUZZER, 494, 500);
    delay(500);
    // turn off tone function for pin A2:
    noTone(BUZZER);
    // play a note on pin 8 for 300 ms:
    tone(BUZZER, 523, 300);
    delay(300);

    delay(1000);
    lcd.clear();
    pinMode(PINtoRESET, OUTPUT);
  } else;
}

// function to intiate the game
void initiate_Game()
{

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Welcome to   ");
  lcd.setCursor(3, 1);
  lcd.print(" Mathopia");

  if (EEPROM.read(1)==0){
  // scroll 13 positions (string length) to the left
  // to move it offscreen left:
  for (int positionCounter = 0; positionCounter < 13; positionCounter++) {
    // scroll one position left:
    lcd.scrollDisplayLeft();
    // wait a bit:
    delay(200);
  }

  // scroll 29 positions (string length + display length) to the right
  // to move it offscreen right:
  for (int positionCounter = 0; positionCounter < 29; positionCounter++) {
    // scroll one position right:
    lcd.scrollDisplayRight();
    // wait a bit:
    delay(200);
  }

  // scroll 16 positions (display length + string length) to the left
  // to move it back to center:
  for (int positionCounter = 0; positionCounter < 16; positionCounter++) {
    // scroll one position left:
    lcd.scrollDisplayLeft();
    // wait a bit:
    delay(200);
  } 
  }
  
  lcd.setCursor(0,0);
  lcd.print("High. Score=");
  lcd.print(EEPROM.read(0));
  delay(2000);

  for (int i = op_1; i <= op_3; i++)
    digitalWrite(i, LOW);

  int w = 0, x = 0, y = 0, z = 0;
  do
  {
    w = digitalRead(ip_1);
    x = digitalRead(ip_2);
    y = digitalRead(ip_3);
    z = digitalRead(ip_4);
    lcd.setCursor(0, 0);
    lcd.print(" Press to Start");
    lcd.setCursor(0, 1);
    lcd.print("+-*");
    lcd.setCursor(13, 1);
    lcd.print("-+/");
  } while ((w == 1 && x == 1 && y == 1 && z == 1));// continue printing if button is not pressed

  // else go back to the loop
  delay(500);
}

// function to display the questions
void start_Game()
{

  lcd.clear();
  // print a random number from 0 to 20
  randNumber = random(0, 20);
  //lcd.print(problems[solcounter]);
  lcd.print(problems[randNumber]);
  lcd.setCursor(0, 1);
  startMillis = millis();

}

// function to store the typed number in an array(keypad[])
void fill_Array(int x)
{ // check for the empty element in the array
  for (int i = 1; i < 10; i++)// element 0 is reserved for the sign
  {
    if (keypad[i] == 10)
    {
      keypad[i] = x;
      i = 10;
    }
    else;
  }
}

//this function finds the last element that is stored(typed) in the keypad[] array
void find_Last_Element()
{
  int endElement = 0;
  for (int i = 1; i < 10; i++)
  {
    if (keypad[i] == 10) {
      endElement = --i;
      i = 10;
    }
    else;
  }

  check_Ans(endElement);
}
// this function checks the answer stored in array keypad[] to the real answer stored in solutions array
void check_Ans(int endElement)
{
  long int answer = 0; // initialise the answer to 0
  // for loop to copy the typed answer from typed[] array to the variable answer
  for (int i = endElement, x = 1; (i >= 1) && (x <= endElement); i--, x++)
  {
    if (x == 1) {
      answer += keypad[i];
    }
    else {
      int tempNum = 1;
      for (int y = 1; y < x; y++ )
      {
        tempNum = tempNum * 10;
      }
      answer += keypad[i] * tempNum;
    }
  }// end of for loop

  answer *= keypad[0]; // check for the sign of the entered answer

  // if else conditional statment is used to compare real answer to typed answer
  //if (answer==solutions[solcounter])
  if (answer == solutions[randNumber])
  { //if answer is correct
    lcd.setCursor(0, 1);
    lcd.print("Correct!");

    /*
      Play this tone sequence when the answer is correct
    */
    tone(BUZZER, 523, 300);
    delay(300);
    // turn off tone function for pin A2:
    noTone(BUZZER);
    tone(BUZZER, 494, 500);
    delay(500);
    // turn off tone function for pin A2:
    noTone(BUZZER);
    tone(BUZZER, 440, 200);
    delay(200);

    delay(1000);
    solcounter++;
    if (solcounter == 21) {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Congratulations!");
      lcd.setCursor(1, 3);
      lcd.print("Champion");
      /*
        Play this tone sequence after the correct answer to the last question
      */
      int x = 0;
      while (x < 4) {
        tone(BUZZER, 523, 300);
        delay(300);
        // turn off tone function for pin A2:
        noTone(BUZZER);
        tone(BUZZER, 494, 500);
        delay(500);
        // turn off tone function for pin A2:
        noTone(BUZZER);
        tone(BUZZER, 440, 200);
        delay(200);
        // turn off tone function for pin A2:
        noTone(BUZZER);
        tone(BUZZER, 494, 500);
        delay(500);
        // turn off tone function for pin A2:
        noTone(BUZZER);
        x++;
      }
      delay(2000);
      pinMode(PINtoRESET, OUTPUT);// reset the board
    }
    keypad[0] = 1;
    for (int i = 1; i < 10; i++)
    {
      keypad[i] = 10;
    }
    start_Game();// call this function to display next question
  }
  else { //if answer is incorrect
    
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Wrong Answer");
    lcd.setCursor(0, 1);
    //print the user score
    lcd.print("Your Score =");
    lcd.print(solcounter);

    //if previous high score is less than current score
    if(solcounter>EEPROM.read(0)){             
      EEPROM.write(0,solcounter);
    }

    //this code prevents program from printing the "welcoming message" for 10 consecutive resets or shut down 
    if (EEPROM.read(1)>9){  
       EEPROM.write(1,0);     
      }else{ 
        int x= EEPROM.read(1);       
        EEPROM.write(1,++x);    
      }
    
    /*
       Play this tone sequence when the answer is wrong or player is out of time
    */
    tone(BUZZER, 440, 200);
    delay(200);
    // turn off tone function for pin A2:
    noTone(BUZZER);
    tone(BUZZER, 494, 500);
    delay(500);
    // turn off tone function for pin A2:
    noTone(BUZZER);
    // play a note on pin 8 for 300 ms:
    tone(BUZZER, 523, 300);
    delay(300);

    delay(1000);
    lcd.clear();
    pinMode(PINtoRESET, OUTPUT);// reset the board
  }
}

//check for the button pressed in column 1
void column1()
{
  digitalWrite(11, LOW);
  int w = digitalRead(ip_1);
  if (w < 1) {
    delay(10);
    lcd.print("1");
    fill_Array(1);// fill the array
    tone(BUZZER, 1906, 200);
    delay(500);
  } else ;

  int x = digitalRead(ip_2);
  if (x < 1) {
    delay(10);
    lcd.print("4");
    fill_Array(4);
    tone(BUZZER, 1979, 200);
    delay(500);
  } else ;

  int y = digitalRead(ip_3);
  if (y < 1) {
    delay(10);
    lcd.print("7");
    fill_Array(7);
    tone(BUZZER, 2061, 200);
    delay(500);
  } else ;

  int z = digitalRead(ip_4);
  if (z < 1) {
    delay(10);
    lcd.print("-");
    keypad[0] = -1;
    tone(BUZZER, 2150, 200);
    delay(500);
  } else ;

  for (int i = op_1; i <= op_3; i++)
    digitalWrite(i, HIGH);
}

//check for the button pressed in column 2
void column2()
{
  digitalWrite(12, LOW);
  int w = digitalRead(ip_1);
  if (w < 1) {
    delay(10);
    lcd.print("2");
    fill_Array(2);
    tone(BUZZER, 2033, 200);
    delay(500);
  } else ;

  int x = digitalRead(ip_2);
  if (x < 1) {
    delay(10);
    lcd.print("5");
    fill_Array(5);
    tone(BUZZER, 2106, 200);
    delay(500);
  } else ;

  int y = digitalRead(ip_3);
  if (y < 1) {
    delay(10);
    lcd.print("8");
    fill_Array(8);
    tone(BUZZER, 2188, 200);
    delay(500);
  } else ;

  int z = digitalRead(ip_4);
  if (z < 1) {
    delay(10);
    lcd.print("0");
    fill_Array(0);
    tone(BUZZER, 2277, 200);
    delay(500);
  } else ;

  for (int i = op_1; i <= op_3; i++)
    digitalWrite(i, HIGH);
}

//check for the button pressed in column 3
void column3()
{
  digitalWrite(13, LOW);
  int w = digitalRead(ip_1);
  if (w < 1) {
    delay(10);
    lcd.print("3");
    fill_Array(3);
    tone(BUZZER, 2174, 200);
    delay(500);
  } else ;

  int x = digitalRead(ip_2);
  if (x < 1) {
    delay(10);
    lcd.print("6");
    fill_Array(6);
    tone(BUZZER, 2247, 200);
    delay(500);
  } else ;

  int y = digitalRead(ip_3);
  if (y < 1) {
    delay(10);
    lcd.print("9");
    fill_Array(9);
    tone(BUZZER, 2329, 200);
    delay(500);
  } else ;

  int z = digitalRead(ip_4);
  if (z < 1) {
    delay(10);
    lcd.setCursor(0, 1);
    lcd.print("                ");
    find_Last_Element();
  } else ;
}

Photo of author

Ankit Negi

I am an electrical engineer by profession who loves to tinker with electronic devices and gadgets and have been doing so for over six years now. During this period, I have made many projects and helped thousands of students through my blog and YouTube videos. I am active on Linkedin.

Leave a Comment