com.threerings.puzzle.data.Board Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vilya Show documentation
Show all versions of vilya Show documentation
Facilities for making networked multiplayer games.
//
// $Id: Board.java 1046 2011-01-01 05:04:14Z dhoover $
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2011 Three Rings Design, Inc., All Rights Reserved
// http://code.google.com/p/vilya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.puzzle.data;
import java.util.Random;
import com.threerings.io.Streamable;
/**
* An abstract base class for generating and storing puzzle board data.
*/
public abstract class Board
implements Cloneable, Streamable
{
/**
* Outputs a string representation of the board contents.
*/
public abstract void dump ();
/**
* Outputs a string representation of the board contents, interlaced with the supplied
* comparison board.
*/
public abstract void dumpAndCompare (Board other);
/**
* Returns whether this board is equal to the given comparison board.
*/
public abstract boolean equals (Board other);
@Override
public Board clone ()
{
try {
Board board = (Board)super.clone();
board._rando = _rando.clone();
return board;
} catch (CloneNotSupportedException cnse) {
throw new AssertionError(cnse);
}
}
/**
* Sets the seed in the board's random number generator and calls {@link #populate}.
*/
public void initializeSeed (long seed)
{
_rando = new BoardRandom(seed);
populate();
}
/**
* Returns the random number generator used by the board to generate random numbers for our
* puzzles.
*/
public Random getRandom ()
{
return _rando;
}
/**
* Called after the seed is set in the board to give derived classes a chance to do things
* like populating the board with random pieces.
*/
protected void populate ()
{
}
/**
* Allows puzzles to add extra noise to their random number generators based on the specific
* events sent from the client to make it more difficult for a hacked client to predict things
* such as piece generation.
*
* @param pidx the player index that submitted the progress event.
* @param gevent the progress event itself.
*/
public void seedFromEvent (int pidx, int gevent)
{
if (isSeedingEvent(pidx, gevent)) {
for (int ii = 0, jj = getSeedForEvent(pidx, gevent); ii < jj; ii++) {
_rando.next(0);
}
}
}
/**
* Returns whether this event is the sort of thing we should use to generate extra noise on
* our random number generator.
*/
protected boolean isSeedingEvent (int pidx, int gevent)
{
return false; // By default, nothing is
}
/**
* Returns a number of bits to read off the random number generator for this event.
* Subclasses can replace this with something that better understands the formats of its
* particular events if desired.
*/
protected int getSeedForEvent (int pidx, int gevent)
{
return (pidx ^ gevent) % 7;
}
/** Used to generate random numbers. */
protected static class BoardRandom extends Random
implements Cloneable
{
public BoardRandom (long seed) {
super(0L);
setSeed(seed);
}
@Override
public synchronized void setSeed (long seed) {
_seed = (seed ^ multiplier) & mask;
}
@Override
synchronized protected int next (int bits) {
long nextseed = (_seed * multiplier + addend) & mask;
_seed = nextseed;
return (int)(nextseed >>> (48 - bits));
}
@Override
public void nextBytes (byte[] bytes) {
unimplemented();
}
// not overridden: (They seemed innocent enough)
// nextInt()
// nextLong()
// nextBoolean()
// nextFloat()
@Override
public int nextInt (int n) {
if (n <= 0) {
throw new IllegalArgumentException("n must be positive");
}
if ((n & -n) == n) { // i.e., n is a power of 2
return (int)((n * (long)next(31)) >> 31);
}
int bits, val;
do {
bits = next(31);
val = bits % n;
} while (bits - val + (n-1) < 0);
return val;
}
@Override
public double nextDouble () {
long l = ((long)(next(26)) << 27) + next(27);
return l / (double)(1L << 53);
}
@Override
public synchronized double nextGaussian () {
if (_haveNextNextGaussian) {
_haveNextNextGaussian = false;
return _nextNextGaussian;
} else {
double v1, v2, s;
do {
v1 = 2 * nextDouble() - 1;
v2 = 2 * nextDouble() - 1;
s = v1 * v1 + v2 * v2;
} while (s >= 1 || s == 0);
double multiplier = Math.sqrt(-2 * Math.log(s)/s);
_nextNextGaussian = v2 * multiplier;
_haveNextNextGaussian = true;
return v1 * multiplier;
}
}
@Override
public BoardRandom clone () {
try {
return (BoardRandom) super.clone();
} catch (CloneNotSupportedException cnse) {
throw new AssertionError(cnse);
}
}
/**
* I suppose I could copy all the methods from Random, then we wouldn't need this..
*/
private final void unimplemented ()
{
throw new RuntimeException(
"The Random method you attempted to call has not been implemented by BoardRandom.");
}
/** The internal state related to generating random numbers. */
protected long _seed;
protected double _nextNextGaussian;
protected boolean _haveNextNextGaussian = false;
private final static long multiplier = 0x5DEECE66DL;
private final static long addend = 0xBL;
private final static long mask = (1L << 48) - 1;
}
/** The object we use to generate our random numbers. */
protected transient BoardRandom _rando;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy