reveal/check/clear

This commit is contained in:
cjdenio committed 2026-09-29 22:26:49 -04:00
1 parent 50be9ab605
commit 60d1bd644c
2 files changed
+105 -14

No files matched your search

-2
View File
@@ -11,8 +11,6 @@ Very silly terminal-based crossword solver. It can play .puz / .ipuz files from
todo todo
- timer - timer
- reveal grid/word
- .puz checksums - .puz checksums
- fix shift+enter / shift+tab in other terminals - fix shift+enter / shift+tab in other terminals
- clear grid
- rebus - rebus
+105 -12
View File
@@ -20,6 +20,16 @@ const (
Solved Solved
) )
type UIState int
const (
StateGame UIState = iota
StateRebusConfirmation
StateMenu
StateRevealMenu
StateCheckMenu
)
type State struct { type State struct {
Puzzle *puz.Puzzle Puzzle *puz.Puzzle
PuzzleState []rune PuzzleState []rune
@@ -29,7 +39,7 @@ type State struct {
DebugMode bool DebugMode bool
SolveState SolveState SolveState SolveState
CheckState []rune CheckState []rune
RebusConfirmation bool UIState UIState
} }
func RenderWithLineWrap(s string, width int) (out string, lines int) { func RenderWithLineWrap(s string, width int) (out string, lines int) {
@@ -74,13 +84,17 @@ func RenderWithLineWrap(s string, width int) (out string, lines int) {
} }
func NewState(puzzle *puz.Puzzle) *State { func NewState(puzzle *puz.Puzzle) *State {
state := StateGame
if puzzle.HasRebus {
state = StateRebusConfirmation
}
return &State{ return &State{
Puzzle: puzzle, Puzzle: puzzle,
PuzzleState: []rune(puzzle.State), PuzzleState: []rune(puzzle.State),
SelectedClue: puzzle.Clues[0], SelectedClue: puzzle.Clues[0],
SelectedCell: puzzle.Clues[0].Cells[0], SelectedCell: puzzle.Clues[0].Cells[0],
CheckState: make([]rune, len(puzzle.State)), CheckState: make([]rune, len(puzzle.State)),
RebusConfirmation: puzzle.HasRebus, UIState: state,
} }
} }
@@ -284,8 +298,25 @@ func (state *State) CheckWord(clue *puz.Clue) {
} }
} }
func (state *State) RevealWord(clue *puz.Clue) {
for i, cellIdx := range clue.Cells {
state.PuzzleState[cellIdx] = rune(clue.Solution[i])
state.CheckState[cellIdx] = 'y'
}
}
func (state *State) RevealPuzzle() {
for i, cell := range state.PuzzleState {
if cell == '.' {
continue
}
state.PuzzleState[i] = rune(state.Puzzle.Solution[i])
state.CheckState[i] = 'y'
}
}
func (state *State) RenderUI(w io.Writer, width int) int { func (state *State) RenderUI(w io.Writer, width int) int {
if state.RebusConfirmation { if state.UIState == StateRebusConfirmation {
fmt.Fprint(w, "This puzzle contains a rebus. This tool does not support rebuses.\r\nPress 'y' to continue anyway, or press any other key to exit.\r\n") fmt.Fprint(w, "This puzzle contains a rebus. This tool does not support rebuses.\r\nPress 'y' to continue anyway, or press any other key to exit.\r\n")
return 2 return 2
} }
@@ -313,6 +344,21 @@ func (state *State) RenderUI(w io.Writer, width int) int {
fmt.Fprintf(w, "%s\r\n", state.Puzzle.Copyright) fmt.Fprintf(w, "%s\r\n", state.Puzzle.Copyright)
uiHeight += 1 uiHeight += 1
switch state.UIState {
case StateGame:
fmt.Fprintln(w, AnsiDimmed("\r\n[enter]/[tab]: next word | [ctrl+a]: menu | [ctrl+c]: exit"))
uiHeight += 2
case StateMenu:
fmt.Fprintln(w, AnsiDimmed("\r\n[c]: check puzzle/word | [r]: reveal puzzle/word | [x]: clear grid | [q]: exit menu"))
uiHeight += 2
case StateCheckMenu:
fmt.Fprintln(w, AnsiDimmed("\r\n[w]: check word | [p]: check puzzle | [q]: exit menu"))
uiHeight += 2
case StateRevealMenu:
fmt.Fprintln(w, AnsiDimmed("\r\n[w]: reveal word | [p]: reveal puzzle | [q]: exit menu"))
uiHeight += 2
}
switch state.SolveState { switch state.SolveState {
case FilledNotSolved: case FilledNotSolved:
fmt.Fprintf(w, "\r\n%s\r\n", AnsiRed("The puzzle was filled, but at least 1 letter is incorrect...")) fmt.Fprintf(w, "\r\n%s\r\n", AnsiRed("The puzzle was filled, but at least 1 letter is incorrect..."))
@@ -471,26 +517,73 @@ func (state *State) SwitchDirections() bool {
return false return false
} }
func (state *State) ClearGrid() {
for i, cell := range state.PuzzleState {
if cell != '.' {
state.PuzzleState[i] = '-'
state.CheckState[i] = '\x00'
}
}
}
func (state *State) HandleInput(buffer []byte) (exited bool) { func (state *State) HandleInput(buffer []byte) (exited bool) {
if len(buffer) == 0 { if len(buffer) == 0 {
return false return false
} }
if state.RebusConfirmation {
if buffer[0] == 'y' {
state.RebusConfirmation = false
return false
} else {
return true
}
}
state.LastKeySequence = fmt.Sprintf("%v", buffer) state.LastKeySequence = fmt.Sprintf("%v", buffer)
if buffer[0] == 3 { if buffer[0] == 3 {
return true return true
} }
switch state.UIState {
case StateRebusConfirmation:
if buffer[0] == 'y' {
state.UIState = StateGame
return false
} else {
return true
}
case StateMenu:
switch buffer[0] {
case 'c':
state.UIState = StateCheckMenu
case 'r':
state.UIState = StateRevealMenu
case 'x':
state.ClearGrid()
state.UIState = StateGame
default:
state.UIState = StateGame
}
return false
case StateCheckMenu:
switch buffer[0] {
case 'w':
state.CheckWord(state.SelectedClue)
case 'p':
state.CheckPuzzle()
}
state.UIState = StateGame
return false
case StateRevealMenu:
switch buffer[0] {
case 'w':
state.RevealWord(state.SelectedClue)
case 'p':
state.RevealPuzzle()
return true
}
state.UIState = StateGame
return false
}
if buffer[0] == '\x01' {
state.UIState = StateMenu
return false
}
if buffer[0] == ' ' { if buffer[0] == ' ' {
state.SwitchDirections() state.SwitchDirections()
} }