egui-hexweb 0.4.0

A hexagonal arrow-connection puzzle game library for egui
Documentation

egui-hexweb

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

A self-contained hexagonal arrow-connection puzzle game library for egui.

The board is a small patch of hexagonal lattice: nodes joined by grid lines in six directions (up, down, and the four diagonals). Fewer pieces than nodes sit on the board, and each piece carries a few arrows pointing along those grid lines. Drag the pieces to any free node, or onto another piece to swap the two until every arrow of every piece points at a node that holds another piece: a completed web where nothing points into the void.

Unsatisfied arrows are drawn in an accent color, so the board itself always tells you how close you are.

Features

  • Pure game logic struct (HexwebGame) with no egui::Ui dependency, usable headlessly or with any renderer
  • Ready-to-use egui Widget (HexwebWidget) with drag & drop: moving onto empty nodes, swapping onto occupied ones
  • Procedural, seeded generation (HexwebGame::random) that always produces a solvable board and verifies, per board, that exactly one placement of the pieces solves it
  • An exact counting solver (HexwebGame::solution_count, HexwebGame::solution), exhaustive over the whole placement space, fast enough to run on every generated candidate and after every repair
  • Mirror-symmetric board shapes of 8 to 16 nodes (random_symmetric_board, hundreds of holey, notched, or compact shapes per size), plus plain hexagon boards
  • No losing state and no timer: every move is undone by moving back
  • The initial scramble is guaranteed to be neither solved nor solvable in a single move or swap

Usage

Add the dependency:

[dependencies]
egui-hexweb = "0.4"

Then use it in your egui app:

use egui_hexweb::{random_symmetric_board, HexwebGame, HexwebWidget, Params};

// A mirror-symmetric 12-node board with 9 pieces, 2-4 arrows each,
// reproducible from a seed. The seed picks both the board shape (from every
// symmetric connected shape of that size) and the puzzle.
let mut game = HexwebGame::random(
    Params {
        nodes: random_symmetric_board(12, 42),
        pieces: 9,
        min_arrows: 2,
        max_arrows: 4,
    },
    42,
);

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

// Customize the win banner:
ui.add(HexwebWidget::new(&mut game).win_message("Solved!"));

Check for a win after each frame:

use egui_hexweb::GameStatus;

match game.status() {
    GameStatus::InProgress => {}
    GameStatus::Won => println!("Every arrow is connected!"),
}

To start over on the same puzzle:

game.reset();

To offer a hint, ask the solver where the pieces belong:

if let Some(nodes) = game.solution() {
    // `nodes[piece]` is the node piece `piece` occupies in one solution.
}

How generation guarantees a single solution

The generator lays a solved configuration down first: it picks which nodes are occupied, then gives each piece arrows that provably point at other pieces in that configuration. A solution therefore always exists, by construction.

Because the boards are small (8 to 16 nodes), the solver is exhaustive rather than heuristic: it enumerates every possible set of empty nodes and counts the distinct assignments of the pieces that satisfy every arrow, treating identical pieces as interchangeable. The generator counts up to two solutions; if it finds more than one, it adds an arrow that provably kills one of them (adding an arrow can never break the configuration it was built from, and can never create a new solution), and recounts, until exactly one remains.

egui version compatibility

egui-hexweb egui
0.4 0.35
0.3 0.35
0.2 0.35

License

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