Random Function omitting certain numbers

That does make sense, I’ll definitely give that a go.

I had to stare at this for some time because I am more used to seeing the construct as in post #15 but, of course, it works. An array decays to a pointer to its first element so dereferencing the first element yields, in this case, a uint8_t.

I made a simple Braille trainer, that could be expanded, which might have value: https://wokwi.com/projects/428317527578434561

Very interesting code, I’m sure that I will get some inspiration from it, thank you for sharing.

i'm curious to see more complete code which provides a better idea of what the final program does or intends to do

guessing that the random value selects a braille symbol from a table indicating the 6-bit value for that symbol but unclear how the character (e.g. 'a') is input

I’m curious to exactly how the game will work.

Given the intent you’ll find plenty of volunteers here to help you write the code if needed or get ideas for making the game more fun. Don’t hesitate to ask for ideas or help.

The outcome could also go into the showcase category and give ideas and ready to make instructions for other parents in a similar situation.

this short program demonstrates the use of a table

struct Braille {
    unsigned char  sym;         // from top-left, across each row
    char           letter;
}
braille [] = {
    { 0x20, 'a' },
    { 0x28, 'b' },
    { 0x30, 'c' },
    { 0x34, 'd' },

    { 0x24, 'e' },
    { 0x38, 'f' },
    { 0x3c, 'g' },
    { 0x2c, 'h' },

    { 0x18, 'i' },
    { 0x1c, 'j' },
    { 0x22, 'k' },
    { 0x2a, 'l' },

    { 0x32, 'm' },
    { 0x36, 'n' },
    { 0x26, 'o' },
    { 0x3a, 'p' },

    { 0x3e, 'q' },
    { 0x2e, 'r' },
    { 0x1a, 's' },
    { 0x1e, 't' },

    { 0x23, 'u' },
    { 0x2b, 'v' },
    { 0x1d, 'w' },
    { 0x33, 'x' },

    { 0x37, 'y' },
    { 0x27, 'z' },
};
const int Nbraille = sizeof(braille)/sizeof(Braille);

// -----------------------------------------------------------------------------
#include <stdio.h>
void draw (
    unsigned char sym )
{
    for (int row = 0; row < 3; row++)  {
        printf ("%4s", "");
        for (int col = 0; col < 2; col++)  {
             printf ("%c", sym & 0x20 ? '*' : ' ');
             sym <<= 1;
        }
        printf ("\n");
    }
}

// -----------------------------------------------------------------------------

int main ()
{
    int cnt [100] = {};
    for (int n = 0; n < Nbraille; n++)  {
        printf ("  %c %2x\n", braille [n].letter, braille [n].sym);
        if (cnt [braille [n].sym]++)
            printf ("     dup\n");
        draw (braille [n].sym);
    }
}

output

  a 20
    *


  b 28
    *
    *

  c 30
    **


  d 34
    **
     *

  e 24
    *
     *

  f 38
    **
    *

  g 3c
    **
    **

  h 2c
    *
    **

  i 18
     *
    *

  j 1c
     *
    **

  k 22
    *

    *
  l 2a
    *
    *
    *
  m 32
    **

    *
  n 36
    **
     *
    *
  o 26
    *
     *
    *
  p 3a
    **
    *
    *
  q 3e
    **
    **
    *
  r 2e
    *
    **
    *
  s 1a
     *
    *
    *
  t 1e
     *
    **
    *
  u 23
    *

    **
  v 2b
    *
    *
    **
  w 1d
     *
    **
     *
  x 33
    **

    **
  y 37
    **
     *
    **
  z 27
    *
     *
    **

Most certainly! I have a working prototype, but I need to improve on the code and the physical game box itself, it’s not doing quite what I want it to do. I can supply photos of the game and a video of my grandson using it. I also have a document with the rules of the game. All need refining.

is it possible for me to post all that on this topic?

i'd just like to see the code, it will expose how you're thinking about the problem.

Definitely for the documentation , rules, code, etc

The video might be more touchy (usually post on YouTube and post a link here but do you want to expose your family members to the Internet ?…)

