Save and load game state
SaveManager.java uses buffered file reading and writing to persist the board, pieces, scores, and difficulty. Saving and restoring structured game state made file I/O a central part of the implementation.
Software systems · Java · event-driven design
A playable Java Swing Tetris I wrote solo for CIS 1200, with a 20 × 18 board, explicit game states, file-based save/load, JUnit tests, and Easy-mode undo.
I wrote a desktop Tetris game in Java for CIS 1200, on my own. The finished application has menu states, scoring, pause behavior, save/load, high-score display, and undo in Easy mode.
I split it into model, rendering, input, and persistence so each piece could be tested on its own. TetrisGame manages gameplay state and timers. GamePanel renders the Swing interface, InputHandler maps keys to state-aware actions, and SaveManager handles file I/O.
TetrisGame
Game state, timers, scoring, current and next pieces, undo snapshots.
GamePanel
Swing rendering for board, active piece, next piece, score, menus, overlays.
InputHandler
Keyboard routing for menu, playing, paused, game-over, and high-score states.
SaveManager
Human-readable autosave file for state restore and top-score loading.
GameBoard stores the board as a 20 × 18 two-dimensional integer grid.-1 values for boundary handling.TetrisGame.canMove validates movement and rotation by checking bounds and occupied cells.clearFullRows.
The game uses explicit states: MENU, COUNTDOWN, PLAYING, PAUSED, GAME_OVER, and VIEWING_SCORES. Keyboard behavior changes based on the active state, which keeps menu navigation, gameplay controls, saving, loading, pausing, and restart behavior from collapsing into one input path.
P pauses or resumes depending on state.S saves during gameplay or while paused.L loads a saved game from the menu.H opens high scores, and Escape returns from the high-score view.
Persistence is implemented through SaveManager, which writes the game state, difficulty, score, top scores, board grid, and current/next tetromino data to autosave.txt. Undo is implemented in Easy mode using a Deque of snapshots containing the board grid, current piece, next piece, and score before placement.
The repository includes JUnit tests for core logic in TetrisTest.java, including row clearing, score updates, tetromino rotation, and factory output validation.
The project builds with Maven and uses the exec plugin to run org.cis1200.Game. Java 17 is required by the Maven configuration.
cd "Tetris Full Project"
mvn compile
mvn exec:java
Formatted project README
A formatted version of my project README, with the implementation details most relevant to the finished application.
SaveManager.java uses buffered file reading and writing to persist the board, pieces, scores, and difficulty. Saving and restoring structured game state made file I/O a central part of the implementation.
The board is stored as a two-dimensional grid. Cells encode empty spaces, wall markers, and piece IDs, which gives the game direct indexed access to collision, placement, and row-clearing behavior.
Undo uses a stack-like Deque of game snapshots. Each snapshot keeps previous board state, current piece, next piece, and score so Easy mode can restore a prior state consistently.
Piece defines shared behavior for game pieces, while Tetromino extends it with concrete piece behavior such as rotation and duplication.
GamePanel.javaInputHandler.javaSaveManager.javaautosave.txt, including difficulty, score, board layout, and active pieces.ScoreManager.javaPiece.java and Tetromino.javaFactory.javaFrame.javaGameBoard.javaTetrisGame.javaThe hardest feature was undo. Restoring a previous move required more than replacing the board grid: the current piece, next piece, and score also had to return to a consistent state, especially after row clears.
File I/O was another debugging-heavy part of the project because the save format had to be read back in the exact order it was written. I also had to refine GamePanel repeatedly because the Swing rendering, overlays, and state-dependent text all needed to work together.
The final design separates responsibilities across the game model, rendering panel, input handler, persistence layer, scoring, board representation, and piece hierarchy. If I revisited it, I would modularize GamePanel further and add levels so the game increases speed and difficulty as score grows.