Hi all,
I'm using Sorbus's PRNG in the tetris game I'm writing (see his post titled Pseudo Random Number Generator in this project's Q&A folder) to pseudorandomly generate my tetris game pieces. However, when I run my code on the VM emulator, the PRNG always spits out the same number, and thus the generated game piece is always the same. Changing the seed value for the PRNG appears to make no difference; indeed, when I look at the relevant data registers in the VM emulator I can see that the PRNG always generates the same number. I assume the issue is with my code and not with Sorbus's but I am having trouble figuring out where I'm going wrong.
Here are the relevant details.
1. I have a class titled gamePiece that contains a constructor and a bunch of methods for the various tetris pieces. Here is the relevant code for that class:
class gamePiece {
field int x, y, chosenType, current_orientation;
/** constructs the active game piece */
constructor gamePiece new(int xcoord, int ycoord, int initial_orientation, int input_type) {
let x = xcoord;
let y = ycoord;
let chosenType = input_type;
let current_orientation = initial_orientation;
if (chosenType = 1) {
do drawBlock();
}
if (chosenType = 2) {
do drawLinepiece();
}
if (chosenType = 3) {
do drawLpiece();
}
if (chosenType = 4) {
do drawPyramidpiece();
}
return this;
}
[various methods]
}
2. Another class, currently titled Testgame, constructs a game piece and, ideally, uses the PRNG to pseudorandomly select the piece type. Here's the relevant code from that class:
class Testgame {
static int seed_value; //a class-level seed value. Will change throughout game so that with each new piece the seed value changes
field gamePiece game_piece; //the piece to be rotated
field int piece_type; //the type of the active game piece
field int future_orientation; //the orientation the piece changes to with previous user input
field int leftMovement, rightMovement; // indicator variables for leftward or rightward movement of the current game piece
/**sets the initial seed*/
function void initialSeed() {
let seed_value = 425;
return;
}
/** constructs a game piece for testing */
constructor Testgame new() {
do LCGRandom.setSeed(seed_value); //sets a seed value for LCGRandom to use
let piece_type = LCGRandom.randRange(1,4); //pseudo-randomly generates a number between 1 and 4, inclusive
let game_piece = gamePiece.new(242, 8, 1, piece_type);
let future_orientation = 0; //initial state is to leave orientation unchanged
let leftMovement = 0; //initial state is no lateral movement
let rightMovement = 0; //initial state is no lateral movement
return this;
}
[various methods]
}
Right now I am manually changing the variable seed_value in the Testgame class and then recompiling my game files to see whether the PRNG will actually generate different numbers. As I mentioned above, so far I haven't managed to get different numbers with different seed values.
Any insight and/or hints are much appreciated. Also, I've copied the contents of Sorbus's PRNG below for easier reference:
/* LCGRandom.jack, released under the BSD 2-Clause License, also known as Simplified BSD or FreeBSD License"
* Copyright (c) 2013, Rowan Limb
* All rights reserved.
* This software implements a PRNG based on Linear Congruential Generator (Schrage Method).
* Based on method documented here:
http://www.cems.uwe.ac.uk/~irjohnso/coursenotes/ufeen8-15-m/p1192-parkmiller.pdf * and using constants for A and M from "Tables of Linear Congruential Generators of Different Sizes and Good Lattice Structure" by Pierre L'Ecuyer, 1999 (citeseer:
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.34.1024)
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
class LCGRandom {
static int seed;
static int A;
static int M;
static int Q;
static int R;
function void setSeed(int newSeed) {
let seed = newSeed;
if(seed=0) {
let seed=1;
}
let A=219;
let M=32749;
let Q=M/A;
let R=Utils.mod(M,A);
return;
}
/* returns a random int in range 0..(M-1) inclusive */
function int rand() {
var int test;
let test=(A*(Utils.mod(seed,Q)))-(R*(seed/Q));
if(test<0) {
let seed=test+M;
}
else {
let seed=test;
}
return seed;
}
/* returns a random int in range low..high inclusive */
function int randRange(int low, int high) {
var int scale;
let scale = (M / (high - low + 1));
return (LCGRandom.rand() / scale) + low;
}
}
/* Utils.jack, released under the BSD 2-Clause License, also known as Simplified BSD or FreeBSD License"
* Copyright (c) 2013, Rowan Limb
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
class Utils {
/* returns a % b */
function int mod(int a, int b) {
var int d;
var int r;
let d = Math.divide(a,b);
let r = a - (b * d);
return r;
}
}