Ok, I’ll post the code here, and redo a video of the game box including the inside showing the birds nest of cables etc. I’ll do what I can with the code before posting. I won’t post the old code because it’s so untidy and unstructured, using arrays. I’ve got my mind set on using shift registers for the input and output values, so all I need do is compare a couple of variables to obtain a result. Final input value matches random number value is all that is needed to play audio track with same value. For instance for “a”, Random number given as 1, suggested audio track played 00001.mp3, final button input value= 000001, gives a correct input so a random “correct” track is sounded. BTW I have the current button presses sounding as per iPhone keypad sounds. All will be revealed when I post the video.

seems like you may be more focused on "how" to do things rather than "what".

i'm not sure what the random # selects (why would some values need to be ignored) and what the LEDs are for? what is the goal, identify a braille character similar to identifying a morse code character?

I have created a short YouTube video, which shows the game in action. This might answer a few questions for you all.

Braille Game - Demo

If necessary, I will post the complete code for this version. However, my aim, as I have said earlier, is to simplify the code using shift registers for the input and output. I will create a further video showing the inside of the console and identify the items used to construct the console.

Any feedback is appreciated.

Is there a reason why the buttons are not laid out in the same pattern as the Braille shape ?

Yes, that’s the way the braille typewriter is laid out for the visually impaired - although they use the button in the middle as a SPC Bar.

Example:

https://shop.rnib.org.uk/collections/braillers

Thank you for the explanation

The link does not work for me but I have found examples of brailers here

Thank you for the link.

i suggest you post your code.

many of us are use to seeing poorly written code to understand "what" the OP is trying to do and can often suggest much simpler and more maintainable code

Ok, no problem. When you see the code you will realise that I am using an array to match the input to the output. By using shift registers I can omit the array entirely by using just 2 variables which contain the bit patterns, one for the challenge “number” has been suggested, and one for the input, say “keyedNumbers”.

/*
Current Sketch: BrailleGameV5_3
FULLY WORKING! - NOW TIDY UP CODE

Rename Sketch to BrailleGameV10 to match new sound files
26/06/2025

Code now works - need to adjust sound volume
Code needs to be tidied up, putting functions in a different tab
Make use of Debug and Serial.print - done
Place button pressed into function - done
Make better use of arrays: States, LEDs, Buttons
Need to remove old obsolete code
Added timer routine to turn LEDs off after each turn (needs tuning)
Last tested working 15 Mar 2025
*/
#define CurrentSketch "BrailleGameV5_3"
#define SketchDate "14 Mar 2025"

#define DEBUG 0  // Set to 1 for serial print feedback

#if DEBUG == 1  // Set to 0 when not needed
#define debug(x) Serial.print(x)
#define debugln(x) Serial.println(x)
#define debugw(x) Serial.write(x)
#else
#define debug(x)
#define debugln(x)
#define debugw(x)
#endif


#include <Tone.h>
#include "Led.h"
#include "PushButton.h"
#include "SoftwareSerial.h"

SoftwareSerial Serial2(9, 10);  // RX, TX  with voltage divider pin 10

Tone freq1;
Tone freq2;

// Dial numbers 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 (To align with array 0)
const int DTMF_freq1[] = { 1209, 1336, 1477, 1209, 1336, 1477, 1209, 1336, 1477, 1336 };
const int DTMF_freq2[] = { 697, 697, 697, 770, 770, 770, 852, 852, 852, 941 };

#define LED0 A0
#define LED1 A1
#define LED2 A2
#define LED3 A3
#define LED4 A4
#define LED5 A5

#define BUTTON0 2
#define BUTTON1 3
#define BUTTON2 4
#define BUTTON3 5
#define BUTTON4 6
#define BUTTON5 7
#define BUTTON6 8

// #define busyPin 11  // Busy Feedback from Soundboard - no longer used

int delayRate = 100;  // for testing LEDs

PushButton button0(BUTTON0, true, true);  // Internal Pullup, Pullup (pin now HIGH)
PushButton button1(BUTTON1, true, true);  // Internal Pullup, Pullup
PushButton button2(BUTTON2, true, true);  // Internal Pullup, Pullup
PushButton button3(BUTTON3, true, true);  // Internal Pullup, Pullup
PushButton button4(BUTTON4, true, true);  // Internal Pullup, Pullup
PushButton button5(BUTTON5, true, true);  // Internal Pullup, Pullup
PushButton button6(BUTTON6, true, true);  // Internal Pullup, Pullup

