tetro-tui 2.1.0

A cross-platform terminal game where tetrominos fall and stack.
tetro-tui-2.1.0 is not a library.

"tetro-tui logo"

Tetro TUI - Terminal User Interface Game

Crates.io License

Tetro TUI is a terminal-based but modern tetromino-stacking game that is very customizable and runs cross-platform.

"tetro-tui demonstration GIF"

Ways to Run

Download + run

  1. Download a release for your platform (Linux, MacOS, Windows, ..) if available.
  2. Navigate to and run the application (tetro-tui)

Compile from source

  1. Ensure Rust is installed.
  2. git clone https://github.com/Strophox/tetro-tui or otherwise download this repository.
  3. Navigate inside tetro-tui/ and do cargo run.

Install via cargo

Tetro TUI is available on crates.io. It can be installed via cargo:

cargo install tetro-tui

This makes tetro-tui available to run on your terminal.

FAQ

How does the base game work?

Tetro is about tetromino pieces falling from the sky and stacking inside a 2D playing field. Whenever a horizontal line is full, it automatically clears away, and everything 'stacked' above shifts down.

A skilled player may keep playing without blocking out the entire board, and different gamemodes put twists on these basic puzzle-like mechanics.

How good is Customization? Features?

For what originally started as a small/proof-of-concept, solid.

  • Graphics: Unicode/ASCII/Electronika; Handful of default color palettes, FPS, toggle effects, ...
  • Game keybinds: to your heart's desire. (*Note: Shift/Alt/.. might not work due to terminal limitations.)
  • Gameplay/handling: Rotation system, tetromino randomization, preview count, DAS, ARR, SDF, LDC, ARE (timings), IRS/IHS.
  • Gamemode selection: Swift ('40lines'), Classic ('marathon'), Master, Puzzle, Cheese, Combo, Custom (select goal, start gravity, toggle gravity progress, cmdline flags: start board, seed).
  • Scoreboard, Replays, Statistics: Can all be accessed and automatically stored in savefile.

Game aesthetics are mostly based on / can be customized/influenced using own terminal settings. E.g., using a bigger font, or using cool-retro-term;

"tetro-tui running in cool-retro-term"

New game/

  • Swift: How fast can you clear 40 lines?
  • Classic: Clear 150 lines at increasing gravity.
  • Master: Clear 150 lines at instant gravity.
  • Puzzle: Clear 24 hand-crafted puzzles.
  • Cheese-20: Eat through lines like Swiss cheese. Limit∈[None, Some(10), Some(11), .., Some(20), ..]
  • Combo-30: Get consecutive line clears. Limit∈[None, Some(10), Some(11), .., Some(30), ..]
  • Ascent*: (experimental, req. Ocular + 180° rot.)
  • Custom: [Del]=reset
    • Initial fall delay = 1.0s (Gravity: 1.0 Hz)
    • Progressive gravity ∈ [on, off]
    • Limit ∈ [None, TimeElapsed(300s), .., PointsScored(200), .., PiecesLocked(100), .., LinesCleared(40), ..]

Settings/Adjust-Graphics/

  • Slot ∈ ['Default', 'Focus+', 'Guideline', 'High Compat.', 'Elektronika 60', 'Custom I'/'II'/..]
  • Glyphset ∈ [Unicode, ASCII, Elektronika_60]
  • Color Palette (modifiable presets) ∈ ['Monochrome', 'ANSI', 'Fullcolor', 'Okpalette', 'Gruvbox', 'Solarized', 'Terafox', 'Fahrenheit', 'The Matrix', 'Sequoia']
  • Color locked tiles ∈ [on, off]
  • Show effects ∈ [on, off]
  • Show shadow piece ∈ [on, off]
  • Show button state ∈ [on, off]
  • Max framerate ∈ [1, .., 60, ..]
  • Show FPS ∈ [on, off]

Settings/Adjust-Keybinds/

  • Slot (modifiable preset) ∈ ['Default', 'Control+', 'Guideline', 'Vim', 'Custom I'/'II'/..]
  • MoveLeft, MoveRight
  • RotateLeft, RotateRight, Rotate180
  • DropSoft, DropHard
  • TeleDown, TeleLeft, TeleRight
  • HoldPiece

Settings/Adjust-Gameplay/

  • Slot ∈ ['Default', 'Finesse+', 'Guideline', 'NES', 'Gameboy', 'Custom I'/'II'/..]
  • Piece rotation system ∈ [Ocular, ClassicL, ClassicR, Super]
  • Piece randomization ∈ [Completely random, 7-Bag, 14-Bag, .., Recency (^2.5), Recency (^2.6), .., Balance out]
  • Piece preview count ∈ [0, 1, .., 3, ..]
  • Delayed auto move (DAS) ∈ [0ms, 1ms, .., 167ms, ..]
  • Auto move rate (ARR) ∈ [0ms, 1ms, .., 33ms, ..]
  • Soft drop speedup (SDF) ∈ [0x, 0.25x, .., 15x, ..]
  • Line clear duration (LCD) ∈ [0ms, 5ms, .., 200ms, ..]
  • Spawn delay (ARE) ∈ [0ms, 5ms, .., 50ms, ..]
  • Allow initial rotation/hold (IRS/IHS) ∈ [on, off]
  • Convert double-tap to teleport ∈ [None, Some(5ms), Some(10ms), ..]

