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