sudoku

package module
v0.0.0-...-6987203 Latest Latest
Warning

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

Go to latest
Published: Apr 10, 2022 License: Apache-2.0 Imports: 14 Imported by: 0

README

#sudoku sudoku is a package written in go for generating and solving sudoku puzzles. Notably, it is able to solve a puzzle like a human would, and aspires to provide high-quality difficulty ratings for puzzles based on a model trained on hundreds of thousands of solves by real users.

This is my first non-trivial project written in Go. It is very much a work in progress, and may be rough/broken/over-engineered/non-idiomatic/slow in places. Pull requests welcome!

You can find documentation at http://godoc.org/github.com/jkomoros/sudoku

You can install all of the commands (including i-sudoku) by running go install github.com/jkomoros/...@latest

##Included commands

###i-sudoku

i-sudoku is an interactive command line sudoku game. Part of its goal is to make debugging hints and human solves easier, although it is sufficiently full-featured to stand on its own as a fun sudoku program.

###dokugen

Dokugen is a simple command line utility exposing the main functionality of the sudoku package, including solving, generating, and difficutly-rating puzzles.

Run dokugen -h to see information on command line options.

###dokugen-analysis

dokugen-analysis is an analysis utility used to analyze a large collection of real-world user solves in order to generate a model to rate the difficulty of provided puzzles.

komoroske.com/sudoku has been running for over 8 years and during that time has logged information on over 800,000 solves by real users. dokugen-analysis uses that information to determine how difficult puzzles are, as judged by the solve time for real users. The analysis includes using markov chains to do rank aggregation to come up with a cross-user rating of difficulty.

This analysis is then used to train a simple multiple linear regression model that provides difficulty ratings for puzzles.

The tool is not particularly useful unless you have your own large database of solve times.

Documentation

Overview

sudoku is a package for generating, solving, and rating the difficulty of sudoku puzzles. Notably, it is able to solve a puzzle like a human would, and aspires to provide high-quality difficulty ratings for puzzles based on a model trained on hundreds of thousands of solves by real users.

The primary types are Grid and MutableGrid, which are interfaces. The Grid interface contains only read-only methods, and MutableGrid contains all of Grid's methods, plus mutating methods. Under the covers, this indirection allows expensive searching operations that require hundreds of grid allocations to be much more efficient.

To get a MutableGrid version of a Grid, use Grid.MutableCopy. MutableGrids can be used as-is wherever a Grid is required.

To load a grid, see Load, LoadSDK, and LoadSDKFromFile.

To generate a new puzzle, see GenerateGrid.

To Solve a puzzle, see Grid.Solve.

To solve a puzzle like a human would, see Grid.HumanSolve.

Index

Constants

View Source
const (
	ALT_0       = "."
	ROW_SEP     = "\n"
	COL_SEP     = "|"
	ALT_COL_SEP = "||"
)

Constants for important aspects of the accepted format

View Source
const (
	DIAGRAM_IMPOSSIBLE = " "
	DIAGRAM_RIGHT      = "|"
	DIAGRAM_BOTTOM     = "-"
	DIAGRAM_CORNER     = "+"
	DIAGRAM_NUMBER     = "•"
	DIAGRAM_LOCKED     = "X"
)

Constants for how important parts of the diagram are printed out

View Source
const BLOCK_DIM = 3

BLOCK_DIM is the height and width of each block within the grid.

DIM is the dimension of the grid (the height and width)

Variables

View Source
var (
	//All of the 'normal' Techniques that will be used to solve the puzzle
	Techniques []SolveTechnique
	//The special GuessTechnique that is used only if no other techniques find options.
	GuessTechnique SolveTechnique
	//Every technique that HumanSolve could ever use, including the oddball Guess technique.
	AllTechniques []SolveTechnique
	//Every variant name for every TechniqueVariant that HumanSolve could ever use.
	AllTechniqueVariants []string
)

The list of techniques that HumanSolve will use to try to solve the puzzle, with the oddball Guess split out.

Functions

func DifficultyModelHash

func DifficultyModelHash() string

DifficultyModelHash is a unique string representing the exact difficulty model in use. Every time a new model is trained or loaded, this value will change. Therefore, if the value is different than last time you checked, the model has changed. This is useful for throwing out caches that assume the same difficulty model is in use.

func LoadDifficultyModel

func LoadDifficultyModel(model map[string]float64)

LoadDifficultyModel loads in a new difficulty model to use to score puzzles' difficulties. This will automatically change what DifficultyModelHash will return.

Types

type Cell

type Cell interface {
	//Row returns the cell's row in its parent grid.
	Row() int

	//Col returns the cell's column in its parent grid.
	Col() int

	//Block returns the cell's block in its parent grid.
	Block() int

	//InGrid returns a reference to a cell in the provided grid that has the same
	//row/column as this cell. Effectively, this cell's analogue in the other
	//grid.
	InGrid(grid Grid) Cell

	//MutableInGrid is like InGrid, but will only work on grids that are mutable.
	MutableInGrid(grid MutableGrid) MutableCell

	//Number returns the number the cell is currently set to.
	Number() int

	//Mark reads out whether the given mark has been set for this cell. See
	//SetMark for a description of what marks represent.
	Mark(number int) bool

	//Marks returns an IntSlice with each mark, in ascending order.
	Marks() IntSlice

	//Possible returns whether or not a given number is legal to fill via
	//SetNumber, given the state of the grid (specifically, the cell's neighbors)
	//and the numbers the cell was told to explicitly exclude via SetExclude. If
	//the cell is already filled with a number, it will return false for all
	//numbers.
	Possible(number int) bool

	//Possibilities returns a list of all current possibilities for this cell: all
	//numbers for which cell.Possible returns true.
	Possibilities() IntSlice

	//Excluded returns whether or not the given number has been specifically
	//excluded with SetExcluded.
	Excluded(number int) bool

	//Invalid returns true if the cell has no valid possibilities to fill in,
	//implying that the grid is in an invalid state because this cell cannot be
	//filled with a number without violating a constraint.
	Invalid() bool

	//Locked returns whether or not the cell is locked. See Lock for more
	//information on the concept of locking.
	Locked() bool

	//SymmetricalPartner returns the cell's partner in the grid, based on the type
	//of symmetry requested.
	SymmetricalPartner(symmetry SymmetryType) Cell

	//Neighbors returns a CellSlice of all of the cell's neighbors--the other
	//cells in its row, column, and block. The set of neighbors is the set of
	//cells that this cell's number must not conflict with.
	Neighbors() CellSlice

	//String returns a debug-friendly summary of the Cell.
	String() string

	//DiagramExtents returns the top, left, height, and width coordinate in
	//grid.Diagram's output that  corresponds to the contents of this cell. The
	//top left corner is 0,0
	DiagramExtents() (top, left, height, width int)

	//Grid returns a reference to the Grid that this Cell is associated with.
	Grid() Grid

	//Reference returns a CellReference corresponding to this cell.
	Reference() CellRef
	// contains filtered or unexported methods
}

