-2

I'm working on a school project where I have a road in the middle of the screen with offroad on each side. I need some obstacles to just appear offroad. To make them appear on both sides, I need to generate a random number with a gap in the middle: i.e. 0-10, 30-40.

How can I accomplish this task?

Bob__
  • 12,361
  • 3
  • 28
  • 42
  • What is your question? Where is your attempt and what issues do you have with it? – UnholySheep Apr 13 '18 at 13:30
  • Show the existing code so that readers can understand what kind of value you need and how to generate it in a way that will fit into your program. – underscore_d Apr 13 '18 at 13:33
  • 2
    Please take some time to read [the help pages](http://stackoverflow.com/help), especially the sections named ["What topics can I ask about here?"](http://stackoverflow.com/help/on-topic) and ["What types of questions should I avoid asking?"](http://stackoverflow.com/help/dont-ask). Also please [take the tour](http://stackoverflow.com/tour) and [read about how to ask good questions](http://stackoverflow.com/help/how-to-ask). Lastly please learn how to create a [Minimal, Complete, and Verifiable Example](http://stackoverflow.com/help/mcve). – Some programmer dude Apr 13 '18 at 13:35
  • 1
    Possible duplicate of [How to generate a random number in C?](https://stackoverflow.com/questions/822323/how-to-generate-a-random-number-in-c) – PaulG Apr 13 '18 at 13:53
  • A more general solution is to construct the full list of numbers you're interested in, then make a random selection from the list using the standard algorithm. – Steve Summit Apr 13 '18 at 17:44
  • @SteveSummit Construct the full list ? Like if I want [0, 3], [5, 10], I create an array, populate it, and then get an valid random index ? – Tom's Apr 14 '18 at 12:19
  • @Tom's - Right. Or, the list could be a Unix pipeline. For example, I have two little utilities in [my bin directory](https://www.eskimo.com/~scs/src/) that I could combine like this: `count 0-10,30-40 | randline` – Steve Summit Apr 14 '18 at 12:40
  • @SteveSummit Well, it seem to me a really really inefficient way to do something this simple. Either you way to allocate an array, fill it, or you have to call execve/system in order to execute your command-line. In essence, you just have to do somthing really simple by adding the offset everytime it's not in the range. I will add an answer soon. – Tom's Apr 14 '18 at 12:49
  • @Tom's Don't get me wrong -- I wasn't saying your answer was wrong, or even incomplete. (I upvoted it.) Within a C program, I'd never dream of shelling out to that pair of programs. Filling an array and then randomly selecting out of it might be easier to code, especially if there were more than two subranges, although yes, it might be less efficient. – Steve Summit Apr 14 '18 at 13:12
  • The shell pipeline I showed probably wouldn't be useful for anyone here, because few people have both of those utilities, but if you *do* (and if you only need a few values), it's magnificently efficient, because you don't have to do any coding at all! It takes me just a couple of seconds to type `count 0-10,30-40 | randline`; far less than it would take anyone to code up any of this, in any language. – Steve Summit Apr 14 '18 at 13:12
  • @SteveSummit No no no, I don't say those thing for "protecting" my answer or anything like that, it's just that "A more general solution" may be risky to implement with array, because if I want [0, 1000000], [1000002], [2000000] ... well, you know what I mean. That's why it picked my curiosity an asked myself `Did I miss something or do he really wanted to malloc an array ?`. – Tom's Apr 14 '18 at 13:15
  • @Tom's No, you didn't miss anything. It's an alternative solution that I sometimes like, but no, it certainly wouldn't be a good idea all of the time. – Steve Summit Apr 14 '18 at 13:18

1 Answers1

4

You want to generate a number in [0;10] or [30;40].

[0;10] is 11 number. [30;40] is 11 number.

So you can generate a number in [0;21] (22 number to 0 from 21)

Now, if your result is in [0;10], it's good, but if your result is in [11;21] you have to add an offset in order to end in [30;40]. How can you "tranform" [11;21] in [30;40] ? By simply adding 19.


Following the discussion with SteveSummit in comment, here an general implementation of the previous algorithm :

#include <stdlib.h>
#include <stdio.h>

int GetRandomInRanges(int *ranges, size_t size)
{
  size_t nbCandidates = 0;
  size_t randomNumber;

  if (!size || size & 1) {
    printf("Error : size must be an even number strictly superior to 0, not %d.\n", size);
    exit(1);
  }
  for (size_t i = 0; i < size; i += 2) {
    if (ranges[i] > ranges[i + 1]) {
      printf("Error : ranges must be sorted : [%d, %d] is not correct.\n", ranges[i], ranges[i + 1]);
      exit(1);
    }
    nbCandidates +=  ranges[i + 1] - ranges[i] + 1;
  }

  randomNumber = (double)rand() / RAND_MAX * nbCandidates;

  for (size_t i = 0; i < size; i += 2) {
    size_t nbNumberInRange = ranges[i + 1] - ranges[i] + 1;
    if (randomNumber < nbNumberInRange) {
      return (ranges[i] + randomNumber);
    }
    randomNumber -= nbNumberInRange;
  }
  return (0); // Just for the compilator to not throw warning
}

int main(void)
{
  int    ranges[]   = {1, 3, 2, 4};
  size_t rangesSize =  sizeof(ranges)/sizeof(*ranges);

  for (size_t i = 0; i < rangesSize; i += 2)
    printf("[%d, %d] ", ranges[i], ranges[i + 1]);
  printf("\n");

  for (size_t i = 0; i < 10; ++i)
    printf("get %d\n", GetRandomInRanges(ranges, rangesSize));

  return (0);
}

I have to concede you the fact that it take me near 25minutes to do all the code (coding, testing).

Tom's
  • 2,448
  • 10
  • 22