mercredi 16 février 2022

Java trying to reset the state of Random() [closed]

Basically my problem arises when I'm trying to run a simulation that uses pseudo-random number generation (using a seed for the Random generation). I want to run a simulation multiple times in a row with the same parameters, however, when doing so, it yields a different result everytime. Is it possible to reset the state of the Random() class everytime I run the simulation? Here's some code to illustrate the problem:

        Simulator test = new Simulator();
        test.runLongSimulation();
        test = new Simulator();
        test.runLongSimulation(); 

After the second call to the method .runLongSimulation(), the result isn't the same.

Edit: For those wondering, I have a "Randomizer" class, where I manage the pseudo random number generator. It isn't nothing special really, and I use it to populate my simulation randomly, with species of varying dimensions.

import java.util.Random;

public class Randomizer
{
    // The default seed for control of randomization.
    private static final int SEED = 1111;
    // A shared Random object, if required.
    private static final Random rand = new Random(SEED);
    // Determine whether a shared random generator is to be provided.
    private static final boolean useShared = true;

    /**
     * Constructor for objects of class Randomizer
     */
    public Randomizer()
    {
    }

    /**
     * Provide a random generator.
     * @return A random object.
     */
    public static Random getRandom()
    {
        if(useShared) {
            return rand;
        }
        else {
            return new Random();
        }
    }
    
    /**
     * Reset the randomization.
     * This will have no effect if randomization is not through
     * a shared Random generator.
     */
    public static void reset()
    {
        if(useShared) {
            rand.setSeed(SEED);
        }
    }
}

Edit 2: To answer further questions, here is the code of the Simulator() class, and I don't think any multi-threding shenanigans are going on.

import java.util.prefs.Preferences;

import java.util.Random;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.awt.Color;

public class Simulator
{
    private Preferences prefs;

    // Constants representing configuration information for the simulation.
    // The default width for the grid.
    private static final int DEFAULT_WIDTH = 120;
    // The default depth of the grid.
    private static final int DEFAULT_DEPTH = 80;
    // The probability that a fox will be created in any given grid position.
    private double FOX_CREATION_PROBABILITY = 0.015;
    // The probability that a rabbit will be created in any given grid position.
    private double RABBIT_CREATION_PROBABILITY = 0.20;  

    private double WOLF_CREATION_PROBABILITY = 0.018;  


    //0.12, 0.20
    // List of animals in the field.
    private List<Animal> animals;
    // The current state of the field.
    private Field field;
    // The current step of the simulation.
    private int step;
    // A graphical view of the simulation.
    private SimulatorView view;

    private boolean isSearching = false;
    
    /**
     * Construct a simulation field with default size.
     */
    public Simulator()
    {
        bootSimulation(DEFAULT_DEPTH, DEFAULT_WIDTH);
    }

    public Simulator(boolean isSearching){
        this.isSearching = true;
        bootSimulation(DEFAULT_DEPTH, DEFAULT_WIDTH);
    }
    
    /**
     * Create a simulation field with the given size.
     * @param depth Depth of the field. Must be greater than zero.
     * @param width Width of the field. Must be greater than zero.
     */
    public Simulator(int depth, int width)
    {
        bootSimulation(depth, width);
    }

    private void bootSimulation(int depth, int width){
        if(width <= 0 || depth <= 0) {
            System.out.println("The dimensions must be greater than zero.");
            System.out.println("Using default values.");
            depth = DEFAULT_DEPTH;
            width = DEFAULT_WIDTH;
        }
        
        animals = new ArrayList<>();
        field = new Field(depth, width);

        // Create a view of the state of each location in the field.
        view = new SimulatorView(depth, width, !isSearching);
        view.setColor(Rabbit.class, Color.ORANGE);
        view.setColor(Fox.class, Color.BLUE);
        view.setColor(Wolf.class, Color.RED);
        
        // Setup a valid starting point.
        reset();
    }
    
    /**
     * Run the simulation from its current state for a reasonably long period,
     * (4000 steps).
     */
    public void runLongSimulation()
    {
        simulate(4000);
    }
    
    /**
     * Run the simulation from its current state for the given number of steps.
     * Stop before the given number of steps if it ceases to be viable.
     * @param numSteps The number of steps to run for.
     */
    public int simulate(int numSteps)
    {
        int count = 0;
        for(int step = 1; step <= numSteps && view.isViable(field); step++) {
            simulateOneStep();
            count++;
            //delay(60);   // uncomment this to run more slowly
        }

        return count;
    }
    
    /**
     * Run the simulation from its current state for a single step.
     * Iterate over the whole field updating the state of each
     * fox and rabbit.
     */
    public void simulateOneStep()
    {
        step++;

        // Provide space for newborn animals.
        List<Animal> newAnimals = new ArrayList<>();        
        // Let all rabbits act.
        for(Iterator<Animal> it = animals.iterator(); it.hasNext(); ) {
            Animal animal = it.next();
            animal.act(newAnimals);
            if(! animal.isAlive()) {
                it.remove();
            }
        }
               
        // Add the newly born foxes and rabbits to the main lists.
        animals.addAll(newAnimals);

        view.showStatus(step, field);
    }
        
    /**
     * Reset the simulation to a starting position.
     */
    public void reset()
    {

        step = 0;
        animals.clear();
        populate();
        
        // Show the starting state in the view.
        view.showStatus(step, field);
    }
    
    /**
     * Randomly populate the field with foxes and rabbits.
     */
    private void populate()
    {
        Random rand = Randomizer.getRandom();
        field.clear();
        for(int row = 0; row < field.getDepth(); row++) {
            for(int col = 0; col < field.getWidth(); col++) {
                if(rand.nextDouble() <= FOX_CREATION_PROBABILITY) {
                    Location location = new Location(row, col);
                    Fox fox = new Fox(field, location);
                    animals.add(fox);
                }
                else if(rand.nextDouble() <= RABBIT_CREATION_PROBABILITY) {
                    Location location = new Location(row, col);
                    Rabbit rabbit = new Rabbit(field, location);
                    animals.add(rabbit);
                }else if(rand.nextDouble() <= WOLF_CREATION_PROBABILITY) {
                    Location location = new Location(row, col);
                    Wolf wolf = new Wolf(field, location);
                    animals.add(wolf);
                }
                // else leave the location empty.
            }
        }
    }
    
    /**
     * Pause for a given time.
     * @param millisec  The time to pause for, in milliseconds
     */
    private void delay(int millisec)
    {
        try {
            Thread.sleep(millisec);
        }
        catch (InterruptedException ie) {
            // wake up
        }
    }
}


Moreover, the Randomizer() class is also used in the Animals' subclasses (the Fox, Rabbit and Wolf ones)

Edit 3: Found the error, wasn't resetting the code properly, thanks to
@Petr Janeček for his response and everyone else that responded!




Aucun commentaire:

Enregistrer un commentaire