Cell represents a single cell within a grid. It maintains information about the number that is filled, the numbers that are currently legal given the filled status of its neighbors, and whether any possibilities have been explicitly excluded by solve techniques. Cells should not be constructed on their own; create a Grid and grab references to the cells from there. Cell does not contain methods to mutate the Cell. See MutableCell for that.

type CellModification

type CellModification struct {
	//The cell representing the cell to modify. The cell's analog (at the same
	//row, col address) will be modified in the new grid.
	Cell CellRef
	//The number to put in the cell. Negative numbers signify no changes.
	Number int
	//The excludes to proactively set. Invalid numbers will be ignored.
	//Indexes not listed will be left the same.
	ExcludesChanges map[int]bool
	//The marks to proactively set. Invalid numbers will be ignored.
	//Indexes not listed will be left the same.
	MarksChanges map[int]bool
}

CellModification represents a modification to be made to a given Cell in a grid.

type CellRef

type CellRef struct {
	Row int
	Col int
}

CellReference is a reference to a generic cell located at a specific row and column.

func (CellRef) Block

func (self CellRef) Block() int

Block returns the block that this CellReference is in.

func (CellRef) Cell

func (self CellRef) Cell(grid Grid) Cell

Cell returns the Cell in the given grid that this CellReference refers to.

func (CellRef) MutableCell

func (self CellRef) MutableCell(grid MutableGrid) MutableCell

MutableCell returns the MutableCell in the given grid that this CellReference refers to.

func (CellRef) String

func (self CellRef) String() string

type CellRefSlice

type CellRefSlice []CellRef

CellReferenceSlice is a slice of CellReferences with many convenience methods.

func (CellRefSlice) AllBlocks

func (self CellRefSlice) AllBlocks() IntSlice

AllBlocks returns all of the blocks for cells in this slice.

func (CellRefSlice) AllCols

func (self CellRefSlice) AllCols() IntSlice

AllCols returns all of the columns for cells in this slice.

func (CellRefSlice) AllRows

func (self CellRefSlice) AllRows() IntSlice

AllRows returns all of the rows for cells in this slice.

func (CellRefSlice) Block

func (self CellRefSlice) Block() int

Block returns the row that at least one of the cells is in. If SameBlock() is false, the Block may be any of the blocks in the set.

func (CellRefSlice) CellSlice

func (self CellRefSlice) CellSlice(grid Grid) CellSlice

CellSlice returns a CellSlice with Cells corresponding to our references, in the given grid.

func (CellRefSlice) Col

func (self CellRefSlice) Col() int

Col returns the column that at least one of the cells is in. If SameCol() is false, the column may be any of the columns in the set.

func (CellRefSlice) CollectNums

func (self CellRefSlice) CollectNums(fetcher func(CellRef) int) IntSlice

CollectNums collects the result of running fetcher across all items in the list.

func (CellRefSlice) Description

func (self CellRefSlice) Description() string

Description returns a human-readable description of the cells in the list, like "(0,1), (0,2), and (0,3)"

func (CellRefSlice) Difference

func (self CellRefSlice) Difference(other CellRefSlice) CellRefSlice

Difference returns a new CellReferenceSlice that contains all of the cells in the receiver that are not also in the other.

func (CellRefSlice) Filter

func (self CellRefSlice) Filter(filter func(CellRef) bool) CellRefSlice

Filter returns a new CellReferenceSlice that includes all cells where filter returned true.

func (CellRefSlice) Intersection

func (self CellRefSlice) Intersection(other CellRefSlice) CellRefSlice

Intersection returns a new CellSlice that represents the intersection of the two CellReferenceSlices; that is, the cells that appear in both slices.

func (CellRefSlice) InverseSubset

func (self CellRefSlice) InverseSubset(indexes IntSlice) CellRefSlice

InverseSubset returns a new CellReferenceSlice that contains all of the elements from the list that are *not* at the indexes provided in the IntSlice. See also Subset.

func (CellRefSlice) MutableCellSlice

func (self CellRefSlice) MutableCellSlice(grid MutableGrid) MutableCellSlice

CellSlice returns a MutableCellSlice with MutableCells corresponding to our references, in the given grid.

func (CellRefSlice) RemoveCells

func (self CellRefSlice) RemoveCells(targets CellRefSlice) CellRefSlice

RemoveCells returns a new CellReferenceSlice that does not contain any of the cells included in the provided CellReferenceSlice.

func (CellRefSlice) Row

func (self CellRefSlice) Row() int

Row returns the row that at least one of the cells is in. If SameRow() is false, the Row may be any of the rows in the set.

func (CellRefSlice) SameBlock

func (self CellRefSlice) SameBlock() bool

SameBlock returns true if all cells are in the same block.

func (CellRefSlice) SameCol

func (self CellRefSlice) SameCol() bool

SameCol returns true if all cells are in the same column.

func (CellRefSlice) SameRow

