0

I'm using the random() to generate random coordinates for coins in a simple game console. The problem here is that the random() function is not generating random numbers, since the coin is at the same coordinates every single time I upload it. I am using the Adafruit GFX library with the Adafruit 1.44" Color TFT LCD Display. Here is my code (sorry, it's kind of long).

//necessary libraries
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>
//colors
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0 
#define WHITE 0xFFFF
//pins
#define TFT_CS 10
#define TFT_RST 9
#define TFT_DC 8
//joystick variables
const int VRxPin = A1;
const int VRyPin = A0;
const int SWPin = 7;
bool mov = false;
//data read from joystick pins
int x = 0;
int y = 0;
int SW = 0;
// X and Y coords for entities
int playerx = 50;
int playery = 50;
long coinx;
long coiny;
//game variables
int score = 0;
//defining the tft class
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
//useful text function
void output(char *text, int x, int y, uint16_t color, bool wrap = 0){
 tft.setCursor(x, y);
 tft.setTextColor(color);
 tft.setTextWrap(wrap);
 tft.print(text);
}
//there is probably a better way to do this but im too lazy to find it
void num_output(int text, int x, int y, uint16_t color, bool wrap = 0){
 tft.setCursor(x, y);
 tft.setTextColor(color);
 tft.setTextWrap(wrap);
 tft.print(text);
}
//clears screen
void clear() {
 tft.fillScreen(BLACK);
}
//setup (lcd init & startup screen)
void setup() {
 Serial.begin(9600);
 pinMode(SWPin,INPUT_PULLUP);
 tft.initR(INITR_GREENTAB);
 
 long coinx = random(20, 100);
 long coiny = random(20, 100);
 
 clear();
 output("RAMBUTAN", 40, 60, RED);
 delay(1000);
 clear();
 tft.fillRect(playerx, playery, 5, 5, WHITE);
 tft.fillCircle(coinx, coiny, 5, YELLOW);
}
void loop() {
 //reads data from joystick pins every single tick
 int VRx = analogRead(VRxPin);
 int VRy = analogRead(VRyPin);
 int SW = digitalRead(SWPin);
 
 //converts joystick pin data into directions
 if (VRx > 250 && VRx < 750 && VRy > 250 && VRy < 750) {
 // middle
 } else if (VRx > 511.5 && VRy < 750 && VRy > 240) {
 // right
 playery -= 5;
 mov = true;
 } else if (VRx < 511.5 && VRy < 750 && VRy > 240) {
 // left
 playery += 5;
 mov = true;
 } else if (VRy > 511.5 && VRx < 750 && VRx > 240) {
 // up
 playerx += 5;
 mov = true;
 } else if (VRy < 511.5 && VRx < 750 && VRx > 240) {
 // down
 playerx -= 5;
 mov = true;
 } else {
 mov = false;
 }
 if (mov == true) {
 clear();
 tft.fillRect(playerx, playery, 5, 5, WHITE);
 num_output(score, 10, 10, WHITE);
 tft.fillCircle(coinx, coiny, 5, YELLOW);
 mov = false;
 }
 delay(100);
}
asked Feb 18, 2021 at 20:54
4
  • Have you read the documentation to the Arduino random() function? Especially the section "Notes and Warnings"? A microcontroller cannot easily generate random numbers without a good source of randomness. Commented Feb 18, 2021 at 20:58
  • Most pseudo-random libraries (like the one in python) at least seems to be random, so I thought I could just use this :/ Commented Feb 18, 2021 at 21:00
  • The random libraries on a PC will also pull randomness/entropy from some sure. On a PC there are many factors, which could be used for that. On a microcontroller the resources are much more limited. Here you need to dedicate an analog input for that (which might or might not be acceptable for you). Commented Feb 18, 2021 at 22:31
  • 5
    Does this answer your question? Getting a truly random number in Arduino Commented Feb 18, 2021 at 23:09

2 Answers 2

1

You are correct, random() isn't random - it's pseudo random. It returns successive results from a mathematical formula which, to all intents and purposes, is random. It's also predictable, as you have seen.

The formula has a starting value, called the seed, which you can choose your self. Changing that seed gives you a different sequence of random-like numbers.

So the trick is to set the seed to something that is truly random. One common source of randomness, or entropy, is an unconnected ADC input:

randomSeed(analogRead(A3));

You can read more about the randomSeed() function here.

answered Feb 18, 2021 at 20:58
7
  • This seems to work better, but when I move, it automatically goes to the corner like it did before... I'm not sure what's happening. Commented Feb 18, 2021 at 21:07
  • @jort57 You aren't calling randomSeed() over and over again are you? You only want to call it once in setup(). Commented Feb 18, 2021 at 21:15
  • 2
    randomSeed(analogRead(A3)); is better than nothing but, in my experience, it has very little entropy (a couple of bits or so). Unless of course you connect a hardware entropy source to A3. Commented Feb 18, 2021 at 23:11
  • 1
    A trick that has worked for many of my projects requiring randomness is to include some sort of a "start" trigger. This could be a network communication response, a push button (e.g, a "go" button), or some other event that will occur at a random point in time. After observing the "start" trigger, call millis() and use the return value as the random seed. You could probably also use micros() in place of millis() if the start trigger may occur quickly (e.g. a local network communication). Commented Feb 19, 2021 at 2:02
  • .... or perform analogRead() a few times in sequence and join the last few bits of each call. Commented Feb 19, 2021 at 6:13
0

As an alternative to Majenko's answer, this is how I generate random n-bit-numbers: for each of the n bits I read the chip temperature (which is pretty noisy), take the least significant bit of the reading and assign it to the corresponding bit in the number. The results are sufficiently random for my purpose at least.

answered Feb 19, 2021 at 18:37

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.