Led ledA0(LED0);
Led ledA1(LED1);
Led ledA2(LED2);
Led ledA3(LED3);
Led ledA4(LED4);
Led ledA5(LED5);

// #############################################################
// from original sketch
// #############################################################
bool brailleButtonStates[6];  // was int

unsigned long currentMillis;
unsigned long gameMillis;
unsigned long countdownMillis;

int gameMode;
int gameTimer = 12500;  //12.5 seconds to find letter by default (to match duration of countdown track)
int chosenChar;         // initially 0
int countdownState;
int countdownTimer = 300;
int countdownTrack = 31;  // revised to allow for extra braille

int gameVolume = 27;  //volume value between 1 and 30...edit if too loud/quiet

int brailleNumLetters = 30;  //may be inscreased if numbers or other characters are added
int brailleMP3array[30][7] = {
  //6 x buttons, mp3 track number(letter)
  { 1, 0, 0, 0, 0, 0, 1 },   //a   playing track 00001
  { 1, 1, 0, 0, 0, 0, 2 },   //b   playing track 00002
  { 1, 0, 0, 1, 0, 0, 3 },   //c   playing track 00003
  { 1, 0, 0, 1, 1, 0, 4 },   //d   playing track 00004
  { 1, 0, 0, 0, 1, 0, 5 },   //e   playing track 00005
  { 1, 1, 0, 1, 0, 0, 6 },   //f   playing track 00006
  { 1, 1, 0, 1, 1, 0, 7 },   //g   playing track 00007
  { 1, 1, 0, 0, 1, 0, 8 },   //h   playing track 00008
  { 0, 1, 0, 1, 0, 0, 9 },   //i   playing track 00009
  { 0, 1, 0, 1, 1, 0, 10 },  //j   playing track 000010
  { 1, 0, 1, 0, 0, 0, 11 },  //k   playing track 000011
  { 1, 1, 1, 0, 0, 0, 12 },  //l   playing track 000012
  { 1, 0, 1, 1, 0, 0, 13 },  //m   playing track 000013
  { 1, 0, 1, 1, 1, 0, 14 },  //n   playing track 000014
  { 1, 0, 1, 0, 1, 0, 15 },  //o   playing track 000015
  { 1, 1, 1, 1, 0, 0, 16 },  //p   playing track 000016
  { 1, 1, 1, 1, 1, 0, 17 },  //q   playing track 000017
  { 1, 1, 1, 0, 1, 0, 18 },  //r   playing track 000018
  { 0, 1, 1, 1, 0, 0, 19 },  //s   playing track 000019
  { 0, 1, 1, 1, 1, 0, 20 },  //t   playing track 000020
  { 1, 0, 1, 0, 0, 1, 21 },  //u   playing track 000021
  { 1, 1, 1, 0, 0, 1, 22 },  //v   playing track 000022
  { 0, 1, 0, 1, 1, 1, 23 },  //w   playing track 000023
  { 1, 0, 1, 1, 0, 1, 24 },  //x   playing track 000024
  { 1, 0, 1, 1, 1, 1, 25 },  //y   playing track 000025
  { 1, 0, 1, 0, 1, 1, 26 },  //z   playing track 000026
  { 1, 1, 1, 1, 0, 1, 27 },  //[   playing track 000027 "AND"
  { 1, 1, 1, 1, 1, 1, 28 },  //\   playing track 000028 "FOR"
  { 1, 1, 1, 0, 1, 1, 29 },  //]   playing track 000029 "OF"
  { 0, 1, 1, 1, 0, 1, 30 }   //^   playing track 000030 "THE"
};

