Class TetrisGame
- All Implemented Interfaces:
GameControls, PropertyChangeEnabledGameControls
This class implements PropertyChangeEnabledGameControls, providing access to
all game controls (movement, rotation, pause, etc.) and firing GameEvent notifications
when the game state changes. Register PropertyChangeListeners to receive
these events and update your user interface accordingly.
Singleton Pattern
Important: This class enforces a singleton pattern - only one instance
of TetrisGame can exist at a time. Attempting to create a second instance will throw
an IllegalStateException. This design ensures a single source of truth for the game
state and simplifies event management.
Basic Usage
// Create the game (only once in your application)
TetrisGame game = new TetrisGame();
// Register listeners to receive game events
game.addPropertyChangeListener(evt -> {
// Handle game events here
});
// Start the game
game.newGame();
// Control the game
game.step(); // Advance one step (typically called by a timer)
game.left(); // Move piece left
game.rotateCW(); // Rotate clockwise
Important Implementation Details
- Default board size: 10 columns × 20 rows
- Frozen blocks: This implementation uses
nullto represent empty spaces in the frozen blocks collection - Coordinate system: (0, 0) is bottom-left; positive x moves right, positive y moves up
- Initial state: Game starts in
GameState.OVER. CallnewGame()before playing
See the package documentation for a complete getting started guide with more examples.
- Version:
- Autumn 2025
- Author:
- Charles Bryan, Alan Fowler
- See Also:
-
Nested Class Summary
Nested classes/interfaces inherited from interface GameControls
GameControls.Block, GameControls.FrozenBlocks, GameControls.GameState, GameControls.IndividualPiece, GameControls.Point -
Constructor Summary
ConstructorsConstructorDescriptionCreates a standard size Tetris game board (10 columns × 20 rows).TetrisGame(int theWidth, int theHeight) Creates a custom size Tetris game board. -
Method Summary
Modifier and TypeMethodDescriptionvoidaddPropertyChangeListener(PropertyChangeListener theListener) Add a PropertyChangeListener to the listener list.voidaddPropertyChangeListener(String thePropertyName, PropertyChangeListener theListener) Add a PropertyChangeListener for a specific property.voiddown()Try to move the movable piece down.voiddrop()Drop the movable piece until it is set.voidendGame()Places the game inGameState.OVER.voidleft()Try to move the movable piece left.voidnewGame()Places the game inGameState.NEWfollowed by placing the game intoGameState.RUNNING.voidpause()Places the game intoGameState.PAUSED.voidremovePropertyChangeListener(PropertyChangeListener theListener) Remove a PropertyChangeListener from the listener list.voidremovePropertyChangeListener(String thePropertyName, PropertyChangeListener theListener) Remove a PropertyChangeListener for a specific property.voidright()Try to move the movable piece right.voidTry to rotate the movable piece in the counter-clockwise direction.voidrotateCW()Try to rotate the movable piece in the clockwise direction.voidstep()Advances the game by one 'step'.voidToggles the game into eitherGameState.RUNNINGorGameState.PAUSED.toString()voidunPause()Places the game intoGameState.RUNNING.
-
Constructor Details
-
TetrisGame
public TetrisGame()Creates a standard size Tetris game board (10 columns × 20 rows).Singleton Restriction: Only one
TetrisGameinstance may exist at a time. If you attempt to create a second instance before the first is garbage collected, this constructor will throw anIllegalStateException. This restriction exists to maintain a single source of truth for game state.After construction, the game is in
GameState.OVER. CallnewGame()to initialize and start playing.- Throws:
IllegalStateException- if a TetrisGame instance has already been created
-
TetrisGame
public TetrisGame(int theWidth, int theHeight) Creates a custom size Tetris game board.Singleton Restriction: Only one
TetrisGameinstance may exist at a time. If you attempt to create a second instance before the first is garbage collected, this constructor will throw anIllegalStateException. This restriction exists to maintain a single source of truth for game state.After construction, the game is in
GameState.OVER. CallnewGame()to initialize and start playing.- Parameters:
theWidth- width of the Tetris game board (number of columns)theHeight- height of the Tetris game board (number of rows)- Throws:
IllegalStateException- if a TetrisGame instance has already been created
-
-
Method Details
-
newGame
public void newGame()Places the game inGameState.NEWfollowed by placing the game intoGameState.RUNNING. This method must be called before the first game and before each new game. No restriction on the current GameState is enforced.When this action is performed, all interested parties will be notified of the action via the following GameEvents in the following order:
GameEvent.GameStateChangedGameState.NEW
GameEvent.NextPieceChanged- A new "next" movable piece to display
GameEvent.CurrentPieceChanged- A new movable piece to display
GameEvent.FrozenBlocksChanged- An empty collection of frozen blocks
- Note: This implementation uses
nullto represent empty blocks.
GameEvent.GameStateChangedGameState.RUNNING
- Specified by:
newGamein interfaceGameControls
-
endGame
public void endGame()Places the game inGameState.OVER. The game must be inGameState.PAUSEDorGameState.RUNNINGfor this action to have an effect.When this action is performed, all interested parties will be notified of the action via the following GameEvents:
GameEvent.GameStateChangedGameState.OVER
- Specified by:
endGamein interfaceGameControls
-
pause
public void pause()Places the game intoGameState.PAUSED. The game must be inGameState.RUNNINGfor this action to have an effect.If this action is performed, all interested parties will be notified of the action via the following GameEvents:
GameEvent.GameStateChangedGameState.PAUSED
- Specified by:
pausein interfaceGameControls
-
unPause
public void unPause()Places the game intoGameState.RUNNING. The game must be inGameState.PAUSEDfor this action to have an effect.If this action is performed, all interested parties will be notified of the action via the following GameEvents:
GameEvent.GameStateChangedGameState.RUNNING
- Specified by:
unPausein interfaceGameControls
-
togglePause
public void togglePause()Toggles the game into eitherGameState.RUNNINGorGameState.PAUSED. More formally, if the game is inGameState.PAUSEDthis action places the game intoGameState.RUNNINGand if the game is inGameState.RUNNING, this action places the game inGameState.PAUSED. The game must be inGameState.PAUSEDorGameState.RUNNINGfor this action to have an effect.If this action is performed, all interested parties will be notified of the action via the following GameEvents:
GameEvent.GameStateChangedGameState.RUNNINGORGameState.PAUSED
- Specified by:
togglePausein interfaceGameControls
-
step
public void step()Advances the game by one 'step'. The game must be inGameState.RUNNINGfor this action to have an effect.
This action could include:- moving the movable piece down 1 line
- freezing the movable piece if appropriate
(which may end the game placing it into
GameState.OVER) - clearing full lines as needed
If this action is performed, all interested parties will be notified of the action via the following GameEvents in the following order:
* GameEvent.RowsCleared- The number of rows cleared
* GameEvent.NextPieceChanged- The new "next" movable piece
GameEvent.CurrentPieceChanged- An update to the movable piece to display
- This may be a "new" piece
* GameEvent.FrozenBlocksChanged- An update to the frozen blocks
- Specified by:
stepin interfaceGameControls
-
down
public void down()Try to move the movable piece down. The game must be inGameState.RUNNINGfor this action to have an effect.
This action could include:- freezing the movable piece if appropriate
(which may end the game placing it into
GameState.OVER) - clearing full lines as needed
If this action is performed, all interested parties will be notified of the action via the following GameEvents in the following order:
* GameEvent.RowsCleared- The number of rows cleared
* GameEvent.NextPieceChanged- The new "next" movable piece
GameEvent.CurrentPieceChanged- An update to the movable piece to display
- This may be a "new" piece
* GameEvent.FrozenBlocksChanged- An update to the frozen blocks
- Specified by:
downin interfaceGameControls
- freezing the movable piece if appropriate
(which may end the game placing it into
-
left
public void left()Try to move the movable piece left. The game must be inGameState.RUNNINGfor this action to have an effect.If this action is performed, all interested parties will be notified of the action via the following GameEvent:
GameEvent.CurrentPieceChanged- An update to the movable piece to display
- Specified by:
leftin interfaceGameControls
-
right
public void right()Try to move the movable piece right. The game must be inGameState.RUNNINGfor this action to have an effect.If this action is performed, all interested parties will be notified of the action via the following GameEvent:
GameEvent.CurrentPieceChanged- An update to the movable piece to display
- Specified by:
rightin interfaceGameControls
-
rotateCW
public void rotateCW()Try to rotate the movable piece in the clockwise direction. The game must be inGameState.RUNNINGfor this action to have an effect.If this action is performed, all interested parties will be notified of the action via the following GameEvent:
GameEvent.CurrentPieceChanged- An update to the movable piece to display
- Specified by:
rotateCWin interfaceGameControls
-
rotateCCW
public void rotateCCW()Try to rotate the movable piece in the counter-clockwise direction. The game must be inGameState.RUNNINGfor this action to have an effect.If this action is performed, all interested parties will be notified of the action via the following GameEvent:
GameEvent.CurrentPieceChanged- An update to the movable piece to display
- Specified by:
rotateCCWin interfaceGameControls
-
drop
public void drop()Drop the movable piece until it is set. The game must be inGameState.RUNNINGfor this action to have an effect. This action will include:- freezing the movable piece
(which may end the game placing it into
GameState.OVER) - clearing full lines as needed
If this action is performed, all interested parties will be notified of the action via the following GameEvents in the following order:
* GameEvent.RowsCleared- The number of rows cleared
GameEvent.NextPieceChanged- The new "next" movable piece
GameEvent.CurrentPieceChanged- A new movable piece to display
- This will be a "new" piece
GameEvent.FrozenBlocksChanged- An update to the frozen blocks
- Specified by:
dropin interfaceGameControls
- freezing the movable piece
(which may end the game placing it into
-
addPropertyChangeListener
Description copied from interface:PropertyChangeEnabledGameControlsAdd a PropertyChangeListener to the listener list. The listener is registered for all properties. The same listener object may be added more than once, and will be called as many times as it is added. If listener is null, no exception is thrown and no action is taken.- Specified by:
addPropertyChangeListenerin interfacePropertyChangeEnabledGameControls- Parameters:
theListener- The PropertyChangeListener to be added
-
addPropertyChangeListener
Description copied from interface:PropertyChangeEnabledGameControlsAdd a PropertyChangeListener for a specific property. The listener will be invoked only when a call on firePropertyChange names that specific property. The same listener object may be added more than once. For each property, the listener will be invoked the number of times it was added for that property. If propertyName or listener is null, no exception is thrown and no action is taken.- Specified by:
addPropertyChangeListenerin interfacePropertyChangeEnabledGameControls- Parameters:
thePropertyName- The name of the property to listen on.theListener- The PropertyChangeListener to be added
-
removePropertyChangeListener
Description copied from interface:PropertyChangeEnabledGameControlsRemove a PropertyChangeListener from the listener list. This removes a PropertyChangeListener that was registered for all properties. If listener was added more than once to the same event source, it will be notified one less time after being removed. If listener is null, or was never added, no exception is thrown and no action is taken.- Specified by:
removePropertyChangeListenerin interfacePropertyChangeEnabledGameControls- Parameters:
theListener- The PropertyChangeListener to be removed
-
removePropertyChangeListener
public void removePropertyChangeListener(String thePropertyName, PropertyChangeListener theListener) Description copied from interface:PropertyChangeEnabledGameControlsRemove a PropertyChangeListener for a specific property. If listener was added more than once to the same event source for the specified property, it will be notified one less time after being removed. If propertyName is null, no exception is thrown and no action is taken. If listener is null, or was never added for the specified property, no exception is thrown and take no action.- Specified by:
removePropertyChangeListenerin interfacePropertyChangeEnabledGameControls- Parameters:
thePropertyName- The name of the property that was listened on.theListener- The PropertyChangeListener to be removed
-
toString
-