- commit
- 8f65ed82faf045dab226d344dfc2caa453e36138
- parent
- 7915414b15131915fe27634e11e95d6a17042fee
- author
- Dami <dami@Damis-MacBook-Air.local>
| M | sudoku/ | 13 | --- |
| A | sudoku/ | 115 | ++++++++++++++++++++++++++++++ |
| M | wordsearch/ | 14 | +++- |
@@ -9,19 +9,6 @@ type cell struct {
99 1010 type grid = [9][9]cell1111 12-func GenerateProvidedCells(m SudokuMode) []cell {13- // TODO: implement14- cells := []cell{15- {1, 2, 3},16- {3, 4, 5},17- }18- //create solved board19- // iteratively remove cells and ensure only 1 solution20- // backtrack if not unique21- // return known values22- return cells23-}24-2512 func newGrid(provided []cell) grid {2613 var g grid2714 for i := range GRIDSIZE {@@ -0,0 +1,115 @@
1+package sudoku2+3+import "math/rand/v2"4+5+// isValid checks whether placing val at (x, y) in the grid is valid.6+func isValid(g *grid, val, x, y int) bool {7+ for i := range GRIDSIZE {8+ if i != x && g[y][i].v == val {9+ return false10+ }11+ if i != y && g[i][x].v == val {12+ return false13+ }14+ }15+ boxX, boxY := (x/3)*3, (y/3)*316+ for by := boxY; by < boxY+3; by++ {17+ for bx := boxX; bx < boxX+3; bx++ {18+ if (bx != x || by != y) && g[by][bx].v == val {19+ return false20+ }21+ }22+ }23+ return true24+}25+26+// fillGrid fills an empty grid with a random valid sudoku solution using backtracking.27+func fillGrid(g *grid) bool {28+ for y := range GRIDSIZE {29+ for x := range GRIDSIZE {30+ if g[y][x].v == 0 {31+ order := rand.Perm(GRIDSIZE)32+ for _, i := range order {33+ val := i + 134+ if isValid(g, val, x, y) {35+ g[y][x].v = val36+ if fillGrid(g) {37+ return true38+ }39+ g[y][x].v = 040+ }41+ }42+ return false43+ }44+ }45+ }46+ return true47+}48+49+// countSolutions counts solutions of the grid up to limit using backtracking.50+func countSolutions(g *grid, limit int) int {51+ for y := range GRIDSIZE {52+ for x := range GRIDSIZE {53+ if g[y][x].v == 0 {54+ count := 055+ for val := 1; val <= GRIDSIZE; val++ {56+ if isValid(g, val, x, y) {57+ g[y][x].v = val58+ count += countSolutions(g, limit-count)59+ g[y][x].v = 060+ if count >= limit {61+ return count62+ }63+ }64+ }65+ return count66+ }67+ }68+ }69+ return 170+}71+72+// GenerateProvidedCells generates a random sudoku puzzle with the number of73+// provided cells determined by the mode's ProvidedCount.74+func GenerateProvidedCells(m SudokuMode) []cell {75+ g := newGrid(nil)76+ fillGrid(&g)77+78+ // Build shuffled list of all positions79+ type pos struct{ x, y int }80+ positions := make([]pos, 0, GRIDSIZE*GRIDSIZE)81+ for y := range GRIDSIZE {82+ for x := range GRIDSIZE {83+ positions = append(positions, pos{x, y})84+ }85+ }86+ rand.Shuffle(len(positions), func(i, j int) {87+ positions[i], positions[j] = positions[j], positions[i]88+ })89+90+ // Iteratively remove cells, ensuring unique solution91+ filled := GRIDSIZE * GRIDSIZE92+ for _, p := range positions {93+ if filled <= m.ProvidedCount {94+ break95+ }96+ saved := g[p.y][p.x].v97+ g[p.y][p.x].v = 098+ if countSolutions(&g, 2) != 1 {99+ g[p.y][p.x].v = saved100+ } else {101+ filled--102+ }103+ }104+105+ // Collect remaining filled cells as provided hints106+ var cells []cell107+ for y := range GRIDSIZE {108+ for x := range GRIDSIZE {109+ if g[y][x].v != 0 {110+ cells = append(cells, g[y][x])111+ }112+ }113+ }114+ return cells115+}@@ -42,6 +42,10 @@ var (
4242 Padding(1, 2).4343 Border(lipgloss.RoundedBorder()).4444 BorderForeground(lipgloss.Color("#00ff00"))45+46+ statusBarStyle = lipgloss.NewStyle().47+ Foreground(lipgloss.Color("#888888")).48+ MarginTop(1)4549 )4650 4751 func renderView(m Model) string {@@ -52,13 +56,19 @@ func renderView(m Model) string {
5256 spacer := strings.Repeat(" ", 4)5357 mainView := lipgloss.JoinHorizontal(lipgloss.Top, gridView, spacer, wordListView)5458 59+ status := statusBarView()60+5561 // Add win message if won5662 if m.won {5763 winMsg := winMessageStyle.Render("🎉 Congratulations! You found all the words! 🎉")58- return lipgloss.JoinVertical(lipgloss.Left, mainView, "\n", winMsg)64+ return lipgloss.JoinVertical(lipgloss.Left, mainView, "\n", winMsg, status)5965 }6066 61- return mainView67+ return lipgloss.JoinVertical(lipgloss.Left, mainView, status)68+}69+70+func statusBarView() string {71+ return statusBarStyle.Render("arrows/wasd: move enter/space: select esc: cancel ctrl+n: menu ctrl+e: debug")6272 }6373 6474 func renderGrid(m Model) string {