Settings/Advanced-Settings/

  • Save contents ∈ ["Nothing", "Only settings - No scores,replays", "Only settings,scres - No replays", "Everything (settings,scores,replays)"]
  • Assume enhanced-key-events available ∈ [on, off]
  • Blindfold gameplay ∈ [on, off]
  • Renderertype ∈ [Default, Legacy debug, Halfcell, Braille]

What was the motivation behind this project?

This is a passion project! The additions of all the many features stem from personal motivation to make them available and make things enjoyable/customizable.

The result is hopefully decent customizability, advanced game mechanics, technical solutions across the board: Swappable settings slots/profiles to deal with all the knobs and buttons (manual json editing possible), basic game replay compression; nontrivial gamemodes, a compile-time modding system, and almost all the modern stacker game mechanics I saw fit.

Maintaining high Rust code quality, especially in the game logic, was also important.

Where's the config file? Will it clutter my system?

The application will not store anything by default; 'Keep save file' needs to be opted in.

The exact location of the config file is visible in the Advanced settings TUI menu. The location based on the dirs::config_dir() implemented, e.g. C:/User/myuser/AppData/Roaming/.tetro-tui_v1.0_savefile.json or /home/myuser/.config/.tetro-tui_v1.0_savefile.json),

  • Otherwise directory of execution.

Savefile size grows primarily with number of saved replays (for which custom input compression is used however). The Scores and Replays menu can be used to select and delete entries or their replay ([Del] or [Alt+Del], respectively).

Experienced Stackers: Why do timing-settings (DAS/ARR/SDF etc.) not apply for me?

TL;DR use a terminal like kitty or Alacritty (or ->other) for 'true'/smoother handling in the terminal. Otherwise timings might solely depend on how quickly your terminal sends key-repetition events.

The real problem lies in how terminals normally send "key pressed" signals, but no "key released again" signals. This makes it impossible to implement mechanics like: "If [←] is pressed, move left repeatedly until key is released again". Precisely this issue is fixed with 'kitty protocol' / 'progressive enhancement' / 'enhanced keyboard events'.

Some Windows terminals support it but are not auto-detected, if so try the Override toggle in the Advanced Settings menu.

Note that a similar technicality affects the recognition of [Shift],[Alt],... key presses as separate keys. On unenhanced terminals, those keys do not cause signals by themselves, but only in combination with a nonspecial-key presses (e.g. [Ctrl+C]).

Experienced Stackers: How 'polished' are the mechanics?

Copy of the feature list from the Falling Tetromino Engine powering the game logic:

The engine aims to compete on the order of modern tetromino stackers; It incorporates many features found in such games. Experienced players may be familiar with most of the following mechanics:

  • Variable gravity/fall delay (frame-agnostic); '20G' (= 0s fall delay),
  • Simple but flexible programming of custom fall and lock delay progressions (DelayParameters),
  • (Arbitrary) piece preview,
  • Pre-spawn actions toggle ('Initial Hold/Rotation System'),
  • Rotation systems: 'Ocular' (engine-specific, playtested), 'ClassicL', 'ClassicR', 'Super',
  • Tetromino generators: 'Uniform', 'Stock' (generalized Bag), 'Recency' (history), 'Balancerelative',
  • Spawn delay (ARE),
  • Delayed auto-shift (DAS),
  • Auto-repeat rate (ARR),
  • Soft drop factor (SDF),
  • Lenient lock delay reset toggle (reset lock delay even if rotate/move fails),
  • Ensure move delay less than lock delay toggle (DAS/ARR automatically shortened when lock delay is very low),
  • Lock-reset-cap factor (~maximum time before lock delay cannot be reset),
  • Line clear duration (LCD),
  • Custom win/loss conditions based on stats: time, pieces, lines, score,
  • Hold piece,
  • Higher score for larger lineclears and spins ('allspin')
  • Game reproducibility (PRNG),
  • Available player actions: MoveLeft, MoveRight; RotateLeft, RotateRight, Rotate180; DropSoft, DropHard, TeleDown ('Sonic drop'), TeleLeft, TeleRight, HoldPiece.

Experienced Stackers: In which ways is it unlike familiar stacker games?

