📄 jcmodel.java
字号:
/*
* JCollapse - Java Collapse Game
* Copyright (C) 2005 Erico Gon鏰lves Rimoli
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package sourceforge.net.projects.jcollapse.engine;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentLinkedQueue;
import sourceforge.net.projects.jcollapse.engine.block.Block;
import sourceforge.net.projects.jcollapse.engine.board.Board;
import sourceforge.net.projects.jcollapse.engine.board.GameBoard;
/**
* This the main class model for JCollapse Game Engine.
* <p>Project started in 2005-09-25</p>
* @author erico
*/
public class JCModel {
/**
* The version of JCollapse Engine
*/
public final static String ENGINE_VERSION = "0.1.0";
private ArrayList<JCListener> m_JCListener;
private GameBoard m_GameBoard;
private ConcurrentLinkedQueue<Block> m_BlockStack;
/**
* Constructor
* @param width The horizontal blocks size (quantity of Block's in x axis)
* @param height The horizontal blocks size (quantity of Block's in y axis)
* @throws InvalidDimensionException If uset set an invalid dimension
*/
public JCModel( int width, int height ) throws InvalidDimensionException {
m_JCListener = new ArrayList<JCListener>(1);
m_BlockStack = new ConcurrentLinkedQueue<Block>();
m_GameBoard = new GameBoard( width, height );
}
/**
* The GameBoard represent base and main Board objects
* @return the GameBoard object
*/
public GameBoard getGameBoard() {
return m_GameBoard;
}
/**
* Add new Block to the Block stack
* The engine pop the first Block from stack to the board game when user call enterBlock event
* @param block The Block object
*/
public void pushBlock( Block block ) {
m_BlockStack.add( block );
}
/**
* Remove Block from stack
* @return the removed Block
*/
public Block popBlock() {
return m_BlockStack.poll();
}
/**
* Clear stack of Block's
*/
public void clearStack() {
m_BlockStack.clear();
}
/**
* Return the number of elements of stack
* @return The number of elements of stack
*/
public int countStackBlocks() {
return m_BlockStack.size();
}
/**
* This method return true when block stack has more than 0 Block's
* or when base board are full (don't care about block stack size).
* It's mean that when we don't have blocks in stack and base board are full, you can
* call rollBlock method to dispatch the base board line to the main board.
* @return true if roll Block method can be called
*/
public boolean hasBlockToRoll() {
if( m_BlockStack.size() > 0 || m_GameBoard.isBaseBoardFull() )
return true;
return false;
}
/**
* Add the JCListener
* @param jCollapseListener The JCollapse listener object
*/
public void addJCollapseListener( JCListener jCollapseListener ) {
m_JCListener.add( jCollapseListener );
}
/**
* Remove JCListener
* @param jCollapseListener The JCListener object
* @return true if event are removed
*/
public boolean removeJCollapseEvent( JCListener jCollapseListener ) {
return m_JCListener.remove( jCollapseListener );
}
/**
* Roll block from stack to the base Board
* @throws EmptyBlockStackException fired when you call this method and stack is empty
* and the base Board not full
*/
public void rollBlock() throws EmptyBlockStackException {
int bw = m_GameBoard.getBoardWidth();
int i;
boolean baseBoardFull;
//if no blocks to roll and base board are not full, fire exception
if( !hasBlockToRoll() )
throw new EmptyBlockStackException();
//if BASEBOARD is not full...
baseBoardFull = m_GameBoard.isBaseBoardFull();
if( !baseBoardFull )
for( i = bw - 1; i > 0; i-- )
m_GameBoard.getBaseBoard().moveBlock( i, i - 1 );
//if base is full, clean base and add new base row to the board
else
flushBaseBoard();
//add new bock to the boardbase block list if we have
//blocks in stack.
if( countStackBlocks() > 0 )
m_GameBoard.getBaseBoard().setBlock( 0, popBlock() );
fireBlockRolled( countStackBlocks(), baseBoardFull );
}
/**
* If base Board are full, Block's rolls to the main Board
*/
private void flushBaseBoard() {
int bw, bh, i;
assert( m_GameBoard.isBaseBoardFull() );
if( m_GameBoard.hasBlockOnTop() ) {
fireGameOver();
return;
}
bw = m_GameBoard.getBoardWidth();
bh = m_GameBoard.getBoardHeight();
for( i = bw * bh - 1; i >= bw; i-- )
m_GameBoard.getMainBoard().moveBlock( i - bw, i );
for( i = 0; i < bw; i++ )
m_GameBoard.getMainBoard().setBlock( i, m_GameBoard.getBaseBoard().getBlock( i ) );
m_GameBoard.getBaseBoard().clear();
}
private void fireGameOver() {
for( JCListener l : m_JCListener )
l.gameOver();
}
private void fireBlockRolled( int remainder, boolean isBaseBoardFull ) {
for( JCListener l : m_JCListener )
l.blockRolled( remainder, isBaseBoardFull );
}
private void fireBoardTouched( int removedBlocks, Block block ) {
for( JCListener l : m_JCListener )
l.boardTouched( removedBlocks, m_BlockStack.size(), block );
}
/**
* When user touch screen Board in position (x,y), the engine apply rule for
* touched block, then the boardTouched event are fired with the number of
* removed blocks
* @param x The x position
* @param y The y position
* @throws InvalidPositionException If position is out of Board
*/
public void touchBoard( int x, int y ) throws InvalidPositionException {
int pos;
int removedBlocks = 0;
Block block;
if( x < 0 || y < 0 ||
x >= m_GameBoard.getBoardWidth() || y >= m_GameBoard.getBoardHeight() )
throw new InvalidPositionException( "Invalid position exception: " + x + ", " + y );
pos = y * m_GameBoard.getBoardWidth() + x;
block = m_GameBoard.getMainBoard().getBlock( pos );
if( block != null ) {
removedBlocks = block.touched( x,
y,
m_GameBoard.getMainBoard() );
validBoard( m_GameBoard.getMainBoard() );
}
fireBoardTouched( removedBlocks, block );
}
/**
* When some blocks disappeared from board, we get some
* white spaces. Then, this method clean these spaces.
* It will be filled by blocks that appear in top of these spaces
* @param board the main Board object
*/
private void validBoard( Board board ) {
int bh = m_GameBoard.getBoardHeight();
for( int x = 0; x < m_GameBoard.getBoardWidth(); x++ )
for( int y = 0; y < bh; y++ )
if( board.getBlock( x, y ) == null )
for( int y1 = y + 1; y1 < bh; y1++ )
if( board.getBlock( x, y1 ) != null ) {
board.moveBlock( x, y1, x, y );
break;
}
}
/**
* Get the version of JCollapse Engine
* @return the JCollapse Engine
*/
public static String getVersion() {
return ENGINE_VERSION;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -