com.threerings.puzzle.drop.util.PieceDropper Maven / Gradle / Ivy
The newest version!
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2012 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.drop.util;
import com.samskivert.util.StringUtil;
import com.threerings.puzzle.drop.data.DropBoard;
import com.threerings.puzzle.drop.data.DropPieceCodes;
import static com.threerings.puzzle.Log.log;
/**
* Handles dropping pieces in a board.
*/
public class PieceDropper
implements DropPieceCodes
{
/**
* A class to hold information detailing the pieces to be dropped in a particular column.
*/
public static class PieceDropInfo
{
/** The starting row of the bottom piece being dropped. */
public int row;
/** The column number. */
public int col;
/** The distance to drop the pieces. */
public int dist;
/** The pieces to be dropped. */
public int[] pieces;
/**
* Constructs a piece drop info object.
*/
public PieceDropInfo (int col, int row, int dist) {
this.col = col;
this.row = row;
this.dist = dist;
}
@Override
public String toString () {
return StringUtil.fieldsToString(this);
}
}
/**
* Called to inform a drop observer that a piece has been dropped.
*/
public static interface DropObserver
{
/** Indicates that the specified piece was dropped. */
public void pieceDropped (int piece, int sx, int sy, int dx, int dy);
}
/**
* Constructs a piece dropper that uses the supplied piece drop logic to specialize itself for
* a particular puzzle.
*/
public PieceDropper (PieceDropLogic logic)
{
_logic = logic;
}
/**
* Effects any drops possible on the supplied board (modifying the board in the progress) and
* notifying the supplied drop observer of those drops.
*
* @return the number of pieces dropped.
*/
public int dropPieces (DropBoard board, DropObserver drobs)
{
int dropped = 0, bhei = board.getHeight(), bwid = board.getWidth();
for (int yy = bhei - 1; yy >= 0; yy--) {
for (int xx = 0; xx < bwid; xx++) {
dropped += dropPieces(board, xx, yy, drobs);
}
}
// if the board wants pieces to be dropped in to fill the gaps, do that now
if (_logic.boardAlwaysFilled()) {
dropped += fillBoard(board, drobs);
}
return dropped;
}
/**
* Drops new pieces onto the board to fill the gaps.
*
* @return the number of pieces dropped.
*/
public int fillBoard (DropBoard board, DropObserver drobs)
{
int dropped = 0;
int bwid = board.getWidth();
for (int xx = 0; xx < bwid; xx++) {
int dist = board.getDropDistance(xx, -1);
for (int ii = 0; ii < dist; ii++) {
int yy = (-1 - ii);
int piece = board.getNextPiece();
if (piece != PIECE_NONE) {
drop(board, piece, xx, yy, yy + dist, drobs);
dropped++;
}
}
}
return dropped;
}
/**
* Computes and effects the drop for the specified piece and any associated attached pieces.
* The supplied observer is notified of all drops.
*/
protected int dropPieces (DropBoard board, int xx, int yy, DropObserver drobs)
{
// skip empty or fixed pieces
int piece = board.getPiece(xx, yy);
if (!_logic.isDroppablePiece(piece)) {
return 0;
}
int dropped = 0;
if (_logic.isConstrainedPiece(piece)) {
// find out where this constrained block starts and ends
int start = _logic.getConstrainedEdge(board, xx, yy, LEFT);
int end = _logic.getConstrainedEdge(board, xx, yy, RIGHT);
int bwid = board.getWidth();
if (start < 0 || end >= bwid) {
log.warning("Board reported bogus constrained edge",
"x", xx, "y", yy, "start", start, "end", end);
board.dump();
start = Math.max(start, 0);
end = Math.min(end, bwid);
}
// get the smallest drop distance across all of the block columns
int dist = board.getHeight() - 1;
for (int xpos = start; xpos <= end; xpos++) {
dist = Math.min(dist, board.getDropDistance(xpos, yy));
}
if (dist == 0) {
return 0;
}
// scoot along the bottom edge of the block, noting the drop for each column
for (int xpos = start; xpos <= end; xpos++) {
piece = board.getPiece(xpos, yy);
drop(board, piece, xpos, yy, yy + dist, drobs);
dropped++;
}
} else {
// get the distance to drop the pieces
int dist = board.getDropDistance(xx, yy);
if (dist == 0) {
return 0;
}
drop(board, piece, xx, yy, yy + dist, drobs);
dropped++;
}
return dropped;
}
/** Helpy helper function. */
protected final void drop (
DropBoard board, int piece, int xx, int yy, int ty, DropObserver drobs)
{
// don't try to clear things out if we're filling in from off-board
if (yy >= 0) {
board.setPiece(xx, yy, PIECE_NONE);
}
board.setPiece(xx, ty, piece);
if (drobs != null) {
drobs.pieceDropped(piece, xx, yy, xx, ty);
}
}
/** Allows puzzle-specific customizations. */
protected PieceDropLogic _logic;
}