wfc

package
v0.0.9 Latest Latest
Warning

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

Go to latest
Published: Apr 28, 2022 License: MIT Imports: 12 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var Directions = []Direction{Down, Left, Right, Up}
View Source
var (
	ErrNoSolution = errors.New("no possible modules for slot")
)

Functions

func DefaultIsPossibleFunc added in v0.0.4

func DefaultIsPossibleFunc(state *Module, from, to *Slot, d Direction) bool

DefaultIsPossibleFunc returns whether or not a module is possible given a slot and direction.

func GetTileFromSpriteSheet

func GetTileFromSpriteSheet(img image.Image, x, y, width, height int) (image.Image, error)

GetTileFromSpriteSheet returns a tile from a sprite sheet.

func HexFromColor

func HexFromColor(c Color) string

func LoadImage

func LoadImage(file string) (image.Image, error)

LoadImage loads an image from a file path.

func LoadImageFolder

func LoadImageFolder(folder string) ([]image.Image, error)

LoadImageFolder loads all images in a directory and returns them as a slice.

func SaveImage

func SaveImage(file string, img image.Image) error

SaveImage saves an image to a file.

Types

type Color

type Color [4]uint8

func DiscardLeastSignificantBits

func DiscardLeastSignificantBits(c Color, bits int) Color

func GetColor

func GetColor(img image.Image, x, y int) Color

type ConstraintFunc

type ConstraintFunc func(image.Image, Direction) ConstraintId

ConstraintFunc is a function that returns an adjacency hash for an image tile in a specified direction.

var DefaultConstraintFunc ConstraintFunc = GetConstraintFunc(3)

The default constraint function uses color values to generate an adjacency.

func GetConstraintFunc added in v0.0.3

func GetConstraintFunc(count int) ConstraintFunc

GetConstraintFunc returns a constraint function that uses the given number of color lookups

type ConstraintId

type ConstraintId [8]byte

Adjacency constraint type.

This is a an arbitrary value that should be the same between two or more modules. It represents modules that can be next to each other.

This codebase combines 3 color values along the edges of input tiles and then uses sha256 to generate a hash. Only the first 8 bytes are kept.

The color values are reduced to 4 bits each, discarding the least significant bits. This rounds the color values to allow for some flexibility.

func GetConstraintFromHex

func GetConstraintFromHex(s string) ConstraintId

GetConstraintFromHex returns the adjacency constraint id for the given hex

func (ConstraintId) Equal added in v0.0.3

func (c ConstraintId) Equal(o ConstraintId) bool

Equal returns true if the two adjacency constraints are equal.

type Direction

type Direction int

Direction type, one of Up, Down, Left, Right.

Used to specify the direction of a constraint between two modules.

const (
	Up Direction = iota
	Down
	Left
	Right
)

func (Direction) Opposite

func (d Direction) Opposite() Direction

Opposite returns the opposite direction of "this" direction.

func (Direction) ToString

func (d Direction) ToString() string

ToString returns the string representation of the direction.

type IsPossibleFunc added in v0.0.4

type IsPossibleFunc func(state *Module, from, to *Slot, d Direction) bool

IsPossibleFunc is a function that returns whether or not a module is possible given a slot and direction. Use this if you'd like custom logic.

type Module

type Module struct {
	Index       int             // The index of the module in the input tiles
	Adjacencies [4]ConstraintId // Adjacency constraints for each direction
	Image       image.Image     // The tile image for the module
}

Module represents a single module in the wave function as described by Oskar Stalberg. A module is a possible tile that might exist at a slot in the wave function grid. It can be thought of as a single state of a superposition.

func (*Module) IsPossibleFrom

func (m *Module) IsPossibleFrom(from *Slot, forward Direction) bool

IsPossibleFrom returns true if the given module is possible from the given direction.

type Slot

type Slot struct {
	X, Y          int       // Coordinates of the slot
	Superposition []*Module // Possible modules at the slot
}

A Slot is a single point in space inside the Wave function. It can be in a superposition of many modules until collapsed.

A Slot that has no superposition (length == 0) is considered to be in a contridiction state. Meaning that the wave function was not able to resolve it.

A Slot that has a single module in its superposition is considered to be a collapsed slot and only has one possible module at its coordinates.

func (*Slot) Collapse

