a lot of things

This commit is contained in:
cjdenio committed 2026-09-02 17:13:48 -06:00
1 parent 6d0249618f
commit 9d1ada43f2
1 file changed
+156 -13
+156 -13
View File
@@ -1,11 +1,13 @@
package main package main
import ( import (
"flag"
"fmt" "fmt"
"log" "log"
"os" "os"
"slices" "slices"
"strings" "strings"
"unicode"
"github.com/cjdenio/crossword/puz" "github.com/cjdenio/crossword/puz"
"golang.org/x/term" "golang.org/x/term"
@@ -23,6 +25,9 @@ func AnsiInverted(s string) string {
func AnsiWhiteBackgrounded(s string) string { func AnsiWhiteBackgrounded(s string) string {
return AnsiWhiteBackground + s + AnsiReset return AnsiWhiteBackground + s + AnsiReset
} }
func AnsiDimmed(s string) string {
return fmt.Sprintf("\x1b[2m%s\x1b[0m", s)
}
func RenderPuzzle(puzzle []rune, width, height int, selectedClueCells []int, selectedCell int) string { func RenderPuzzle(puzzle []rune, width, height int, selectedClueCells []int, selectedCell int) string {
b := strings.Builder{} b := strings.Builder{}
@@ -43,7 +48,7 @@ func RenderPuzzle(puzzle []rune, width, height int, selectedClueCells []int, sel
case '.': case '.':
cell = string(rune(0x2588)) cell = string(rune(0x2588))
case '-': case '-':
cell = "_" cell = AnsiDimmed("_")
default: default:
cell = string(char) cell = string(char)
} }
@@ -80,11 +85,91 @@ func RenderPuzzle(puzzle []rune, width, height int, selectedClueCells []int, sel
} }
type State struct { type State struct {
Puzzle *puz.Puzzle Puzzle *puz.Puzzle
PuzzleState []rune PuzzleState []rune
SelectedCell int SelectedCell int
SelectedClue *puz.Clue SelectedClue *puz.Clue
Goodbye bool Goodbye bool
LastKeySequence string
DebugMode bool
}
func (state *State) MoveCursor(direction int) {
switch direction {
case 0: // up
if state.SelectedCell < state.Puzzle.Width { // if already in the top row, do nothing
return
}
for i := state.SelectedCell - state.Puzzle.Width; i >= 0; i -= state.Puzzle.Width {
if state.PuzzleState[i] != '.' {
state.SelectedCell = i
return
}
}
case 1: // right
if (state.SelectedCell+1)%state.Puzzle.Width == 0 { // if already in the right column, do nothing
return
}
for i := state.SelectedCell + 1; i%state.Puzzle.Width != 0; i += 1 {
if state.PuzzleState[i] != '.' {
state.SelectedCell = i
return
}
}
case 2: // down
if (state.SelectedCell) >= (state.Puzzle.Width*state.Puzzle.Height)-state.Puzzle.Width { // if already in the bottom row, do nothing
return
}
for i := state.SelectedCell + state.Puzzle.Width; i < (state.Puzzle.Width * state.Puzzle.Height); i += state.Puzzle.Width {
if state.PuzzleState[i] != '.' {
state.SelectedCell = i
return
}
}
case 3: // left
if state.SelectedCell%state.Puzzle.Width == 0 { // if already in the left column, do nothing
return
}
for i := state.SelectedCell - 1; (i+1)%state.Puzzle.Width != 0; i -= 1 {
if state.PuzzleState[i] != '.' {
state.SelectedCell = i
return
}
}
}
}
func (state *State) NextWord() {
if state.SelectedClue == nil {
return
}
foundSelectedClue := false
for _, clue := range state.Puzzle.Clues {
if !foundSelectedClue && clue == state.SelectedClue {
foundSelectedClue = true
continue
}
if foundSelectedClue && clue.Direction == state.SelectedClue.Direction {
state.SelectedClue = clue
state.SelectedCell = clue.Cells[0]
return
}
}
for _, clue := range state.Puzzle.Clues {
if clue.Direction != state.SelectedClue.Direction {
state.SelectedClue = clue
state.SelectedCell = clue.Cells[0]
return
}
}
} }
func RenderUI(state *State) int { func RenderUI(state *State) int {
@@ -102,12 +187,21 @@ func RenderUI(state *State) int {
fmt.Print(RenderPuzzle(state.PuzzleState, state.Puzzle.Width, state.Puzzle.Height, selectedClueCells, state.SelectedCell) + "\r\n") fmt.Print(RenderPuzzle(state.PuzzleState, state.Puzzle.Width, state.Puzzle.Height, selectedClueCells, state.SelectedCell) + "\r\n")
uiHeight += state.Puzzle.Height + 3 uiHeight += state.Puzzle.Height + 3
if state.SelectedClue != nil { if state.SelectedClue != nil {
fmt.Printf("%d: %s\r\n\r\n", state.SelectedClue.Number, state.SelectedClue.Clue) if state.SelectedClue.Direction == puz.DirectionAcross {
fmt.Printf("%d-across: %s\r\n\r\n", state.SelectedClue.Number, state.SelectedClue.Clue)
} else {
fmt.Printf("%d-down: %s\r\n\r\n", state.SelectedClue.Number, state.SelectedClue.Clue)
}
uiHeight += 2 uiHeight += 2
} }
fmt.Printf("%s\r\n", state.Puzzle.Copyright) fmt.Printf("%s\r\n", state.Puzzle.Copyright)
uiHeight += 1 uiHeight += 1
if state.LastKeySequence != "" && state.DebugMode {
fmt.Printf("\r\n%s\r\n", AnsiDimmed(state.LastKeySequence))
uiHeight += 2
}
if state.Goodbye { if state.Goodbye {
fmt.Print("\r\nsee ya\r\n") fmt.Print("\r\nsee ya\r\n")
uiHeight += 2 uiHeight += 2
@@ -129,7 +223,10 @@ func main() {
defer term.Restore(int(os.Stdin.Fd()), termState) defer term.Restore(int(os.Stdin.Fd()), termState)
filename := os.Args[1] debugMode := flag.Bool("debug", false, "")
flag.Parse()
filename := flag.Arg(0)
file, err := os.ReadFile(filename) file, err := os.ReadFile(filename)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@@ -146,6 +243,9 @@ func main() {
SelectedClue: puzzle.Clues[0], SelectedClue: puzzle.Clues[0],
SelectedCell: puzzle.Clues[0].Cells[0], SelectedCell: puzzle.Clues[0].Cells[0],
} }
if debugMode != nil {
state.DebugMode = *debugMode
}
uiHeight := RenderUI(&state) uiHeight := RenderUI(&state)
@@ -156,6 +256,8 @@ func main() {
log.Fatal(err) log.Fatal(err)
} }
state.LastKeySequence = fmt.Sprintf("%v", buffer)
if buffer[0] == 3 { if buffer[0] == 3 {
state.SelectedClue = nil state.SelectedClue = nil
state.SelectedCell = -1 state.SelectedCell = -1
@@ -166,6 +268,48 @@ func main() {
return return
} }
if buffer[0] == ' ' {
switch state.SelectedClue.Direction {
case puz.DirectionAcross:
if state.Puzzle.Cells[state.SelectedCell][1] != nil {
state.SelectedClue = state.Puzzle.Cells[state.SelectedCell][1]
}
case puz.DirectionDown:
if state.Puzzle.Cells[state.SelectedCell][0] != nil {
state.SelectedClue = state.Puzzle.Cells[state.SelectedCell][0]
}
}
}
if buffer[0] >= 0x61 && buffer[0] <= 0x7a {
state.PuzzleState[state.SelectedCell] = unicode.ToUpper(rune(buffer[0]))
// jump to next unfilled cell in clue
i := slices.Index(state.SelectedClue.Cells, state.SelectedCell)
for x := i + 1; x < len(state.SelectedClue.Cells); x++ {
if state.PuzzleState[state.SelectedClue.Cells[x]] == '-' {
state.SelectedCell = state.SelectedClue.Cells[x]
break
}
}
}
if buffer[0] == 0x7f {
// is there a filled cell underneath the cursor?
if state.PuzzleState[state.SelectedCell] != '-' {
state.PuzzleState[state.SelectedCell] = '-'
} else {
i := slices.Index(state.SelectedClue.Cells, state.SelectedCell)
if i > 0 {
state.PuzzleState[state.SelectedClue.Cells[i-1]] = '-' // clear the previous cell
state.SelectedCell = state.SelectedClue.Cells[i-1]
}
}
}
if buffer[0] == 0x0d {
state.NextWord()
}
if (buffer[2] == 68 || buffer[2] == 67) && state.SelectedClue != nil && state.SelectedClue.Direction == puz.DirectionDown { if (buffer[2] == 68 || buffer[2] == 67) && state.SelectedClue != nil && state.SelectedClue.Direction == puz.DirectionDown {
state.SelectedClue = state.Puzzle.Cells[state.SelectedCell][0] state.SelectedClue = state.Puzzle.Cells[state.SelectedCell][0]
} else if (buffer[2] == 65 || buffer[2] == 66) && state.SelectedClue != nil && state.SelectedClue.Direction == puz.DirectionAcross { } else if (buffer[2] == 65 || buffer[2] == 66) && state.SelectedClue != nil && state.SelectedClue.Direction == puz.DirectionAcross {
@@ -173,14 +317,13 @@ func main() {
} else { } else {
switch buffer[2] { switch buffer[2] {
case 68: // left case 68: // left
state.SelectedCell-- state.MoveCursor(3)
case 67: // right case 67: // right
state.PuzzleState[state.SelectedCell] = 'a' state.MoveCursor(1)
state.SelectedCell++
case 65: // up case 65: // up
state.SelectedCell -= puzzle.Width state.MoveCursor(0)
case 66: // down case 66: // down
state.SelectedCell += puzzle.Width state.MoveCursor(2)
} }
switch state.SelectedClue.Direction { switch state.SelectedClue.Direction {