All projects

Tetris Block Puzzle

A Java Swing puzzle in which nothing falls: random three-by-three shapes are dragged onto the board with the mouse, complete rows and columns clear together, and every finished match is appended to a file of serialised objects.

Java Game DevelopmentSwingJava
tetris-block-puzzle.pdf · 530 KB Open the report

The problem

Project for the Programming II course at the Universitat de les Illes Balears.

The brief was a graphical application, and the game was the excuse. What was being marked was the interface, the event handling and the file work, so the requirement was really a menu with four things behind it — start a game, configure it, read the history of past matches, show the instructions — each of which has to refuse while a game is running, because all four either reset state or need the board still.

It is called Tetris and it is not Tetris. Nothing falls under gravity, the pieces are not the seven tetrominoes, and a line clears down columns as well as across rows. You pull an arbitrary shape out of the tray and drop it wherever it fits, which is the genre 1010! belongs to rather than the one the title claims.

The board is 24×24 cells with a two-cell black border all the way round, so 20×20 are playable. That border is not decoration: it is what stops a three-wide shape being dropped half outside the grid, and the completeness tests skip it so it can never count towards a line. A piece is a 3×3 grid where every cell is decided by a coin flip, thrown again if the whole grid comes up empty, so the shapes are arbitrary rather than drawn from a set. A match lasts a fixed number of seconds, and when the clock runs out the score is shown and written to disk.

How it works

  • The board draws itself — Tablero extends JComponent and paints in layers: the empty cells, the grid lines, the black border, the backdrop, and then either an occupied cell’s texture or the shape currently riding the cursor. It also owns the row and column tests, which scan only the playable range.
  • A piece is a boolean matrix — Pieza keeps a 3×3 of flags alongside the cells that carry the image. Rotation is a transpose read backwards, nueva[fila][columna] = tieneCasilla[2 - columna][fila], written into a scratch matrix and copied back afterwards, because rotating in place would overwrite cells the operation still had to read.
  • Placement is three mouse events — mousePressed picks the shape up, mouseDragged carries it with the cursor, and mouseReleased works out which cell it was dropped on and tests the 3×3 against what is already there. Nothing is committed until the whole shape is known to fit.
  • Clearing scores rows and columns alike — each cleared line is worth ten points. Rotating costs one and swapping the shape for a fresh one costs five, so neither escape is free, and the score can go negative if you use them to stall.
  • Appending to a file of objects — this is the part worth stealing. An ObjectOutputStream writes a stream header the moment it opens, so opening an existing file in append mode and writing normally leaves a second header buried in the middle and the reader stops dead when it reaches it. AdicionObjectOutputStream overrides writeStreamHeader() to do nothing at all, which is what makes a match appendable to a file that already holds matches. Reading back has no record count to work from, so the history loop reads until EOFException and treats that as the end rather than as a failure.
  • Everything about the game is configurable — the points for each action, the length of a match, and the texture the cells are drawn with, given by name and resolved against the images that ship with it. A field left blank keeps its current value.

Running it

Requires Java 17, which is what the project is set to compile against. It is a NetBeans Ant project, so it opens in the IDE directly and ant builds it from a terminal:

ant jar
java -jar dist/entregaFinal.jar

Run it from the repository root. Textures, icons and the backdrop are loaded through relative paths, and the file of saved matches is created beside them, so starting it anywhere else gives a board with no images and a history that never finds its file.