func (s *Slot) Collapse()

Collapse chooses a random module from the list of superpositions available to it. Its superposition list is set to the single module chosen.

type Wave

type Wave struct {
	Width, Height    int       // Width and height of the grid
	Input            []*Module // Input tiles (possible tiles at each slot)
	PossibilitySpace []*Slot   // The 2D grid of slots

	History []*Slot // Slots that have been visited during the current/last collapse iteration

	// Override this if you'd like custom logic when checking if a state is
	// possible from a direction. This is useful if you'd like to slow down the
	// collapse or add probabilities.
	IsPossibleFn IsPossibleFunc
}

Wave holds the state of a wave collapse function as described by Oskar Stalberg.

The wave is a recursive algorithm that collapses the possibility space of a 2D grid into a single output. Specifically, it is a 2D array of slots that are all in a superposition state of one or more modules; each module is a possible tile that might exist at that slot.

The algorithm is described in detail by Oskar Stalberg at several conferences. It is described in detail during the following talk: https://www.youtube.com/watch?v=0bcZb-SsnrA&t=350s

An example implmentation of the algorithm can be found here: https://oskarstalberg.com/game/wave/wave.html

func New

func New(tiles []image.Image, width, height int) *Wave

New creates a new wave collapse function with the given width and height and possible image tiles.

Constraints are automatically generated by looking at the color values of the pixels along each of the four edges of the tile. Any tiles that should potentially be neighbors should have the same color values along the edges. Otherwise, the tile will not be considered a neighbor.

When generating constraints, only 3 pixels per edge are considered. For example, for the top edge, it looks at the top-left, then top-middle, then top-right pixels. likewise for the right edge, it would look at the top-right, then middle-right, then bottom-right.

func NewWithCustomConstraints

func NewWithCustomConstraints(tiles []image.Image, width, height int, fn ConstraintFunc) *Wave

NewWithCustomConstraints creates a new wave collapse function with the given adjacency constraint calculation function. Use this if you'd like custom logic for specifying constraints.

func (*Wave) Collapse

func (w *Wave) Collapse(attempts int) error

Collapse recursively collapses the possibility space for each slot into a single module.

Important: Not all tile sets will allways produce a solution, so this function can return an error if a contradiction is found. You can still export the image of a failed collapse to see which of your tiles is causing issues for you.

func (*Wave) CollapseRandomSlot

func (w *Wave) CollapseRandomSlot() *Slot

CollapseRandomSlot takes a random slot and collapses it into a single module. If the slot is already collapsed, it will pick another slot and try again.

func (*Wave) ExportImage

func (w *Wave) ExportImage() image.Image

Export takes the current state of the wave collapse function and exports it as an image. Any slots that have not been collapsed will be transparent. Contradictions will be red.

func (*Wave) GetNeighbor

func (w *Wave) GetNeighbor(s *Slot, d Direction) *Slot

GetNeighbor returns the slot in the given direction from the given slot.

func (*Wave) GetPossibleModules

func (w *Wave) GetPossibleModules(a, b *Slot, d Direction) []*Module

GetPossibleModules returns a list of modules that are possible when traveling from slot "a" to slot "b" with the provided direction.

func (*Wave) GetSlot

func (w *Wave) GetSlot(x, y int) *Slot

GetSlot returns the slot at the given coordinates in this wave function.

func (*Wave) HasNeighbor

func (w *Wave) HasNeighbor(s *Slot, d Direction) bool

HasNeighbor checks if the given slot has a neighbor in the given direction (edges of the grid don't have neighbors).

func (*Wave) HasVisited

func (w *Wave) HasVisited(s *Slot) bool

HasVisited checks if the given slot has been visited during the current collapse iteration. This is used to prevent infinite recursion.

func (*Wave) Initialize

func (w *Wave) Initialize(seed int)

Initialize sets up the wave collapse function so that every slot is in a superposition of all input tiles/modules.

Each module is equally likely to be at each slot.

func (*Wave) IsCollapsed

func (w *Wave) IsCollapsed() bool

IsCollapsed checks if the given slot is collapsed. Either in a contradiction state or to a single possible value.

func (*Wave) Recurse

func (w *Wave) Recurse() error

Recurse collapses the wave collapse function recursively.

Jump to

Keyboard shortcuts

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