hashiwokakero

package
v1.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 6, 2026 License: MIT Imports: 18 Imported by: 0

README

Hashiwokakero

Connect islands with bridges to form a single connected group.

Hashiwokakero gameplay

How to Play

Islands are numbered circles on the grid. Each number indicates how many bridges must connect to that island. Bridges run horizontally or vertically between adjacent islands, may not cross, and can be single or double. The puzzle is solved when every island has exactly the required number of bridges and all islands are connected.

  1. Navigate to an island and press Enter or Space to select it.
  2. Press an arrow key toward an adjacent island to build a bridge.
  3. Press the same direction again to upgrade to a double bridge, or a third time to remove the bridge.
  4. Press Enter, Space, or Escape to deselect.

Controls

Navigation Mode
Key Action
Arrow keys / WASD / hjkl Jump to nearest island
Enter / Space Select island for bridging
Ctrl+R Reset puzzle
Ctrl+H Toggle full help
Ctrl+E Toggle debug overlay
Ctrl+N Return to main menu
Bridge Mode (after selecting an island)
Key Action
Arrow keys / WASD / hjkl Build or cycle bridge in direction
Enter / Space / Escape Deselect island

Modes

Mode Grid Islands Description
Easy 7x7 7x7 8-10 Small grid, few islands
Medium 7x7 7x7 12-15 Moderate density
Hard 7x7 7x7 17-20 Dense island placement
Easy 9x9 9x9 12-16 Larger grid, spread out
Medium 9x9 9x9 20-24 Moderate density
Hard 9x9 9x9 28-32 Dense island placement
Easy 11x11 11x11 18-24 Large grid, spread out
Medium 11x11 11x11 30-36 Moderate density
Hard 11x11 11x11 42-48 Dense island placement
Easy 13x13 13x13 25-34 Largest grid, spread out
Medium 13x13 13x13 42-51 Moderate density
Hard 13x13 13x13 59-68 Dense island placement

Quick Start

puzzletea new hashi easy-7x7
puzzletea new hashi medium-9x9
puzzletea new hashi hard-13x13

Documentation

Overview

Package hashiwokakero implements the bridge-connecting puzzle game.

Index

Constants

This section is empty.

Variables

View Source
var DailyModes = []list.Item{
	Modes[3],
	Modes[1],
}
View Source
var DefaultKeyMap = KeyMap{
	CursorKeyMap: game.DefaultCursorKeyMap,
	Select: key.NewBinding(
		key.WithKeys("enter", "space"),
		key.WithHelp("enter/space", "Select"),
	),
	Cancel: key.NewBinding(
		key.WithKeys("esc"),
		key.WithHelp("esc", "Cancel"),
	),
}
View Source
var Definition = game.Definition{
	Name:        "Hashiwokakero",
	Description: "Connect islands with bridges.",
	Aliases:     []string{"hashi", "bridges"},
	Modes:       Modes,
	DailyModes:  DailyModes,
	Help:        HelpContent,
	Import:      func(data []byte) (game.Gamer, error) { return ImportModel(data) },
}
View Source
var HelpContent string
View Source
var Modes = []list.Item{
	NewMode("Easy 7x7", "7x7 grid with 8-10 islands.", 7, 7, 8, 10),
	NewMode("Medium 7x7", "7x7 grid with 12-15 islands.", 7, 7, 12, 15),
	NewMode("Hard 7x7", "7x7 grid with 17-20 islands.", 7, 7, 17, 20),
	NewMode("Easy 9x9", "9x9 grid with 12-16 islands.", 9, 9, 12, 16),
	NewMode("Medium 9x9", "9x9 grid with 20-24 islands.", 9, 9, 20, 24),
	NewMode("Hard 9x9", "9x9 grid with 28-32 islands.", 9, 9, 28, 32),
	NewMode("Easy 11x11", "11x11 grid with 18-24 islands.", 11, 11, 18, 24),
	NewMode("Medium 11x11", "11x11 grid with 30-36 islands.", 11, 11, 30, 36),
	NewMode("Hard 11x11", "11x11 grid with 42-48 islands.", 11, 11, 42, 48),
	NewMode("Easy 13x13", "13x13 grid with 25-34 islands.", 13, 13, 25, 34),
	NewMode("Medium 13x13", "13x13 grid with 42-51 islands.", 13, 13, 42, 51),
	NewMode("Hard 13x13", "13x13 grid with 59-68 islands.", 13, 13, 59, 68),
}

Functions

func New

func New(mode HashiMode, puzzle Puzzle) game.Gamer

