Skip to main content

Most free mahjong games deal unwinnable boards. I built mine backwards.

An inside look at building a solvable mahjong solitaire game, extracting SVG tiles from Noto Sans Symbols 2, and running on a framework-free stack.

AI-written
Inewgen
27 Jul 2026Source: Dev.to3 min read (0 views)Last updated 04 Aug 2026
Share
Most free mahjong games deal unwinnable boards. I built mine backwards.

Stock photo for illustration only, not from the actual event

Font size
  • Standard free mahjong games often use random tile drops that frequently create unwinnable boards.
  • The developer fixed this by generating a solution first and deriving the board in reverse order.
  • SVG artwork was extracted from Noto Sans Symbols 2 font to bypass broken Unicode defaults.
  • The architecture relies entirely on vanilla PHP, vanilla JavaScript, and SQLite without npm.

Mahjong solitaire is a matching game where players remove pairs of identical tiles from a 144-tile pile, provided the tiles are free with no top stack and at least one long side open. However, the conventional way of dealing these boards routinely leads to dead ends.

The straightforward method of shuffling all 144 tiles and dropping them onto a layout is flawed. A random arrangement easily creates unwinnable states where the final four tiles are buried under each other or a pair is locked permanently. Players usually discover this twenty minutes into a game when no matches remain.

The remedy is to stop generating boards and checking them afterward, and instead generate a complete solution first and derive the board from it. Playing back that removal order guarantees that a valid solution exists before the player ever touches a tile.

Designing puzzle games using a reverse-generation approach effectively eliminates player frustration caused by unluckily randomized layouts. It highlights how backend architectural decisions directly dictate the quality of the frontend user experience and long-term engagement.

A fallback mechanism is in place if all sixty generation attempts fail, pairing adjacent positions to produce a functional board even if solvability isn't strictly guaranteed. This branch has never been triggered, but the developer kept it to ensure users see a game screen rather than a blank page.

Regarding tile faces, the Unicode mahjong block (U+1F000–U+1F02B) is frequently broken or missing in default Windows and Android font stacks, which would render the game unplayable. Consequently, the tile faces are rendered using SVG graphics.

Public-domain riichi mahjong artwork covers 33 out of 42 faces, but lacks flower tiles, season tiles, and the white dragon. To fill the gap, the missing outlines were extracted directly from the Noto Sans Symbols 2 font using fontTools.

Never miss the latest news?

Subscribe to get news summaries by email - not often enough to be annoying.

โฆษณา

This extraction process revealed two unexpected details. Each glyph draws its own outer and inner tile borders, which are byte-identical across bonus tiles. Dropping those border contours leaves behind clean artwork, and using the drawing area bounding box provides a consistent scale for every face.

mahjong tile vector svg font

Stock photo for illustration only, not from the actual event

Additionally, the small character in the corner representing symbols like plum or spring can be cleanly separated from the main picture. This separation allows developers to color the character and the illustration independently using a single monochrome glyph source.

Technically, the project runs on vanilla PHP, vanilla JavaScript, and SQLite without any frameworks, build steps, or npm packages. Every page is server-rendered, JavaScript handles interactive layers, and CSS provides the tile depth and shadows while SVG acts as the face plate.

The game is currently live at juju.games/mahjong for anyone willing to test their luck.

Source: Dev.to

Comments

Leave a Comment
0/2000

Found something wrong in this article? Report an issue with this article