func (self CellRefSlice) SameRow() bool

SameRow returns true if all cells are in the same row.

func (CellRefSlice) Sort

func (self CellRefSlice) Sort()

Sort mutates the provided CellReferenceSlice so that the cells are in order from left to right, top to bottom based on their position in the grid.

func (CellRefSlice) Subset

func (self CellRefSlice) Subset(indexes IntSlice) CellRefSlice

Subset returns a new CellReferenceSlice that is the subset of the list including the items at the indexes provided in the IntSlice. See also InverseSubset.

func (CellRefSlice) Union

func (self CellRefSlice) Union(other CellRefSlice) CellRefSlice

Union returns a new CellSlice that contains all of the cells that are in either the receiver or the other CellSlice.

type CellSlice

type CellSlice []Cell

CellSlice is a list of cells with many convenience methods for doing common operations on them. MutableCellSlice is similar, but operates on a slice of MutableCells.

func (CellSlice) AllBlocks

func (self CellSlice) AllBlocks() IntSlice

AllBlocks returns all of the blocks for cells in this slice.

func (CellSlice) AllCols

func (self CellSlice) AllCols() IntSlice

AllCols returns all of the columns for cells in this slice.

func (CellSlice) AllRows

func (self CellSlice) AllRows() IntSlice

AllRows returns all of the rows for cells in this slice.

func (CellSlice) Block

func (self CellSlice) Block() int

Block returns the row that at least one of the cells is in. If SameBlock() is false, the Block may be any of the blocks in the set.

func (CellSlice) CellReferenceSlice

func (self CellSlice) CellReferenceSlice() CellRefSlice

CellReferenceSlice returns a CellReferenceSlice that corresponds to the cells in this CellSlice.

func (CellSlice) Col

func (self CellSlice) Col() int

Col returns the column that at least one of the cells is in. If SameCol() is false, the column may be any of the columns in the set.

func (CellSlice) CollectNums

func (self CellSlice) CollectNums(fetcher func(Cell) int) IntSlice

CollectNums collects the result of running fetcher across all items in the list.

func (CellSlice) Difference

func (self CellSlice) Difference(other CellSlice) CellSlice

Difference returns a new CellSlice that contains all of the cells in the receiver that are not also in the other.

func (CellSlice) FilledNums

func (self CellSlice) FilledNums() IntSlice

FilledNums returns an IntSlice representing all of the numbers that have been actively set on cells in the list. Cells that are empty (are set to '0') are not included.

func (CellSlice) Filter

func (self CellSlice) Filter(filter func(Cell) bool) CellSlice

Filter returns a new CellSlice that includes all cells where filter returned true.

func (CellSlice) FilterByFilled

func (self CellSlice) FilterByFilled() CellSlice

FilterByFilled returns a new CellSlice with only the cells that have a number in them.

func (CellSlice) FilterByHasPossibilities

func (self CellSlice) FilterByHasPossibilities() CellSlice

FilterByHasPossibilities returns a new CellSlice with only cells that have 0 or more open possibilities.

func (CellSlice) FilterByNumPossibilities

func (self CellSlice) FilterByNumPossibilities(target int) CellSlice

FilterByNumPossibles returns a new CellSlice with only cells that have precisely the provided number of possible numbers.

func (CellSlice) FilterByPossible

func (self CellSlice) FilterByPossible(possible int) CellSlice

FilterByPossible returns a new CellSlice with only the cells in the list that have the given number as an active possibility.

func (CellSlice) FilterByUnfilled

func (self CellSlice) FilterByUnfilled() CellSlice

FilterByUnfilled returns a new CellSlice with only the cells in the list that are not filled with any number.

func (CellSlice) Intersection

func (self CellSlice) Intersection(other CellSlice) CellSlice

Intersection returns a new CellSlice that represents the intersection of the two CellSlices; that is, the cells that appear in both slices.

func (CellSlice) InverseSubset

func (self CellSlice) InverseSubset(indexes IntSlice) CellSlice

InverseSubset returns a new CellSlice that contains all of the elements from the list that are *not* at the indexes provided in the IntSlice. See also Subset.

func (CellSlice) Map

func (self CellSlice) Map(mapper func(Cell))

Map executes the mapper function on each cell in the list.

func (CellSlice) PossibilitiesUnion

func (self CellSlice) PossibilitiesUnion() IntSlice

PossibilitiesUnion returns an IntSlice that is the union of all active possibilities in cells in the set.

func (CellSlice) RemoveCells

func (self CellSlice) RemoveCells(targets CellSlice) CellSlice

RemoveCells returns a new CellSlice that does not contain any of the cells included in the provided CellSlice.

func (CellSlice) Row

func (self CellSlice) Row() int

Row returns the row that at least one of the cells is in. If SameRow() is false, the Row may be any of the rows in the set.

func (CellSlice) SameBlock

func (self CellSlice) SameBlock() bool

SameBlock returns true if all cells are in the same block.

func (CellSlice) SameCol

func (self CellSlice) SameCol() bool

SameCol returns true if all cells are in the same column.

func (CellSlice) SameRow

func (self CellSlice) SameRow() bool

SameRow returns true if all cells are in the same row.

func (CellSlice) Sort

func (self CellSlice) Sort()

Sort mutates the provided CellSlice so that the cells are in order from left to right, top to bottom based on their position in the grid.

func (CellSlice) Subset

func (self CellSlice) Subset(indexes IntSlice) CellSlice

Subset returns a new CellSlice that is the subset of the list including the items at the indexes provided in the IntSlice. See also InverseSubset.

func (CellSlice) Union

func (self CellSlice) Union(other CellSlice) CellSlice

Union returns a new CellSlice that contains all of the cells that are in either the receiver or the other CellSlice.

type CompoundSolveStep

type CompoundSolveStep struct {
	PrecursorSteps []*SolveStep
	FillStep       *SolveStep
	// contains filtered or unexported fields
}

