Quick Start Guide

Playing Tetris in a database requires a slightly different workflow than launching a standard executable. Because SQL queries run entirely server-side, we must run two separate processes simultaneously:

  1. The Input Listener: A Python script that captures your keystrokes and writes them to a database table.
  2. The Game Engine: The massive SQL query that reads those inputs, calculates the game state, and renders the graphics back to your terminal.

Step 1: Start the Input Listener (The "Controller")

Open a fresh terminal window. This window will act as your game controller. You must keep this window active and focused while playing to ensure it captures your keystrokes.

If using the Docker installation:

docker exec -it pg ./tetris-sql/input.py

If using a local installation:

python3 input.py
(If your local database uses a different port, user, or password, you must pass those arguments here. See the Configuration page for details.)

Expected Output

Upon running the script, you should see the following text confirming a successful connection:

Connecting to localhost:5432/postgres ... connected.
Controls:
  Arrow keys/WASD - move
  Space - hard drop
  P - pause (move/hard drop to unpause)
  Q - stop the input script
Leave this terminal running and open a second terminal window.

Step 2: Start the Game Loop (The "Screen")

In your second terminal window, you will execute the SQL script. This terminal will act as your screen.

If using the Docker installation:

docker exec pg psql -U postgres -f tetris-sql/game.sql

If using a local installation:

psql -U postgres -f game.sql

Dealing with JIT Compilation Delays

When you execute the query, you might experience a delay of several seconds before the game board appears. This is not a bug.

PostgreSQL uses Just-In-Time (JIT) compilation to optimize complex queries. Because game.sql contains a massive, multi-layered recursive CTE, the JIT compiler spends significant time trying to optimize it before execution begins.

How to fix the delay: If you are running the query from an interactive psql session, you can turn off JIT for your session before running the game:

SET jit = off;
\i game.sql

Step 3: Play the Game!

Once the board renders in your second terminal, click back into your first terminal (the input listener) to ensure it has focus.

Controls

  • Move Left / Right: Left Arrow / Right Arrow (or A / D)
  • Move Down (Soft Drop): Down Arrow (or S) - Speeds up the natural fall.
  • Rotate: Up Arrow (or W)
  • Hard Drop: Spacebar - Instantly drops the piece to the bottom (indicated by the ghost piece ()).
  • Pause: P - Pauses gravity. To unpause, simply press any movement key or the spacebar.
  • Quit Script: Q (This only stops the input script; you must use Ctrl+C in the SQL terminal to kill the game loop).

What's Happening Under the Hood?

As you play, the Python script is firing asynchronous UPDATE statements to an unlogged table called Input. Simultaneously, the SQL query is looping 60 times a second, using a dblink connection to read that table and update the 1D boolean array representing your board.

Curious about the technical wizardry making this possible? Dive into The Game Loop Architecture.