void setup() {

  Serial.begin(9600);
  Serial2.begin(9600);  // Start Software Serial
  debugln("Setup complete");
  debugln(CurrentSketch);
  debugln(SketchDate);

  // initialise objects:
  freq1.begin(13);  // 560 ohm resistor - resistor not used
  freq2.begin(12);  // 560 ohm resistor - resistor not used

  button0.init();  // Braille Button 1
  button1.init();  // Braille Button 2
  button2.init();  // Braille Button 3
  button3.init();  // Braille Button 4
  button4.init();  // Braille Button 5
  button5.init();  // Braille Button 6
  button6.init();  // Green Button

  ledA0.init();  // Braille LED Indicator 1
  ledA1.init();  // Braille LED Indicator 2
  ledA2.init();  // Braille LED Indicator 3
  ledA3.init();  // Braille LED Indicator 4
  ledA4.init();  // Braille LED Indicator 5
  ledA5.init();  // Braille LED Indicator 6

  // Check button sound
  chimeAll();

  // Check LEDs - Run twice to leave LEDs in the OFF state
  checkLeds();
  checkLeds();
}



void loop() {
  //int q;

  currentMillis = millis();
  randomSeed(currentMillis);  //random seed generator to randomise character sequence

  switch (gameMode) {
    case 1:  //choose letter
      debug("gameMode: ");
      debugln(gameMode);
      // randomSeed(currentMillis); //random seed generator to randomise character sequence
      // //choose a random letter (A to Carat - circumflex)
      chosenChar = random(30);
      //Start track playing here
      gameMillis = currentMillis;
      playTrack(brailleMP3array[chosenChar][6]);
      
      gameMode = 2;
      countdownState = 0;  //reset so countdown starts when letter sound has ended
      //countdownMillis = currentMillis;
      debug("Chosen Char: ");
      debugw(65 + chosenChar);  // HTML Number - &#65 = 'A'
      debugln(" ");
      delay(1500);  // 1.5 second delay to allow sound to complete (aka countdown state)
      break;

    case 2:  //wait for timer to end to read buttons
      debug("gameMode: ");
      debugln(gameMode);
      playTrack(countdownTrack);  // keeps repeating?

      brailleButtonStates[6] = 0;  // Reset Start Button to use as LED reset button

      gameMode = 3;


    case 3:
      if (currentMillis - gameMillis < gameTimer) {  //still time to choose may need for loop
        checkButtonsPressed();                       // In a loop for 12.5 seconds
      } else {
        gameMode = 4;
      }
      debug("gameMode: ");
      debugln(gameMode);

      break;


    case 4:         //did they pick correctly?
      delay(1000);  // Delay for 1 second for suspense
      debug("gameMode: ");
      debugln(gameMode);
      debug("Braille Button 0 State: ");
      debugln(brailleButtonStates[0]);
      debug("Braille Button 1 State: ");
      debugln(brailleButtonStates[1]);
      debug("Braille Button 2 State: ");
      debugln(brailleButtonStates[2]);
      debug("Braille Button 3 State: ");
      debugln(brailleButtonStates[3]);
      debug("Braille Button 4 State: ");
      debugln(brailleButtonStates[4]);
      debug("Braille Button 5 State: ");
      debugln(brailleButtonStates[5]);

      //do the buttons pressed match the braille code
      if (brailleButtonStates[0] == brailleMP3array[chosenChar][0] && brailleButtonStates[1] == brailleMP3array[chosenChar][1] && brailleButtonStates[2] == brailleMP3array[chosenChar][2] && brailleButtonStates[3] == brailleMP3array[chosenChar][3] && brailleButtonStates[4] == brailleMP3array[chosenChar][4] && brailleButtonStates[5] == brailleMP3array[chosenChar][5]) {
        //play success sound
        playTrack(random(32, 41));
        //playTrack(7);
        debugln("Success");
      } else {
        //play fail sound
        playTrack(random(42, 51));
        //playTrack(10);
        debugln("Fail");
        }
      
      gameMode = 0;
      delay(8000); // wait 8 secomds for result sound to finish before resetting LEDs
      resetLEDs();

      break;

    default:  //waiting for start button to get pressed
      debug("gameMode: ");
      debugln(gameMode);
      brailleButtonStates[6] = 0;  // Reset Start Button State
      if (button6.isPressed()) {   //start button pressed
        debugln("Start button pressed");
        resetLEDs();  // Reset LEDs and Button States
        gameMode = 1;
      }
      break;
  }
}
// === END OF LOOP ========================================
// ========================================================
void checkLeds() {
  // Toggle each LED (on or off, or off or on)
  ledA0.toggle();
  delay(delayRate);
  ledA0.toggle();
  delay(delayRate);
  ledA1.toggle();
  delay(delayRate);
  ledA1.toggle();
  delay(delayRate);
  ledA2.toggle();
  delay(delayRate);
  ledA2.toggle();
  delay(delayRate);
  ledA3.toggle();
  delay(delayRate);
  ledA3.toggle();
  delay(delayRate);
  ledA4.toggle();
  delay(delayRate);
  ledA4.toggle();
  delay(delayRate);
  ledA5.toggle();
  delay(delayRate);
  ledA5.toggle();
  delay(delayRate);

  // Toggle each LED (on or off) in sequence
  ledA0.toggle();
  delay(delayRate);
  ledA1.toggle();
  delay(delayRate);
  ledA2.toggle();
  delay(delayRate);
  ledA3.toggle();
  delay(delayRate);
  ledA4.toggle();
  delay(delayRate);
  ledA5.toggle();
  delay(delayRate);
}
// =========================================================
void chimeAll() {
  // Chime all frequencies
  int i;
  uint8_t phone_number[] = {
    0,
    1,
    2,
    3,
    4,
    5,
  };

  debug("Button numbers: ");

  for (i = 0; i < sizeof(phone_number); i++) {
    debug(phone_number[i]);
    playDTMF(phone_number[i], 500);
    delay(600);
  }
  debugln(" ");
}
// =========================================================
void playDTMF(uint8_t number, long duration) {
  freq1.play(DTMF_freq1[number], duration);
  freq2.play(DTMF_freq2[number], duration);
}
// =========================================================
void checkButtonsPressed() {
  if (button0.isPressed() && !brailleButtonStates[0]) {
    ledA0.on();
    brailleButtonStates[0] = 1;
    playDTMF(0, 500);
    debugln("Button0 is pressed");
  }

  if (button1.isPressed() && !brailleButtonStates[1]) {
    ledA1.on();
    brailleButtonStates[1] = 1;
    playDTMF(1, 500);
    debugln("Button1 is pressed");
  }

  if (button2.isPressed() && !brailleButtonStates[2]) {
    ledA2.on();
    brailleButtonStates[2] = 1;
    playDTMF(2, 500);
    debugln("Button2 is pressed");
  }

  if (button3.isPressed() && !brailleButtonStates[3]) {
    ledA3.on();
    brailleButtonStates[3] = 1;
    playDTMF(3, 500);
    debugln("Button3 is pressed");
  }

  if (button4.isPressed() && !brailleButtonStates[4]) {
    ledA4.on();
    brailleButtonStates[4] = 1;
    playDTMF(4, 500);
    debugln("Button4 is pressed");
  }

  if (button5.isPressed() && !brailleButtonStates[5]) {
    ledA5.on();
    brailleButtonStates[5] = 1;
    playDTMF(5, 500);
    debugln("Button5 is pressed");
  }

  // Reset all Button States if green button is pressed
  if (button6.isPressed() && !brailleButtonStates[6]) {
    brailleButtonStates[6] = 1;
    debugln("Button6 is pressed");

    resetLEDs();  // Resets LEDs and Button States
  }
}