CompoundSolveStep is a special type of meta SolveStep that has 0 to n precursor steps that cull possibilities (instead of filling in a number), followed by precisely one fill step. It reflects the notion that logically only fill steps actually advance the grid towards being solved, and all cull steps are in service of getting the grid to a state where a Fill step can be found. CompoundSolveSteps are the primary units returned from HumanSolutions.

func (*CompoundSolveStep) Apply

func (c *CompoundSolveStep) Apply(grid MutableGrid)

Apply applies all of the steps in the CompoundSolveStep to the grid in order: first each of the PrecursorSteps in order, then the fill step. It is equivalent to calling Apply() on every step returned by Steps().

func (*CompoundSolveStep) Description

func (c *CompoundSolveStep) Description() string

Description returns a human-readable sentence describing what the CompoundSolveStep instructs the user to do, and what reasoning it used to decide that this step was logically valid to apply.

func (*CompoundSolveStep) Modifications

func (c *CompoundSolveStep) Modifications() GridModification

Modifications returns the set of modifications that this CompoundSolveStep would make to a Grid if Apply were called.

func (*CompoundSolveStep) ScoreExplanation

func (c *CompoundSolveStep) ScoreExplanation() []string

ScoreExplanation returns a in-depth descriptive string about why this compound step was scored the way it was. Intended for debugging purposes; its primary use is in i-sudoku.

func (*CompoundSolveStep) Steps

func (c *CompoundSolveStep) Steps() []*SolveStep

Steps returns the simple list of SolveSteps that this CompoundSolveStep represents.

type DifficultySignals

type DifficultySignals map[string]float64

DifficultySignals is a collection of names to float64 values, representing the various signals extracted from a SolveDirections, and used for the Difficulty calculation. Generally not useful to package users.

type GenerationOptions

type GenerationOptions struct {
	//symmetrty and symmetryType control the aesthetics of the generated grid. symmetryPercentage
	//controls roughly what percentage of cells with have a filled partner across the provided plane of
	//symmetry.
	Symmetry           SymmetryType
	SymmetryPercentage float64
	//The minimum number of cells to leave filled in the puzzle. The generated puzzle might have
	//more filled cells. A value of DIM * DIM - 1, for example, would return an extremely trivial
	//puzzle.
	MinFilledCells int
}

GenerationOptions provides configuration options for generating a sudoku puzzle.

func DefaultGenerationOptions

func DefaultGenerationOptions() *GenerationOptions

DefaultGenerationOptions returns a GenerationOptions object configured to have reasonable defaults.

type Grid

type Grid interface {

	//Copy returns a new immutable grid that has all of the same observable
	//state (including set numbers, locks, excludes, marks, etc)
	Copy() Grid

	//MutableCopy returns a new, mutable grid that has all of the same
	//starting state (including set numbers, locks, excludes, marks, etc.)
	MutableCopy() MutableGrid

	//CopyWithModifications returns a new immutable Grid that has the given
	//modifications applied.
	CopyWithModifications(modifications GridModification) Grid

	//Cells returns a CellSlice with pointers to every cell in the grid,
	//from left to right and top to bottom.
	Cells() CellSlice

	//Row returns a CellSlice containing all of the cells in the given row (0
	//indexed), in order from left to right.
	Row(index int) CellSlice

	//Col returns a CellSlice containing all of the cells in the given column (0
	//indexed), in order from top to bottom.
	Col(index int) CellSlice

	//Block returns a CellSlice containing all of the cells in the given block (0
	//indexed), in order from left to right, top to bottom.
	Block(index int) CellSlice

	//Cell returns a reference to a specific cell (zero-indexed) in the grid.
	Cell(row, col int) Cell

	//Solved returns true if all cells are filled without violating any
	//constraints; that is, the puzzle is solved.
	Solved() bool

	//Invalid returns true if any numbers are set in the grid that conflict with
	//numbers set in neighborhing cells; when a valid solution cannot be arrived
	//at by continuing to fill additional cells.
	Invalid() bool

	//Empty returns true if none of the grid's cells are filled.
	Empty() bool

	//DataString represents the serialized format of the grid (not including
	//excludes) in canonical sdk format; the output is valid to pass to
	//Grid.Load(). If you want other formats, see the sdkconverter subpackage.
	DataString() string

	//String returns a concise representation of the grid appropriate for printing
	//to the screen. Currently simply an alias for DataString.
	String() string

	//Diagram returns a verbose visual representation of a grid, representing not
	//just filled numbers but also what numbers in a cell are possible. If
	//showMarks is true, instead of printing the possibles, it will print only the
	//activley added marks.
	Diagram(showMarks bool) string

	//HumanSolution returns the SolveDirections that represent how a human
	//would solve this puzzle. If options is nil, will use reasonable
	//defaults.
	HumanSolution(options *HumanSolveOptions) *SolveDirections

	//Hint returns a SolveDirections with precisely one CompoundSolveStep that is
	//a reasonable next step to move the puzzle towards being completed. It is
	//effectively a hint to the user about what Fill step to do next, and why it's
	//logically implied; the truncated return value of HumanSolve. Returns nil if
	//the puzzle has multiple solutions or is otherwise invalid. If options is
	//nil, will use reasonable defaults. optionalPreviousSteps, if provided,
	//serves to help the algorithm pick the most realistic next steps.
	Hint(options *HumanSolveOptions, optionalPreviousSteps []*CompoundSolveStep) *SolveDirections

	//Difficulty returns a value between 0.0 and 1.0, representing how hard the
	//puzzle would be for a human to solve. :This is an EXTREMELY expensive method
	//(although repeated calls without mutating the grid return a cached value
	//quickly). It human solves the puzzle, extracts signals out of the
	//solveDirections, and then passes those signals into a machine-learned model
	//that was trained on hundreds of thousands of solves by real users in order
	//to generate a candidate difficulty. It then repeats the process multiple
	//times until the difficultly number begins to converge to an average.
	Difficulty() float64

	//NumSolutions returns the total number of solutions found in the grid when it
	//is solved forward from this point. A valid Sudoku puzzle has only one
	//solution.
	NumSolutions() int

	//HasSolution returns true if the grid has at least one solution.
	HasSolution() bool

	//HasMultipleSolutions returns true if the grid has more than one solution.
	HasMultipleSolutions() bool

	//Solutions returns a slice of grids that represent possible solutions if you
	//were to solve forward this grid. The current grid is not modified. If there
	//are no solutions forward from this location it will return a slice with
	//len() 0.
	Solutions() []Grid

	//HumanSolvePossibleSteps returns a list of CompoundSolveSteps that could
	//apply at this state, along with the probability distribution that a human
	//would pick each one. The optional previousSteps argument is the list of
	//CompoundSolveSteps that have been applied to the grid so far, and is used
	//primarily to tweak the probability distribution and make, for example, it
	//more likely to pick cells in the same block as the cell that was just
	//filled. This method is the workhorse at the core of HumanSolve() and is
	//exposed here primarily so users of this library can get a peek at which
	//possibilites exist at each step. cmd/i-sudoku is one user of this method.
	HumanSolvePossibleSteps(options *HumanSolveOptions, previousSteps []*CompoundSolveStep) (steps []*CompoundSolveStep, distribution ProbabilityDistribution)
	// contains filtered or unexported methods
}

