29

オブジェクトのディープ クローンを作成しています。オブジェクトにはRandom.

からシードを取得することをお勧めしますRandomか? もしそうなら、どのように?はありませんRandom.getSeed()

4

7 に答える 7

20

シードを取得するより簡単な方法は、シードを生成し、それをシードとして保存することです。私はこの方法をゲームに使用していますが、プレイヤーが望むなら、まったく同じ世界を生成するオプションをプレイヤーに提供したいと考えています。そのため、最初にシードなしで Random オブジェクトを作成し、次にそのオブジェクトで乱数を生成し、それを別のランダム オブジェクトでシードとして使用します。プレイヤーがレベルのシードを必要とするときはいつでも、どこかに保存しています。デフォルトでは、ゲームはまだランダムです。

    Random rand = new Random();
    //Store a random seed
    long seed = rand.nextLong();
    //Set the Random object seed
    rand.setSeed(seed);

    //do random stuff...

    //Wonder what the seed is to reproduce something?
    System.out.println(seed);
于 2015-07-17T13:34:03.767 に答える
10

できることは、自分でシステム時間を取得し、それを乱数ジェネレーターにシードしてどこかに保存するか、後で使用できるように印刷することです。

long rgenseed = System.currentTimeMillis();
Random rgen = new Random();
rgen.setSeed(rgenseed);
System.out.println("Random number generator seed is " + rgenseed);
于 2012-06-21T19:29:30.787 に答える
8

目的によっては良い練習になります。ほとんどの場合、現在のシードを取得する必要はありません。たとえば、同じシーケンスの値を生成する 2 つの Random ジェネレーターを使用することが目的の場合、ランダム シードを取得する必要はありません。同じ (事前に設定された) シードを使用して 2 つの Random オブジェクトを作成するだけです。

Java は、Random オブジェクトからシードを取得する標準的な方法を提供していません。その数が本当に必要な場合は、回避することができます: Random オブジェクトをシリアル化し、別の Random オブジェクトを (異なるシードで) シリアル化し、これら 2 つの文字列が異なる 8 バイトを見つけ、それらの 8 バイトからシード値を取得します。

シリアル化でそれを行う方法は次のとおりです。

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Random;
public class SeedGetter {
  static long getSeed(Random random) {
    byte[] ba0, ba1, bar;
    try {
      ByteArrayOutputStream baos = new ByteArrayOutputStream(128);
      ObjectOutputStream oos = new ObjectOutputStream(baos);
      oos.writeObject(new Random(0));
      ba0 = baos.toByteArray();
      baos = new ByteArrayOutputStream(128);
      oos = new ObjectOutputStream(baos);
      oos.writeObject(new Random(-1));
      ba1 = baos.toByteArray();
      baos = new ByteArrayOutputStream(128);
      oos = new ObjectOutputStream(baos);
      oos.writeObject(random);
      bar = baos.toByteArray();
    } catch (IOException e) {
      throw new RuntimeException("IOException: " + e);
    }
    if (ba0.length != ba1.length || ba0.length != bar.length)
      throw new RuntimeException("bad serialized length");
    int i = 0;
    while (i < ba0.length && ba0[i] == ba1[i]) {
      i++;
    }
    int j = ba0.length;
    while (j > 0 && ba0[j - 1] == ba1[j - 1]) {
      j--;
    }
    if (j - i != 6)
      throw new RuntimeException("6 differing bytes not found");
    // The constant 0x5DEECE66DL is from
    // http://download.oracle.com/javase/6/docs/api/java/util/Random.html .
    return ((bar[i] & 255L) << 40 | (bar[i + 1] & 255L) << 32 |
            (bar[i + 2] & 255L) << 24 | (bar[i + 3] & 255L) << 16 |
            (bar[i + 4] & 255L) << 8 | (bar[i + 5] & 255L)) ^ 0x5DEECE66DL;
  }
  public static void main(String[] args) {
    Random random = new Random(12345);
    if (getSeed(random) != 12345)
      throw new RuntimeException("Bad1");
    random.nextInt();
    long seed = getSeed(random);
    if (seed == 12345)
      throw new RuntimeException("Bad2");
    Random random2 = new Random(seed);
    if (random.nextInt() != random2.nextInt())
      throw new RuntimeException("Bad3");
    System.out.println("getSeed OK.");
  }
}
于 2011-05-14T11:06:31.317 に答える
5

Random はランダムであることを意図しています。通常、2 つの Random で同じ数を生成するのではなく、異なる数を生成する必要があります。

シリアライゼーション/デシリアライゼーションを使用してランダムをコピーし、リフレクションを使用して「シード」フィールドを取得できます。(しかし、私はあなたがどちらかをやるべきだとは思わない)

シーケンスが重要でない限り、Random のクローンはそれ自体または任意のものであると見なすことができます。new Random()

于 2011-05-14T11:01:27.843 に答える
3

興味深いパラドックス...クローンされたRandomオブジェクトをランダムとは呼びません-回避策として、これを試すことができます:オブジェクトをクローンするときに、両方のRandomインスタンスで同じ値でシードを自分で設定できます。

于 2011-05-14T11:02:19.107 に答える
1

私がここにいる理由は、特定のプログラム実行で何が起こったかを再現する必要がある場合に備えて、シードを覚えておく必要があるからです。私が使用したコードは次のとおりです。

long seed = random.nextLong();
random.setSeed(seed);

これは求められていることではありませんが、おそらく求められていることだと思います。

于 2016-03-06T16:08:40.667 に答える