第六部分习题 - 图1

    第六部分习题 - 图2

    1. package main
    2. import (
    3. "errors"
    4. "fmt"
    5. "os"
    6. )
    7. const (
    8. rows, columns = 9, 9
    9. empty = 0
    10. )
    11. // Cell is a square on the Sudoku grid.
    12. type Cell struct {
    13. digit int8
    14. fixed bool
    15. }
    16. // Grid is a Sudoku grid.
    17. type Grid [rows][columns]Cell
    18. // Errors that could occur.
    19. var (
    20. ErrBounds = errors.New("out of bounds")
    21. ErrDigit = errors.New("invalid digit")
    22. ErrInRow = errors.New("digit already present in this row")
    23. ErrInColumn = errors.New("digit already present in this column")
    24. ErrInRegion = errors.New("digit already present in this region")
    25. ErrFixedDigit = errors.New("initial digits cannot be overwritten")
    26. )
    27. // NewSudoku makes a new Sudoku grid.
    28. func NewSudoku(digits [rows][columns]int8) *Grid {
    29. var grid Grid
    30. for r := 0; r < rows; r++ {
    31. for c := 0; c < columns; c++ {
    32. d := digits[r][c]
    33. if d != empty {
    34. grid[r][c].digit = d
    35. grid[r][c].fixed = true
    36. }
    37. }
    38. }
    39. return &grid
    40. }
    41. // Set a digit on a Sudoku grid.
    42. func (g *Grid) Set(row, column int, digit int8) error {
    43. switch {
    44. case !inBounds(row, column):
    45. return ErrBounds
    46. case !validDigit(digit):
    47. return ErrDigit
    48. case g.isFixed(row, column):
    49. return ErrFixedDigit
    50. case g.inRow(row, digit):
    51. return ErrInRow
    52. case g.inColumn(column, digit):
    53. return ErrInColumn
    54. case g.inRegion(row, column, digit):
    55. return ErrInRegion
    56. }
    57. g[row][column].digit = digit
    58. return nil
    59. }
    60. // Clear a cell from the Sudoku grid.
    61. func (g *Grid) Clear(row, column int) error {
    62. switch {
    63. case !inBounds(row, column):
    64. return ErrBounds
    65. case g.isFixed(row, column):
    66. return ErrFixedDigit
    67. }
    68. g[row][column].digit = empty
    69. return nil
    70. }
    71. func inBounds(row, column int) bool {
    72. if row < 0 || row >= rows || column < 0 || column >= columns {
    73. return false
    74. }
    75. return true
    76. }
    77. func validDigit(digit int8) bool {
    78. return digit >= 1 && digit <= 9
    79. }
    80. func (g *Grid) inRow(row int, digit int8) bool {
    81. for c := 0; c < columns; c++ {
    82. if g[row][c].digit == digit {
    83. return true
    84. }
    85. }
    86. return false
    87. }
    88. func (g *Grid) inColumn(column int, digit int8) bool {
    89. for r := 0; r < rows; r++ {
    90. if g[r][column].digit == digit {
    91. return true
    92. }
    93. }
    94. return false
    95. }
    96. func (g *Grid) inRegion(row, column int, digit int8) bool {
    97. startRow, startColumn := row/3*3, column/3*3
    98. for r := startRow; r < startRow+3; r++ {
    99. for c := startColumn; c < startColumn+3; c++ {
    100. if g[r][c].digit == digit {
    101. return true
    102. }
    103. }
    104. }
    105. return false
    106. }
    107. func (g *Grid) isFixed(row, column int) bool {
    108. return g[row][column].fixed
    109. }
    110. func main() {
    111. s := NewSudoku([rows][columns]int8{
    112. {5, 3, 0, 0, 7, 0, 0, 0, 0},
    113. {6, 0, 0, 1, 9, 5, 0, 0, 0},
    114. {0, 9, 8, 0, 0, 0, 0, 6, 0},
    115. {8, 0, 0, 0, 6, 0, 0, 0, 3},
    116. {4, 0, 0, 8, 0, 3, 0, 0, 1},
    117. {7, 0, 0, 0, 2, 0, 0, 0, 6},
    118. {0, 6, 0, 0, 0, 0, 2, 8, 0},
    119. {0, 0, 0, 4, 1, 9, 0, 0, 5},
    120. {0, 0, 0, 0, 8, 0, 0, 7, 9},
    121. })
    122. err := s.Set(1, 1, 4)
    123. if err != nil {
    124. fmt.Println(err)
    125. os.Exit(1)
    126. }
    127. for _, row := range s {
    128. fmt.Println(row)
    129. }
    130. }
    1. package main
    2. import "testing"
    3. var grid = [rows][columns]int8{
    4. {5, 3, 0, 0, 7, 0, 0, 0, 0},
    5. {6, 0, 0, 1, 9, 5, 0, 0, 0},
    6. {0, 9, 8, 0, 0, 0, 0, 6, 0},
    7. {8, 0, 0, 0, 6, 0, 0, 0, 3},
    8. {4, 0, 0, 8, 0, 3, 0, 0, 1},
    9. {7, 0, 0, 0, 2, 0, 0, 0, 6},
    10. {0, 6, 0, 0, 0, 0, 2, 8, 0},
    11. {0, 0, 0, 4, 1, 9, 0, 0, 5},
    12. {0, 0, 0, 0, 8, 0, 0, 7, 9},
    13. }
    14. func TestOk(t *testing.T) {
    15. s := NewSudoku(grid)
    16. tests := []struct {
    17. row, column int
    18. digit int8
    19. }{
    20. {1, 1, 4},
    21. {0, 3, 6},
    22. {1, 6, 4},
    23. }
    24. for _, tt := range tests {
    25. err := s.Set(tt.row, tt.column, tt.digit)
    26. if err != nil {
    27. t.Errorf("Expected no error, got %v for row: %d, column: %d, digit: %d.", err, tt.row, tt.column, tt.digit)
    28. }
    29. err = s.Clear(tt.row, tt.column)
    30. if err != nil {
    31. t.Fatalf("Unexpected error clearing row: %d, column: %d", tt.row, tt.column)
    32. }
    33. }
    34. }
    35. func TestClear(t *testing.T) {
    36. s := NewSudoku(grid)
    37. err := s.Clear(0, 0)
    38. if err != ErrFixedDigit {
    39. t.Errorf("Clear expected ErrFixedDigit, got %v", err)
    40. }
    41. err = s.Clear(1, 1)
    42. if err != nil {
    43. t.Errorf("Clear expected no error, got %v", err)
    44. }
    45. }
    46. func TestErrors(t *testing.T) {
    47. s := NewSudoku(grid)
    48. tests := []struct {
    49. row, column int
    50. digit int8
    51. err error
    52. }{
    53. {-1, 0, 8, ErrBounds},
    54. {0, -1, 8, ErrBounds},
    55. {9, 0, 8, ErrBounds},
    56. {0, 9, 8, ErrBounds},
    57. {0, 0, -1, ErrDigit},
    58. {0, 0, 10, ErrDigit},
    59. {0, 2, 5, ErrInRow},
    60. {2, 0, 5, ErrInColumn},
    61. {1, 1, 8, ErrInRegion},
    62. {2, 3, 7, ErrInRegion},
    63. {0, 0, 1, ErrFixedDigit},
    64. }
    65. for _, tt := range tests {
    66. err := s.Set(tt.row, tt.column, tt.digit)
    67. if err != tt.err {
    68. t.Errorf("Expected error %q, got %v for row: %d, column: %d, digit: %d.", tt.err, err, tt.row, tt.column, tt.digit)
    69. }
    70. }
    71. }