Grid is the primary type in the package. It represents a DIMxDIM sudoku puzzle that can be acted on in various ways. Grid is read-only; the way to modify it is to create a copy with CopyWithModifications. For grids that can be mutated directly, see MutableGrid.

func Load

func Load(data string) Grid

Load takes the string data and returns a puzzle with that data. The format is the 'sdk' format: a `.` marks an empty cell, a number denotes a filled cell, and an (optional) newline marks a new row. Load also accepts other variations on the sdk format, including one with a `|` between each cell. For other sudoku formats see the sdkconverter subpackage. For a MutableGrid, see MutableLoad.

func LoadSDK

func LoadSDK(data string) Grid

LoadSDK loads a puzzle in SDK format. Unlike Load, LoadSDK "locks" the cells that are filled. See cell.Lock for more on the concept of locking. For a MutableGrid, see MutableLoadSDK.

func LoadSDKFromFile

func LoadSDKFromFile(path string) (Grid, error)

LoadSDKFromFile is a simple convenience wrapper around LoadSDK that loads a grid based on the contents of the file at the given path. For a MutableGrid, see MutableLoadSDKFromFile.

type GridModification

type GridModification []*CellModification

GridModification is a series of CellModifications to apply to a Grid.

type HumanSolveOptions

type HumanSolveOptions struct {
	//At each step in solving the puzzle, how many candidate SolveSteps should
	//we generate before stopping the search for more? Higher values will give
	//more 'realistic' solves, but at the cost of *much* higher performance
	//costs. Also note that the difficulty may be wrong if the difficulty
	//model in use was trained on a different NumOptionsToCalculate.
	NumOptionsToCalculate int
	//Which techniques to try at each step of the puzzle, sorted in the order
	//to try them out (generally from cheapest to most expensive). A value of
	//nil will use Techniques (the default). Any GuessTechniques will be
	//ignored.
	TechniquesToUse []SolveTechnique
	//NoGuess specifies that even if no other techniques work, the HumanSolve
	//should not fall back on guessing, and instead just return failure.
	NoGuess bool
	// contains filtered or unexported fields
}

HumanSolveOptions configures how precisely the human solver should operate. Passing nil where a HumanSolveOptions is expected will use reasonable defaults. Note that the various human solve methods may mutate your options object.

func DefaultHumanSolveOptions

func DefaultHumanSolveOptions() *HumanSolveOptions

DefaultHumanSolveOptions returns a HumanSolveOptions object configured to have reasonable defaults.

type IntSlice

type IntSlice []int

IntSlice is a list of ints, with many convenience methods specific to sudoku.

func (IntSlice) Description

func (self IntSlice) Description() string

Description returns a human readable description of the ints in the set, like "7, 4, and 3"

func (IntSlice) Difference

func (self IntSlice) Difference(other IntSlice) IntSlice

Difference returns a new IntSlice that contains all of the ints in the receiver that are not also in other.

func (IntSlice) Intersection

func (self IntSlice) Intersection(other IntSlice) IntSlice

Intersection returns a new IntSlice that represents the intersection of the two IntSlices, that is, the ints that appear in both slices.

func (IntSlice) Same

func (self IntSlice) Same() bool

Same returns true if all ints in the slice are the same.

func (IntSlice) SameAs

func (self IntSlice) SameAs(other IntSlice) bool

SameAs returns true if the receiver and otherSlice have the same ints in the same order. See also SameContentAs.

func (IntSlice) SameContentAs

func (self IntSlice) SameContentAs(otherSlice IntSlice) bool

SameContetnAs returns true if the receiver and otherSlice have the same list of ints (although not necessarily the same ordering of them)

func (IntSlice) Sort

func (self IntSlice) Sort()

Sort sorts the IntSlice in place from small to large.

func (IntSlice) Subset

func (self IntSlice) Subset(indexes IntSlice) IntSlice

Subset returns a new IntSlice like the receiver, but with only the ints at the provided indexes kept.

func (IntSlice) Unique

func (self IntSlice) Unique() IntSlice

Unique returns a new IntSlice like the receiver, but with any duplicates removed. Order is not preserved.

type MutableCell