///mp3 player variables and functions
byte commandLength;    //length in bytes of command being sent
byte command[6];       //array that stores the bytes of the command
int16_t checkSum = 0;  //checksum of command

void playNext() {
  command[0] = 0xAA;  //first byte says it's a command
  command[1] = 0x06;
  command[2] = 0x00;
  command[3] = 0xB0;
  commandLength = 4;
  sendCommand();
}

void playTrack(int soundTrack) {  //play a selected track
  //select track
  debug("soundTrack: ");
  debugln(soundTrack);
  command[0] = 0xAA;  //first byte says it's a command
  command[1] = 0x07;
  command[2] = 0x02;
  command[3] = (soundTrack >> 8) & 0xFF;  //snh...track HIGH bit
  command[4] = soundTrack & 0xFF;         //SNL... track low bit
  checkSum = 0;
  for (int q = 0; q < 5; q++) {
    checkSum += command[q];
  }
  command[5] = (checkSum & 0xFF);  //SM check bit... low bit of the sum of all previous values
  commandLength = 6;
  sendCommand();
}

//sets the device volume...0 - 30
void playbackVolume(int vol) {
  if (vol > 30) {  //check within limits
    vol = 30;
  }
  command[0] = 0xAA;  //first byte says it's a command
  command[1] = 0x13;
  command[2] = 0x01;
  command[3] = vol;  //volume
  checkSum = 0;
  for (int q = 0; q < 4; q++) {
    checkSum += command[q];
  }
  command[4] = (checkSum & 0xFF);  //SM check bit... low bit of the sum of all previous values
  commandLength = 5;
  sendCommand();
}

