egui-numberlink 0.2.1

A Numberlink puzzle game library for egui
Documentation

egui-numberlink

crates.io docs.rs deps.rs CI Rust version License Changelog Live demo Archived

Archived. This project is no longer maintained. The crate remains functional, but the procedural generator never produced genuinely difficult puzzles despite extensive effort — they all play too easy. Use or fork at your own risk.

A self-contained Numberlink puzzle game library for egui.

Numberlink is the classic puzzle of connecting matching pairs of numbered endpoints on a grid with a path each, such that no two paths cross and every non-blocked cell of the board ends up covered by exactly one path. Some cells may be permanently blocked (walls no path may ever enter), which is what makes lower-density procedural puzzles genuinely harder rather than merely bigger.

Features

  • Pure game logic struct (NumberlinkGame) with no egui dependency — usable headlessly or with any renderer
  • Ready-to-use egui Widget (NumberlinkWidget) that renders an interactive, numbered board, including any blocked (wall) cells
  • Two ways to build a puzzle: NumberlinkGame::from_endpoints/from_endpoints_with_blocked (supply your own endpoints and, optionally, blocked cells) and NumberlinkGame::random (procedural, seeded, always has a solution by construction and prefers one verified unique within a bounded search)
  • Endpoints are always labeled with numbers, like the original Numberlink — color is an optional, fully customizable skin on top, not a replacement
  • NumberlinkWidget::colors lets embedding apps supply their own per-number palette; defaults to a colorblind-safe built-in one
  • Paths are drawn through the interior of each cell (connecting cell centers, turning at a cell's center), never along a cell's border
  • Click-and-drag drawing: either endpoint always works to start/redraw a number's path; dragging back over a path's own previous cell retracts it by one; dragging onto a different number's path is rejected; a plain click (no drag needed) also clears/starts a path
  • Undo/redo history, one entry per completed drag
  • Win banner drawn over the board once solved

Usage

Add the dependency:

[dependencies]
egui-numberlink = "0.1"

Then use it in your egui app:

use egui_numberlink::{NumberlinkGame, NumberlinkWidget};

// A curated puzzle from explicit endpoint pairs (number 0's endpoints, then
// number 1's, ...):
let mut game = NumberlinkGame::from_endpoints(
    3,
    3,
    vec![((0, 0), (2, 2)), ((0, 2), (1, 2))],
);

// Or a procedural puzzle, reproducible via a seed: 5 pairs on a 6x6 board,
// with 70% of cells playable (the rest permanently blocked). The generator
// prefers a layout it can verify has exactly one solution, within a bounded
// search.
let mut game = NumberlinkGame::random(6, 6, 5, 0.7, 42);

// Inside your egui update/UI closure:
ui.add(egui_numberlink::NumberlinkWidget::new(&mut game));

// Customize the per-number palette (must be at least one color; cycles if
// shorter than the puzzle's pair count):
use egui::Color32;
let colors = [Color32::RED, Color32::GREEN, Color32::BLUE];
ui.add(egui_numberlink::NumberlinkWidget::new(&mut game).colors(&colors));

After each frame you can inspect game.status to check for a win:

use egui_numberlink::GameStatus;

match game.status {
    GameStatus::Playing => {}
    GameStatus::Won => println!("Solved!"),
}

To start over on the same puzzle:

game.reset();

egui version compatibility

egui-numberlink egui
0.1 0.35

License

Licensed under either of MIT or Apache-2.0 at your option.