type MutableCell interface {
	//MutableCell contains all of Cell's (read-only) methods.
	Cell

	//MutableNeighbors returns a MutableCellSlice of all of the cell's
	//neighbors--the other cells in its row, column, and block. The set of
	//neighbors is the set of cells that this cell's number must not conflict
	//with.
	MutableNeighbors() MutableCellSlice

	//MutableSymmetricalPartner returns the cell's mutable partner in the
	//grid, based on the type of symmetry requested.
	MutableSymmetricalPartner(symmetry SymmetryType) MutableCell

	//SetNumber explicitly sets the number of the cell. This operation could cause
	//the grid to become invalid if it conflicts with its neighbors' numbers. This
	//operation will affect the Possiblities() of its neighbor cells.
	SetNumber(number int)

	//SetExcluded defines whether a possibility is considered not feasible, even
	//if not directly precluded by the Number()s of the cell's neighbors. This is
	//used by advanced HumanSolve techniques that cull possibilities that are
	//logically excluded by the state of the grid, in a non-direct way. The state
	//of Excluded bits will affect the results of this cell's Possibilities()
	//list.
	SetExcluded(number int, excluded bool)

	//ResetExcludes sets all excluded bits to false, so that Possibilities() will
	//be based purely on direct implications of the Number()s of neighbors. See
	//also SetExcluded.
	ResetExcludes()

	//SetMark sets the mark at the given index to true. Marks represent number
	//marks proactively added to a cell by a user. They have no effect on the
	//solver or human solver; they only are visible when Diagram(true) is called.
	SetMark(number int, mark bool)

	//ResetMarks removes all marks. See SetMark for a description of what marks
	//represent.
	ResetMarks()

	//Lock 'locks' the cell. Locking represents the concept of cells that are set
	//at the beginning of the puzzle and that users may not modify. Locking does
	//not change whether calls to SetNumber or SetMark will fail; it only impacts
	//Diagram().
	Lock()

	//Unlock 'unlocks' the cell. See Lock for more information on the concept of
	//locking.
	Unlock()

	//MutableGrid returns a reference to the MutableGrid this MutableCell is
	//associated with.
	MutableGrid() MutableGrid
	// contains filtered or unexported methods
}

MutableCell is a Cell that also has methods that allow mutation of the cell. They are generally gathered from Mutable* methods on a MutableGrid.

type MutableCellSlice

type MutableCellSlice []MutableCell

MutableCellSlice is a CellSlice that contains references to MutableCells. It doesn't have analogues for each CellSlice method; only ones that return a CellSlice. Note: MutableCellSlices are not mutable themselves; the "mutable" refers to the MutableCell.

func (MutableCellSlice) CellReferenceSlice

func (self MutableCellSlice) CellReferenceSlice() CellRefSlice

CellReferenceSlice returns a CellReferenceSlice that corresponds to the cells in this MutableCellSlice.

func (MutableCellSlice) Difference

func (self MutableCellSlice) Difference(other CellSlice) MutableCellSlice

Difference returns a new CellSlice that contains all of the cells in the receiver that are not also in the other.

func (MutableCellSlice) Filter

func (self MutableCellSlice) Filter(filter func(Cell) bool) MutableCellSlice

Filter returns a new CellSlice that includes all cells where filter returned true.

func (MutableCellSlice) FilterByFilled

func (self MutableCellSlice) FilterByFilled() MutableCellSlice

FilterByFilled returns a new CellSlice with only the cells that have a number in them.

func (MutableCellSlice) FilterByHasPossibilities

func (self MutableCellSlice) FilterByHasPossibilities() MutableCellSlice

FilterByHasPossibilities returns a new CellSlice with only cells that have 0 or more open possibilities.

func (MutableCellSlice) FilterByNumPossibilities

func (self MutableCellSlice) FilterByNumPossibilities(target int) MutableCellSlice

FilterByNumPossibles returns a new CellSlice with only cells that have precisely the provided number of possible numbers.

func (MutableCellSlice) FilterByPossible

func (self MutableCellSlice) FilterByPossible(possible int) MutableCellSlice

FilterByPossible returns a new CellSlice with only the cells in the list that have the given number as an active possibility.

func (MutableCellSlice) FilterByUnfilled

func (self MutableCellSlice) FilterByUnfilled() MutableCellSlice

FilterByUnfilled returns a new CellSlice with only the cells in the list that are not filled with any number.

func (MutableCellSlice) Intersection

func (self MutableCellSlice) Intersection(other CellSlice) MutableCellSlice

Intersection returns a new CellSlice that represents the intersection of the two CellSlices; that is, the cells that appear in both slices.

func (MutableCellSlice) InverseSubset

func (self MutableCellSlice) InverseSubset(indexes IntSlice) MutableCellSlice

InverseSubset returns a new CellSlice that contains all of the elements from the list that are *not* at the indexes provided in the IntSlice. See also Subset.

func (MutableCellSlice) Map

func (self MutableCellSlice) Map(mapper func(MutableCell))

Map executes the mapper function on each cell in the list.

func (MutableCellSlice) RemoveCells

func (self MutableCellSlice) RemoveCells(targets CellSlice) MutableCellSlice

RemoveCells returns a new CellSlice that does not contain any of the cells included in the provided CellSlice.

func (MutableCellSlice) Sort

func (self MutableCellSlice) Sort()

Sort mutates the provided CellSlice so that the cells are in order from left to right, top to bottom based on their position in the grid.

func (MutableCellSlice) Subset

func (self MutableCellSlice) Subset(indexes IntSlice) MutableCellSlice

Subset returns a new CellSlice that is the subset of the list including the items at the indexes provided in the IntSlice. See also InverseSubset.

func (MutableCellSlice) Union

func (self MutableCellSlice) Union(other CellSlice) MutableCellSlice

Union returns a new CellSlice that contains all of the cells that are in either the receiver or the other CellSlice.

type MutableGrid