void sendCommand() {
  int q;
  for (q = 0; q < commandLength; q++) {
    Serial2.write(command[q]);
    Serial.print(command[q], HEX);
  }
  debugln("End");
}

//end mp3 player functions

void resetLEDs() {
  ledA0.off();
  ledA1.off();
  ledA2.off();
  ledA3.off();
  ledA4.off();
  ledA5.off();
  brailleButtonStates[0] = 0;
  brailleButtonStates[1] = 0;
  brailleButtonStates[2] = 0;
  brailleButtonStates[3] = 0;
  brailleButtonStates[4] = 0;
  brailleButtonStates[5] = 0;
}


Code for Led.cpp

// Led.cpp
// Implementation (what is included in the functions)
// 23 Feb 2024

#include "led.h"

Led::Led(byte pin) {
  this->pin = pin;
}

void Led::init() {
  pinMode(pin, OUTPUT);
}

void Led::init(byte defaultState) {
  init();
  if (defaultState == HIGH) {
    on();
  } else {
    off();
  }
}

void Led::on() {
  digitalWrite(pin, HIGH);
}

void Led::off() {
  digitalWrite(pin, LOW);
}

void Led::toggle() {
  digitalWrite(pin, !digitalRead(pin));
}


Led.h

// Led.h
// Interface (Class)
// 23 Feb 2024

#ifndef LED_H // Header Guard!
#define LED_H // All Uppercase

#include <arduino.h> // normally automatically included in main programme

class Led 
{
private:
  byte pin;
public:
  Led() {} // construcor do not use
  Led(byte pin); // constructor

  void init(); // initialise the pin
  void init(byte defaultState); // initialise the pin

  void on(); // function to turn on the LED
  void off(); // function to turn off the LED
  void toggle(); // function to toggle state of the LED
};

#endif


Code for PushButton.cpp

/*
PushButton.cpp (Implementation)
De-bounce function implemented
23 Feb 2024
*/

#include "PushButton.h"

PushButton::PushButton(byte pin, bool isPullUp, bool internalPullUpActivated) {
  this->pin = pin;
  this->isPullUp = isPullUp;
  this->internalPullUpActivated = internalPullUpActivated;

  lastTimeStateChanged = millis();
  debounceDelay = 50;  // 50 milliseconds
}

void PushButton::init() {
  if (isPullUp && internalPullUpActivated) {
    pinMode(pin, INPUT_PULLUP);
  } else {
    pinMode(pin, INPUT);
  }
  state = digitalRead(pin);
}

void PushButton::readState() {
  unsigned long timeNow = millis();
  if (timeNow - lastTimeStateChanged > debounceDelay) {
    byte newState = digitalRead(pin);
    if (newState != state) {
      state = newState;
      lastTimeStateChanged = timeNow;
    }
  }
}

bool PushButton::isPressed() {
  readState();
  if (isPullUp) {
    return (state == LOW);
  } else {
    return (state == HIGH);
  }
}


Code for PushButton.h

/*
PushButton.h (Interface)
De-bounce function implemented
23 Feb 2024
*/

#ifndef PUSH_BUTTON_H
#define PUSH_BUTTON_H

#include <Arduino.h>

class PushButton
{
  private:
  byte pin;
  byte state;

  bool isPullUp;
  bool internalPullUpActivated;
  unsigned long lastTimeStateChanged;
  unsigned long debounceDelay;

  void readState();

  public:
  PushButton() {} // do not use
  PushButton(byte pin, bool isPullUp, bool internalPullUpActivated);

  void init();
  
  bool isPressed();

};


#endif

Hope this helps?

thanks for posting the code.

i probably missed in the video, but how does the code know which card was selected?