10

I started making a project where there are goats! Yeah Goats. Currently there is only one function, when I click a goat, it create another goat in a Random position. I realized that there is a pattern of positions:

I've made red lines on patterns

Here is the code:

public class GameActivity extends Activity {

    private int[] arrGoats = new int[5];
    private RelativeLayout battlefield;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_game);

        battlefield = (RelativeLayout) findViewById(R.id.rel_battlefield);

        arrGoats[0] = R.drawable.amarelo;
        arrGoats[1] = R.drawable.azul;
        arrGoats[2] = R.drawable.branco;
        arrGoats[3] = R.drawable.verde;
        arrGoats[4] = R.drawable.vermelho;

        criarCabra(60, 100);

    }

    private void criarCabra(float x, float y) {
        int cabraImg = arrGoats[new Random().nextInt(4)];

        ImageView cabra = new ImageView(this);
        cabra.setImageResource(cabraImg);
        cabra.setX(x);
        cabra.setY(y);

        LayoutParams params = (LayoutParams) new LayoutParams(MarginLayoutParams.WRAP_CONTENT,
                MarginLayoutParams.WRAP_CONTENT);
        params.width = 150;
        params.height = 120;
        cabra.setLayoutParams(params);

        cabra.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                criarCabra(new Random().nextInt(2000), new Random().nextInt(1000));
            }
        });

        battlefield.addView(cabra);
    }
}

I would like to know why this pattern is being created although I'm using Random().NextInt() to define goats positions.

Am I crazy?

Kevin Coppock
  • 133,643
  • 45
  • 263
  • 274
Rafael
  • 3,042
  • 3
  • 20
  • 36
  • what you mean by pattern ? – Blackbelt Sep 17 '14 at 14:45
  • @blackbelt Look at the picture, the goats position is a diagonal pattern. – Rafael Sep 17 '14 at 14:47
  • 2
    Try using a single instance of Random throughout the program instead of creating a new instance every time you need a number. – Karakuri Sep 17 '14 at 14:49
  • 2
    @blackbelt There is no good reason to create these extra objects that immediately become candidates for garbage collection. – Karakuri Sep 17 '14 at 14:53
  • 1
    There is a discussion about the same http://stackoverflow.com/questions/9726991/mathrandom-aint-so-random – Kushal Sharma Sep 17 '14 at 14:54
  • @blackbelt Creating multiple instances of `Random` in quick succession will give you bizarre results like this if seeding is done via a low resolution peek at the clock, which is common to many PRNG implementations. – pjs Sep 17 '14 at 15:21
  • @pjs The random is seeded with `System.currentTimeMillis() + System.identityHashCode(this)` where `this` is the `Random` object (leading to different seed for each `Random` here). – laalto Sep 17 '14 at 15:24
  • how fast are you clicking? – cliffroot Sep 17 '14 at 15:39
  • @laalto and I'm guessing that the actual seeds being produced are close to sequential. See http://stackoverflow.com/questions/12282628/why-are-initial-random-numbers-similar-when-using-similar-seeds – pjs Sep 17 '14 at 15:39

2 Answers2

5

You are creating new instances of Random with every call to criarCabra and every invocation of onClick. Create a single static instance of Random, then re-use it.

Unless you really know what you're doing and have a very good reason to be doing it, the best practice is to only create one instance of Random per program and then poll it whenever you need additional values.

pjs
  • 18,696
  • 4
  • 27
  • 56
  • Waiting for response :D – Nabin Sep 17 '14 at 15:18
  • ... and how would creating a new random object cause the behavior seen by OP? – laalto Sep 17 '14 at 15:23
  • 2
    @laalto Via an interaction with the seeding mechanism. Java's `Random` is a linear congruential generator, those stinkers are infamous for producing collinear results when seeds are sequentially related. See the brief discussion of Marsaglia's theorem on the [LCG Wikipedia page](http://en.wikipedia.org/wiki/Linear_congruential_generator#Advantages_and_disadvantages_of_LCGs). – pjs Sep 17 '14 at 15:32
5

First, you're creating a new Random object each time. In Android, the initial seed is derived from current time and the identity hash code:

public Random() {
     // Note: Using identityHashCode() to be hermetic wrt subclasses.
     setSeed(System.currentTimeMillis() + System.identityHashCode(this));
}

For two objects created in sequence, the identity hash codes are close to each other. On my Android KitKat Dalvik VM, I get identity hash codes that differ only by 32.

The currentTimeMillis() does not provide much difference to the seeds either.

The random itself is a linear congruential generator of the form

random[i+1] = a * random[i] + b (mod c)

where random[0] is the seed and a, b and c are parameters.

Based on this answer, similar seeds indeed produce similar results in linear congruential generators:

The reason you're seeing similar initial output from nextDouble given similar seeds is that, because the computation of the next integer only involves a multiplication and addition, the magnitude of the next integer is not much affected by differences in the lower bits.

Hence, your two successively generated Randoms with default seeds will produce values that seem to be correlated and make your goats get positioned on a line.

To fix it, use the same Random object and/or a more random pseudorandom generator than a linear congruential one.

Community
  • 1
  • 1
laalto
  • 150,114
  • 66
  • 286
  • 303