type MutableGrid interface {
	//MutableGrid contains all of Grid's (read-only) methods.
	Grid

	//Load is like the top-level MutableLoad, but mutates this grid as opposed
	//to returning a new one.
	Load(data string)

	//LoadSDK is like the top-level MutableLoadSDK, but mutates this grid as
	//opposed to returning a new one.
	LoadSDK(data string)

	//ResetExcludes calls ResetExcludes on all cells in the grid. See
	//Cell.SetExcluded for more about excludes.
	ResetExcludes()

	//ResetMarks calls ResetMarks on all cells in the grid. See Cell.SetMark for
	//more about marks.
	ResetMarks()

	//ResetUnlockedCells clears out numbers, marks, and excludes from each cell
	//that is unlocked. In general a locked cell represents a number present in
	//the original puzzle, so this method effectively clears all user
	//modifications back to the start of the puzzle.
	ResetUnlockedCells()

	//UnlockCells unlocks all cells. See cell.Lock for more information on the
	//concept of locking.
	UnlockCells()

	//LockFilledCells locks all cells in the grid that have a number set.
	LockFilledCells()

	//MutableCells returns a MutableCellSlice with pointers to every cell in the
	//grid, from left to right and top to bottom.
	MutableCells() MutableCellSlice

	//MutableRow returns a MutableCellSlice containing all of the cells in the
	//girven row (0 indexed), in order from left to right.
	MutableRow(index int) MutableCellSlice

	//MutableCol returns a MutableCellSlice containing all of the cells in the
	//given column (0 indexed), in order from top to bottom.
	MutableCol(index int) MutableCellSlice

	//MutableBlock returns a MutableCellSlice containing all of the cells in the
	//given block (0 indexed), in order from left to right, top to bottom.
	MutableBlock(index int) MutableCellSlice

	//MutableCell returns a reference to a Mutable Cell at the given location.
	MutableCell(row, col int) MutableCell

	//Fill will find a random filling of the puzzle such that every cell is filled
	//and no cells conflict with their neighbors. If it cannot find one,  it will
	//return false and leave the grid as it found it. Generally you would only
	//want to call this on grids that have more than one solution (e.g. a fully
	//blank grid). Fill provides a good starting point for generated puzzles.
	Fill() bool

	//HumanSolve is the workhorse of the package. It solves the puzzle much like a
	//human would, applying complex logic techniques iteratively to find a
	//sequence of steps that a reasonable human might apply to solve the puzzle.
	//HumanSolve is an expensive operation because at each step it identifies all
	//of the valid logic rules it could apply and then selects between them based
	//on various weightings. HumanSolve endeavors to find the most realistic human
	//solution it can by using a large number of possible techniques with
	//realistic weights, as well as by doing things like being more likely to pick
	//a cell that is in the same row/cell/block as the last filled cell. Returns
	//nil if the puzzle does not have a single valid solution. If options is nil,
	//will use reasonable defaults. Mutates the grid.
	HumanSolve(options *HumanSolveOptions) *SolveDirections

	//Solve searches for a solution to the puzzle as it currently exists
	//without unfilling any cells. If one exists, it will fill in all cells to
	//fit that solution and return true. If there are no solutions the grid
	//will remain untouched and it will return false. If multiple solutions
	//exist, Solve will pick one at random.
	Solve() bool
	// contains filtered or unexported methods
}

MutableGrid is a sudoku Grid that can be mutated directly.

func GenerateGrid

func GenerateGrid(options *GenerationOptions) MutableGrid

GenerateGrid returns a new sudoku puzzle with a single unique solution and many of its cells unfilled--a puzzle that is appropriate (and hopefully fun) for humans to solve. Puzzles returned will have filled cells locked (see cell.Lock for more on locking). GenerateGrid first finds a random full filling of the grid, then iteratively removes cells until just before the grid begins having multiple solutions. The result is a grid that has a single valid solution but many of its cells unfilled. Pass nil for options to use reasonable defaults. GenerateGrid doesn't currently give any way to define the desired difficulty; the best option is to repeatedly generate puzzles until you find one that matches your desired difficulty. cmd/dokugen applies this technique.

func MutableLoad

func MutableLoad(data string) MutableGrid

MutableLoad is similar to Load, but returns a MutableGrid. If you want to operate on an existing grid instead of returning a new one, see MutableGrid.Load.

func MutableLoadSDK

func MutableLoadSDK(data string) MutableGrid

MutableLoadSDK is like LoadSDK, but returns a MutableGrid. If you want to operate on an existing grid, see MutableGrid.LoadSDK.

func MutableLoadSDKFromFile

func MutableLoadSDKFromFile(path string) (MutableGrid, error)

MutableLoadSDKFromFile is similar to LoadSDKFromFile, but returns a MutableGrid.

func NewGrid

func NewGrid() MutableGrid

NewGrid creates a new, blank grid with all of its cells unfilled.

type ProbabilityDistribution

type ProbabilityDistribution []float64

ProbabilityDistribution represents a distribution of probabilities over indexes.

func (ProbabilityDistribution) RandomIndex

func (d ProbabilityDistribution) RandomIndex() int

RandomIndex returns a random index based on the probability distribution.

type SolveDirections

type SolveDirections struct {

	//The list of CompoundSolveSteps that, when applied in order, would cause
	//the SolveDirection's Grid() to be solved.
	CompoundSteps []*CompoundSolveStep
	// contains filtered or unexported fields
}

SolveDirections is a list of CompoundSolveSteps that, when applied in order to its Grid, would cause it to be solved (or, for a hint, would cause it to have precisely one more fill step filled).

func (SolveDirections) Description

func (self SolveDirections) Description() []string

Description returns a comprehensive prose description of the SolveDirections, including reasoning for each step, that if followed would lead to the grid being solved. Unlike Walkthrough, Description() does not include diagrams for each step.

func (SolveDirections) Grid

func (self SolveDirections) Grid() Grid

Grid returns a snapshot of the grid at the time this SolveDirections was generated.

func (SolveDirections) Signals

func (self SolveDirections) Signals() DifficultySignals

Signals returns the DifficultySignals for this set of SolveDirections.

func (SolveDirections) Stats

func (self SolveDirections) Stats() []string

Stats returns a printout of interesting statistics about the SolveDirections, including number of steps, difficulty (based on this solve description alone), how unrelated the cells in subsequent steps are, and the values of all of the signals used to generate the difficulty.

func (SolveDirections) Steps

func (s SolveDirections) Steps() []*SolveStep

Steps returns the list of all CompoundSolveSteps flattened into one stream of SolveSteps.

