Show HN: Zsweep – Play Minesweeper using only Vim motions
Posted by oug-t 5 days ago
Comments
Comment by oug-t 5 days ago
I’m the creator of zsweep. It’s a keyboard-centric Minesweeper clone where you play entirely using Vim motions (h, j, k, l to move; w/b to skip words; etc.).
The Backstory: I wanted to build a project to get my hands dirty with Svelte 5 and the new Runes system. I also wanted a way to practice Vim muscle memory that wasn't just typing code.
Tech Stack:
Frontend: Svelte 5 (Runes) + SvelteKit
Styling: Tailwind CSS
State: Custom Finite State Machine (FSM) for the game logic
The Challenge: One of the hardest parts was getting the "chording" logic right (where you clear multiple squares at once) while keeping the keyboard navigation feeling instant and "vim-like."
It’s open source, so if you’re curious about how Svelte 5 handles game state, feel free to poke around the code: https://github.com/oug-t/zsweep
I’d love to hear your feedback on the controls or any edge cases you find!
Comment by shagie 14 hours ago
https://github.com/rwestlund/freesweep was the result.
As he was learning how to program at the time, he decided to undertake writing minesweeper that he could play from a telnet session from the library or one of the vt100 terminals in the lab. And yes, he also had difficulty with the chording logic. He called it "super click" (that code is in clear.c). Part of the initial challenge was since he was taking this as his first project and before really reading the K&R everything was a one dimensional array (>.<) and there was a lot of multiplication and addition (and division and modulus).
Movement code is in play.c
Comment by oug-t 13 hours ago
I will definitely checkout play.c for reference.
Comment by oug-t 15 hours ago
Motivated by the response, I just pushed a cleanup of the repo to make it easier to build and run locally.
I am now opening issues for the specific requests mentioned here--like adding the `e` motion, improving `w/b` logic, and preserving the board state when game over.
Thank you again, PRs are very welcome!!
Comment by QuadmasterXLII 18 hours ago
case '0': return { type: 'ZERO' };
case '_': return { type: 'START_ROW' };
// --- SEARCH ---
case '/': return { type: 'START_SEARCH' };
case 'n': return { type: 'NEXT_MATCH' };
case 'N': return { type: 'PREV_MATCH' };
// --- MOVEMENT (WASD Removed) ---
case 'h': case 'ArrowLeft': return { type: 'MOVE_CURSOR', dx: -1, dy: 0 };
case 'j': case 'ArrowDown': return { type: 'MOVE_CURSOR', dx: 0, dy: 1 };
case 'k': case 'ArrowUp': return { type: 'MOVE_CURSOR', dx: 0, dy: -1 };
case 'l': case 'ArrowRight': return { type: 'MOVE_CURSOR', dx: 1, dy: 0 };
// --- SKIPS ---
case 'w': return { type: 'NEXT_UNREVEALED' };
case 'b': return { type: 'PREV_UNREVEALED' };
// --- ACTIONS ---
case 'i': case 'Enter': return { type: 'REVEAL' };
case ' ': return { type: 'SMART' };
case 'f': return { type: 'FLAG' };
// --- ADVANCED MOTIONS ---
case '$': return { type: 'MOVE_CURSOR', dx: 999, dy: 0 };
case 'G': return { type: 'GO_BOTTOM' };
case 'g': return { type: 'GO_TOP' };
No macros or block select yet, still fun! probably for the best that /mine doesn't work yetComment by apetrov 1 hour ago
Comment by johnhamlin 18 hours ago
Comment by oug-t 15 hours ago
I will add an issue for this!
Comment by unformedelta 20 hours ago
It would feel a little more intuitive if w/b worked on groups of unrevealed tiles instead of just moving 1 space when you were already on an unrevealed tile. i.e. unrevealed = words, revealed = spaces. That way, you could also use them to meaningfully navigate around unrevealed groups better than using h/l. I also found myself missing "e" to go to the end of a word, apparently I use it more often than "w".
I really appreciated the attention to detail though, I was delighted when I realized that gg/G/0/$ all worked as expected.
Comment by oug-t 16 hours ago
I'll add `e` (end of word) support in the next push, too. Thank a lot for the feedback!
Comment by kej 20 hours ago
The only complaint I have is that enter for clearing feels awkward in conjunction with hjkl movement; maybe add (d)elete and (f)lag as alternatives to enter and space to keep everything on the home row without requiring stretching?
Comment by oug-t 15 hours ago
Now I mainly use `space` key for both chording and flagging. It's the old muscle memory I inherited from playing the classic minesweeper game. One good thing about using the space is that, thumb is always available in vim motions, where other fingers are on the home row.
Thanks for the advise!!
Comment by 1313ed01 20 hours ago
Comment by schmooser 14 hours ago
Comment by oug-t 8 hours ago
I will try to fix this
Comment by TheGRS 18 hours ago
Comment by oug-t 15 hours ago
I opened an issue regarding to this, Thank you for the advise!!
Comment by alejoar 19 hours ago
Comment by oug-t 15 hours ago
Comment by sodacanner 18 hours ago
Comment by oug-t 15 hours ago
I will try to integrate more advanced motions inside the game!!