This project took its liberties to adapt/experiment with certain aspects of the game, although it should still feel as familiar as it can:

  • Default controls set to WASD + Arrow keys.
  • Use of the symmetrical and flexible Ocular Rotation System as default (instead of the arguably quirky industry standard).
  • Default Recency (History) randomizer (instead of 'overdeterministic' 7-Bag).
  • Scoring system is custom and kept simple.
    • "1pt for simple line clear, increasing score incentivizing higher clears, spins, perfects and combos."
    • 'Allspin' (instead of preoccupation with 'T-spins'), but no 'minis' (TBD).
    • Combos, but no 'back-to-back'.
    • ...Exact formula: score_bonus = if is_perfect_clear{ 4 }else{ 1 } * if is_spin{ 2 }else{ 1 } * lineclears * 2 - 1 + (combo - 1)
  • Additional controls for Teleport Down (a.k.a. 'Sonic Drop') / Left / Right.
  • Different lock reset / lock-down cutoff: 'max time = 10⋅current lock delay' (instead of 'max 15 moves with current lock delay').
  • Speed/Gravity/Fall curve practically the same but technically slightly adapted.

Experienced Stackers: What's the "Ocular Rotation System"?

A 'better' implementation of tetromino rotation, based off visual intuition and symmetry:

The Ocular Rotation System affords:

  • Rotation based on 'where it looks like the piece should be able to go'.
  • Symmetric (mirrored) situations should lead to symmetric (mirrored) outcomes.
  • Tetrominos should not teleport up/down too much.

Visual heatmap comparison of rotation systems:

"super rotation system heatmap"

"ocular rotation system heatmap"

CLI Enthusiasts: How was the Terminal User Interface (TUI) programmed and why isn't it Ratatui?

The project started out simple and has been directly using the amazing Crossterm since then. Crossterm handles all the placement of (colored) characters and reading inputs from the terminal. We implement custom diff'ing so I/O does not bottleneck smooth rendering. We find TUI should generally stay in its current, minimalistic form, although a rewrite with Ratatui might be considered.

How do I navigate the TUI? Can I see a table of all the controls?

Refer to the following tables for comprehensive controls:

Keys ≈Meaning
/, j/k Navigate up/down
/, h/l Change value
Enter, e Select
Esc, q, Back, Go back
Del, d Delete/reset
1/2/3... Quickselect option (⇝'New game')
Alt+? Different value change' (⇝'New game'⇝['Combo','Savepoint','Custom'], ⇝'Gameplay settings'⇝'Tetromino generation')
Alt+Del, Alt+d Delete replay (⇝'Scores and replays')
Ctrl+U (For experienced/impatient people) unlock all gamemodes (⇝'New game')
Ctrl+C Exit application (respects save preferences)
Key Action
Esc Pause game
Move left
Move right
A Rotate left (CCW)
- Rotate around (180°)
D Rotate right (CW)
Soft drop
Hard drop
- Teleport down
- Teleport left
- Teleport right
Space Hold piece
Ctrl+D Forfeit game
Ctrl+E Store seed (accessible in ⇝'New game'⇝'Custom')
Ctrl+S Store savepoint (accessible in ⇝'New game'⇝'Savepoint', ⇝(live) 'Game'⇝Ctrl+L)
Ctrl+L Load savepoint (Caution: overwrites live game)
Ctrl+Alt+B Toggle on/off visibility of tiles ('Blindfolded')
Ctrl+C Exit application (respects save preferences)
Key Action
Esc, q, Back Exit replay
Space Pause replay
/ , j/k Speed up / Slow down replay by ±0.25x
Alt+/, Alt+j/k Speed up / Slow down replay by ±0.05x
- Reset replay speed to =1.0x
/ , h/l Skip forward/backward 1s in time
1/2/3... Jump to 10%/20%/30%/...
. Skip forward one player input and pause
Alt+. Skip forward one game state change* and pause (experimental, might not work properly for modded games)
Enter, e Start (live) Game from current replay state
Ctrl+E Store seed (accessible in ⇝'New game'⇝'Custom')
Ctrl+S Store savepoint (accessible in ⇝'New game'⇝'Savepoint', ⇝(live) 'Game'⇝Ctrl+L)
Ctrl+I Toggle Instant Interactive Input Intervention mode (experimental)
Ctrl+C Exit application (respects save preferences)

License

Licensed under MIT.

Provenance

100% human-sourced spaghetti code

Color palettes used:

Acknowledgements

Special Thanks to:

  • GrBtAce, KonSola5 and bennxt – for support early in development
  • Dunspixel – for inspiration regarding 'O'-spins
  • madkiwi – for advice regarding 4wide-6residual combo layouts
  • (Apostolos Kousoukos for making Apotris!)
  • and RayZN and ˗ˋˏthe One and Onlyˎˊ˗ – for advice regarding the Tetro logo