Types

type Bridge

type Bridge struct {
	Island1, Island2 int // island IDs (Island1 < Island2)
	Count            int // 1 or 2
}

Bridge represents a connection between two islands.

type HashiMode

type HashiMode struct {
	game.BaseMode
	Width      int
	Height     int
	MinIslands int
	MaxIslands int
}

func NewMode

func NewMode(title, description string, width, height, minIslands, maxIslands int) HashiMode

func (HashiMode) Spawn

func (h HashiMode) Spawn() (game.Gamer, error)

func (HashiMode) SpawnSeeded added in v1.3.0

func (h HashiMode) SpawnSeeded(rng *rand.Rand) (game.Gamer, error)

type Island

type Island struct {
	ID       int
	X, Y     int
	Required int // target bridge count (1-8)
}

Island represents a numbered node on the grid.

type KeyMap

type KeyMap struct {
	game.CursorKeyMap
	Select key.Binding
	Cancel key.Binding
}

type Model

type Model struct {
	// contains filtered or unexported fields
}

func ImportModel

func ImportModel(data []byte) (*Model, error)

func (Model) GetDebugInfo

func (m Model) GetDebugInfo() string

func (Model) GetFullHelp

func (m Model) GetFullHelp() [][]key.Binding

func (Model) GetSave

func (m Model) GetSave() ([]byte, error)

func (Model) Init

func (m Model) Init() tea.Cmd

func (Model) IsSolved

func (m Model) IsSolved() bool

func (Model) Reset added in v1.3.0

func (m Model) Reset() game.Gamer

func (Model) SetTitle

func (m Model) SetTitle(t string) game.Gamer

func (Model) Update

func (m Model) Update(msg tea.Msg) (game.Gamer, tea.Cmd)

func (Model) View

func (m Model) View() string

type Puzzle

type Puzzle struct {
	Width, Height int
	Islands       []Island
	Bridges       []Bridge
	// contains filtered or unexported fields
}

Puzzle holds the full game state.

func GeneratePuzzle

func GeneratePuzzle(mode HashiMode) (Puzzle, error)

GeneratePuzzle creates a solvable hashiwokakero puzzle for the given mode.

func GeneratePuzzleSeeded added in v1.3.0

func GeneratePuzzleSeeded(mode HashiMode, rng *rand.Rand) (Puzzle, error)

func (*Puzzle) BridgeCount

func (p *Puzzle) BridgeCount(islandID int) int

BridgeCount returns the total number of bridges connected to an island.

func (*Puzzle) CellContent

func (p *Puzzle) CellContent(x, y int) cellInfo

CellContent returns what occupies the given grid cell, using a lazily-built cache.

func (*Puzzle) FindAdjacentIsland

func (p *Puzzle) FindAdjacentIsland(fromID, dx, dy int) *Island

FindAdjacentIsland casts a ray from the island at fromID in direction (dx,dy) and returns the first island hit, or nil. dx/dy must be (0,1),(0,-1),(1,0),(-1,0). Stops if a perpendicular bridge crosses the path.

func (*Puzzle) FindIslandAt

func (p *Puzzle) FindIslandAt(x, y int) *Island

FindIslandAt returns the island at (x,y), or nil.

func (*Puzzle) FindIslandByID

func (p *Puzzle) FindIslandByID(id int) *Island

FindIslandByID returns the island with the given ID, or nil.

func (*Puzzle) GetBridge

func (p *Puzzle) GetBridge(id1, id2 int) *Bridge

GetBridge returns the bridge between two islands (by ID), or nil.

func (*Puzzle) IsConnected

func (p *Puzzle) IsConnected() bool

IsConnected checks if all islands form a single connected component via bridges.

func (*Puzzle) IsSolved

func (p *Puzzle) IsSolved() bool

IsSolved returns true if the puzzle is completely and correctly solved.

func (*Puzzle) SetBridge

func (p *Puzzle) SetBridge(id1, id2, count int)

SetBridge sets or removes the bridge between two islands. count=0 removes the bridge. count must be 0, 1, or 2.

func (*Puzzle) WouldCross

func (p *Puzzle) WouldCross(id1, id2 int) bool

WouldCross checks if adding a bridge between id1 and id2 would cross any existing bridge.

type Save

type Save struct {
	Width     int      `json:"width"`
	Height    int      `json:"height"`
	Islands   []Island `json:"islands"`
	Bridges   []Bridge `json:"bridges"`
	ModeTitle string   `json:"mode_title,omitempty"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL