A minimal terminal Tetris

A minimal terminal Tetris. I needed a quick project to get me back into writing Zig and had never implemented Tetris before.

Both fun to write and to play.

demo

6 Likes

Your build.zig.zon uses a branch specific url, this mean that the upstream project breaks your build when it updates its branch (because then the hashes no longer match).

To avoid that use the git+https protocol which automatically creates commit specific urls because it automatically adds the commit hash as the fragment/hash/# part of the url, or manually get a commit specific url like described here: Best way to release packages for libraries? - #2 by Sze, the changing the ending to tar is no longer necessary.

Thanks. Done

1 Like

This is great! I canā€™t wait to take a deeper look and get it running on my local machine.

Iā€™m curious, were there any hurdles that you overcame when implementing this? Any gotchas a newbie should be aware of?

1 Like

Things I had to puzzle over:

  • Iā€™d never used Zigā€™s package system before. The key thing I needed was to do zig fetch --save git+https://github.com/xyaman/mibu.git and then GitHub - xyaman/mibu: Pure Zig library for low-level terminal manipulation.
  • Initially, I forgot that terminals have non-square characters. To print something on a square grid, each cell needs to be two characters wide (see stage.zig)
  • Also, writing the entire game to the terminal for every redrawn frame would be quite inefficient, so I wanted to do double buffering, a comparison then only send the changes (see display.zig). This could be done much more neatly and with less cursor movement
  • I forgot how strict Zig is about casting (compared to C) and the syntax for @intCast() might have changed since I remember last using it. E.g. const xo = px + @as(isize, @intCast(x)) in player.zig
  • AFAICT, Zigā€™s range .. operator only supports positive and increasing integers, so I ended up using while in some cases which I had to look up the syntax for

Everything else I spent time on was to do with how Tetris works. Probably the thing which took the longest was remembering how to rotate a bitmap in 2D. Initially I went with a ā€œproperā€ trigonometry type solution, until I realised I could just write out the mapping Simplify rotation Ā· ringtailsoftware/zigtris@408fd24 Ā· GitHub

3 Likes

Very fun project, I look forward to trying it out!

Itā€™s probably true that this technique is more efficient, and itā€™s definitely the classic thing to do.

I havenā€™t bothered in quite a long time, though. Computers, and modern terminal emulators, are ludicrously fast in comparison to human reflexes, so it just wonā€™t happen that painting one screenā€™s worth of terminal, no matter how intricate, will visibly drop the frame rate.

What can happen is tearing, if the terminal renders a frame in a partial state then it doesnā€™t matter how fast the render is going, users are going to notice.

But we have mode 2026 now, which prevents that from happening on supported terminals. Iā€™ve found that toggling the mode and using a BufferedWriter to minimize syscalls is more than enough to get flicker-free updates, despite repainting on each update.

I think itā€™s cool that you implemented a double-buffer, great way to stretch your Zig muscles. Mainly I donā€™t want people to think that theyā€™d have to do that to get a good result while working with the terminal, in my experience this is no longer necessary.

Itā€™s still neat that this would probably work on a real glass tty, and not every terminal emulator out there supports 2026, although most do by now.

3 Likes

Fascinating. I didnā€™t know such a mode existed! That would be very useful if I go back to my Zig ā€œDoom in a terminalā€ port Toby Jaffey šŸ³ļøā€šŸŒˆ: "If you'd ever wondered how #Doom looks in a 160x5ā€¦" - mastodon.me.uk which sheared very badly (via zig-wasm-audio-framebuffer/src/doom/doom.zig at master Ā· ringtailsoftware/zig-wasm-audio-framebuffer Ā· GitHub)

I think my mental model of terminals is very much from the 1970sā€¦

3 Likes

Itā€™s a very nice little project! I love tetris and zigtris feels like the real thing even though itā€™s so minimalistic. Nicely done!

1 Like

Btw, the readme says itā€™s MIT licensed, but it would be good to add a standard LICENSE file so that tooling like github and zigistry identify it as MIT licensed.

3 Likes

Thanks. Done