Randomの状態を保存する

Randomを使ったプログラムを一時中断して、あとから再開したり、ほかのコンピュータから再開したりしたいこと、ありますよね。
そういうとき、Randomの状態を保存する必要があります。


そんなときは、とりあえずこんなメソッドを用意します。

public static byte[] getRandomState(Random r){
    try(ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos)){
        oos.writeObject(new Random(1234));//仮のランダム
        int headerSize = baos.size();
        oos.writeObject(r);
        byte[] randomInfo = Arrays.copyOfRange(baos.toByteArray(), headerSize, baos.size());
        return randomInfo;
    }catch(IOException ex){
        throw new UncheckedIOException(ex);
    }
}


こんな感じで呼び出してみますね。

Random r1 = new Random(2345);
r1.nextInt();

byte[] randomInfo = getRandomState(r1);
System.out.println(Arrays.toString(randomInfo));


こういうデータが表示されます。

[115, 113, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -17, 6, 84, -120, -9, -1, 120]

で、こんなメソッドを用意します。

public static Random getRandomFromState(byte[] state){
    try(ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos)){
        oos.writeObject(new Random(1234));
        baos.write(state);
        try(ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);){
            ois.readObject();//ランダムをひとつ捨てる
            return (Random) ois.readObject();
        }
    }catch(IOException ex){
        throw new UncheckedIOException(ex);
    } catch (ClassNotFoundException ex) {
        throw new RuntimeException(ex);
    }
}


そんで、こんなコードを実行してみます。

Random r1 = new Random(2345);
r1.nextInt();
byte[] myRandom =
    {115, 113, 0, 126,    0,  0,  0,   0,
       0,   0, 0,   0,    0,  0,  0,   0,
       0, -17, 6,  84, -120, -9, -1, 120};
Random r2 = getRandomFromState(myRandom);
System.out.println(r1.nextInt());
System.out.println(r2.nextInt());
System.out.println(r1.nextInt());
System.out.println(r2.nextInt());


再現されますね。やった!

49532468
49532468
-1883052629
-1883052629