func (SolveDirections) Walkthrough

func (self SolveDirections) Walkthrough() string

Walkthrough prints an exhaustive set of human-readable directions that includes diagrams at each step to make it easier to follow.

type SolveStep

type SolveStep struct {
	//The technique that was used to identify that this step is logically valid at this point in the solution.
	Technique SolveTechnique
	//The cells that will be affected by the techinque (either the number to fill in or possibilities to exclude).
	TargetCells CellRefSlice
	//The numbers we will remove (or, in the case of Fill, add) to the TargetCells.
	TargetNums IntSlice
	//The cells that together lead the techinque to logically apply in this case; the cells behind the reasoning
	//why the TargetCells will be mutated in the way specified by this SolveStep.
	PointerCells CellRefSlice
	//The specific numbers in PointerCells that lead us to remove TargetNums from TargetCells.
	//This is only very rarely needed (at this time only for hiddenSubset techniques)
	PointerNums IntSlice
	// contains filtered or unexported fields
}

SolveStep is a step to fill in a number in a cell or narrow down the possibilities in a cell to get it closer to being solved. SolveSteps model techniques that humans would use to solve a puzzle. Most HumanSolve related methods return CompoundSolveSteps, which are higher-level collections of the base SolveSteps.

func (*SolveStep) Apply

func (self *SolveStep) Apply(grid MutableGrid)

Apply does the solve operation to the Grid that is defined by the configuration of the SolveStep, mutating the grid and bringing it one step closer to being solved.

func (*SolveStep) Description

func (self *SolveStep) Description() string

Description returns a human-readable sentence describing what the SolveStep instructs the user to do, and what reasoning it used to decide that this step was logically valid to apply.

func (*SolveStep) HumanLikelihood

func (self *SolveStep) HumanLikelihood() float64

HumanLikelihood is how likely a user would be to pick this step when compared with other possible steps. Generally inversely related to difficulty (but not perfectly). This value will be used to pick which technique to apply when compared with other candidates. Based on the technique's HumanLikelihood, possibly attenuated by this particular step's variant or specifics.

func (*SolveStep) IsUseful

func (self *SolveStep) IsUseful(grid Grid) bool

IsUseful returns true if this SolveStep, when applied to the given grid, would do useful work--that is, it would either fill a previously unfilled number, or cull previously un-culled possibilities. This is useful to ensure HumanSolve doesn't get in a loop of applying the same useless steps.

func (*SolveStep) Modifications

func (self *SolveStep) Modifications() GridModification

Modifications returns the GridModifications repesenting how this SolveStep would mutate the grid.

func (*SolveStep) TechniqueVariant

func (self *SolveStep) TechniqueVariant() string

TechniqueVariant returns the name of the precise variant of the Technique that this step represents. This information is useful for figuring out which weight to apply when calculating overall difficulty. A Technique would have variants (as opposed to simply other Techniques) when the work to calculate all variants is the same, but the difficulty of produced steps may vary due to some property of the technique. Forcing Chains is the canonical example.

type SolveTechnique

type SolveTechnique interface {
	//Name returns the human-readable shortname of the technique.
	Name() string
	//Description returns a human-readable phrase that describes the logical reasoning applied in the particular step; why
	//it is valid.
	Description(*SolveStep) string

	//Candidates returns all of the SolveSteps that this Technique sees at the
	//current state of Grid. All of the returned steps are valid and useful to
	//apply. Will return early once maxResults have been found if maxResults >
	//0.
	Candidates(grid Grid, maxResults int) []*SolveStep

	//IsFill returns true if the techinque's action when applied to a grid is to fill a number (as opposed to culling possbilitie).
	IsFill() bool

	//Variants returns a slice of strings representing all of the various variantnames
	//that steps produced from this technique could ever have. This is useful as part of
	//enumerating all possible TechniqueVariant names that any steps could ever emit.
	Variants() []string
	// contains filtered or unexported methods
}

SolveTechnique is a logical technique that, when applied to a grid, returns potential SolveSteps that will move the grid closer to being solved, and are based on sound logical reasoning. A stable of SolveTechniques (stored in Techniques) are repeatedly applied to the Grid in HumanSolve.

type SymmetryType

type SymmetryType int
const (
	SYMMETRY_NONE SymmetryType = iota
	SYMMETRY_ANY
	SYMMETRY_HORIZONTAL
	SYMMETRY_VERTICAL
	SYMMETRY_BOTH
)

Directories

Path Synopsis
cmd
dokugen
dokugen is a simple command line utility that exposes many of the basic functions of the sudoku package.
dokugen is a simple command line utility that exposes many of the basic functions of the sudoku package.
dokugen-analysis
dokugen-analysis is a command that does complex analysis on solve data from users in the wild in order to understand how accurately the difficulties have been set in that data, and help train difficulties for the main sudoku package based on that real world solve data.
dokugen-analysis is a command that does complex analysis on solve data from users in the wild in order to understand how accurately the difficulties have been set in that data, and help train difficulties for the main sudoku package based on that real world solve data.
dokugen-analysis/internal/gendifficulties
gendifficulties is used to take weka output and create the hs_difficulty_weights file in the main package with go generate.
gendifficulties is used to take weka output and create the hs_difficulty_weights file in the main package with go generate.
dokugen-analysis/internal/wekaparser
wekaparser takes the output of Weka's training model and parses it into a map of weights and r2.
wekaparser takes the output of Weka's training model and parses it into a map of weights and r2.
i-sudoku
i-sudoku is an interactive command-line sudoku tool.
i-sudoku is an interactive command-line sudoku tool.
Package sdkconverter provides a set of converters to and from sudoku's default sdk format.
Package sdkconverter provides a set of converters to and from sudoku's default sdk format.
sudokuhistory manages modifications to a given grid, allowing easy undo/redo, and keeping track of all moves.
sudokuhistory manages modifications to a given grid, allowing easy undo/redo, and keeping track of all moves.

Jump to

Keyboard shortcuts

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