• C# 实现数独游戏


    1.数独单元

    1. public struct SudokuCell
    2. {
    3. public SudokuCell() : this(0, 0, 0)
    4. {
    5. }
    6. public SudokuCell(int x, int y, int number)
    7. {
    8. X = x; Y = y; Number = number;
    9. }
    10. public int X { get; set; }
    11. public int Y { get; set; }
    12. public int Number { get; set; }
    13. }

    2.数独创建

    1. public class SudokuGenerator
    2. {
    3. private const int BoardSize = 9;
    4. private const int EmptyCellValue = 0;
    5. private Random random;
    6. private readonly ChaosRandomEx chaosRandomEx;
    7. public SudokuGenerator()
    8. {
    9. random = new Random();
    10. chaosRandomEx = new ChaosRandomEx();
    11. }
    12. public SudokuCell[,] GenerateSudoku(DifficultyLevel difficulty)
    13. {
    14. SudokuCell[,] board = new SudokuCell[BoardSize, BoardSize];
    15. // 初始化数独网格
    16. for (int row = 0; row < BoardSize; row++)
    17. {
    18. for (int col = 0; col < BoardSize; col++)
    19. {
    20. board[row, col] = new SudokuCell(row, col, EmptyCellValue);
    21. }
    22. }
    23. // 填充数独网格
    24. FillSudoku(board);
    25. // 根据难度要求移除部分单元格的值
    26. RemoveCells(board, difficulty);
    27. return board;
    28. }
    29. private void FillSudoku(SudokuCell[,] board)
    30. {
    31. SolveSudoku(board);
    32. }
    33. private bool SolveSudoku(SudokuCell[,] board)
    34. {
    35. int row = 0;
    36. int col = 0;
    37. if (!FindEmptyCell(board, ref row, ref col))
    38. {
    39. // 所有单元格都已填满,数独已解决
    40. return true;
    41. }
    42. List<int> numbers = GetRandomNumberSequence();
    43. foreach (int num in numbers)
    44. {
    45. if (IsValidMove(board, row, col, num))
    46. {
    47. // 尝试填充数字
    48. board[row, col].Number = num;
    49. if (SolveSudoku(board))
    50. {
    51. // 递归解决剩余的单元格
    52. return true;
    53. }
    54. // 回溯到上一个单元格
    55. board[row, col].Number = EmptyCellValue;
    56. }
    57. }
    58. return false;
    59. }
    60. private bool FindEmptyCell(SudokuCell[,] board, ref int row, ref int col)
    61. {
    62. for (row = 0; row < BoardSize; row++)
    63. {
    64. for (col = 0; col < BoardSize; col++)
    65. {
    66. if (board[row, col].Number == EmptyCellValue)
    67. {
    68. return true;
    69. }
    70. }
    71. }
    72. return false;
    73. }
    74. public bool IsValidMove(SudokuCell[,] board, int row, int col, int num)
    75. {
    76. // 检查行是否合法
    77. for (int i = 0; i < BoardSize; i++)
    78. {
    79. if (board[i, col].Number == num)
    80. {
    81. return false;
    82. }
    83. }
    84. // 检查列是否合法
    85. for (int i = 0; i < BoardSize; i++)
    86. {
    87. if (board[row, i].Number == num)
    88. {
    89. return false;
    90. }
    91. }
    92. // 检查子网格是否合法
    93. int subgridRow = (row / 3) * 3;
    94. int subgridCol = (col / 3) * 3;
    95. for (int i = 0; i < 3; i++)
    96. {
    97. for (int j = 0; j < 3; j++)
    98. {
    99. if (board[subgridRow + i, subgridCol + j].Number == num)
    100. {
    101. return false;
    102. }
    103. }
    104. }
    105. return true;
    106. }
    107. private List<int> GetRandomNumberSequence()
    108. {
    109. List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    110. Shuffle(numbers);
    111. return numbers;
    112. }
    113. private void Shuffle<T>(List list)
    114. {
    115. int n = list.Count;
    116. while (n > 1)
    117. {
    118. n--;
    119. int k = random.Next(n + 1);
    120. T value = list[k];
    121. list[k] = list[n];
    122. list[n] = value;
    123. }
    124. }
    125. private void RemoveCells(SudokuCell[,] board, DifficultyLevel difficulty)
    126. {
    127. int cellsToRemove = GetCellsToRemoveCount(difficulty);
    128. for (int i = 0; i < cellsToRemove; i++)
    129. {
    130. int row = random.Next(BoardSize);
    131. int col = random.Next(BoardSize);
    132. if (board[row, col].Number != EmptyCellValue)
    133. {
    134. board[row, col].Number = EmptyCellValue;
    135. }
    136. else
    137. {
    138. i--;
    139. }
    140. }
    141. }
    142. private int GetCellsToRemoveCount(DifficultyLevel difficulty)
    143. {
    144. return difficulty switch
    145. {
    146. DifficultyLevel.Medium => 32,
    147. DifficultyLevel.Hard => 44,
    148. DifficultyLevel.VeryHard => 56,
    149. DifficultyLevel.SuperHard => 68,
    150. DifficultyLevel.Insane => 80,
    151. _ => 20
    152. };
    153. }
    154. }

    3.数独难度等级

    1. public enum DifficultyLevel
    2. {
    3. ///
    4. /// 简单
    5. ///
    6. [Remark("简单")]
    7. Easy,
    8. ///
    9. /// 中等
    10. ///
    11. [Remark("中等")]
    12. Medium,
    13. ///
    14. /// 困难
    15. ///
    16. [Remark("困难")]
    17. Hard,
    18. ///
    19. /// 极难
    20. ///
    21. [Remark("极难")]
    22. VeryHard,
    23. ///
    24. /// 超难
    25. ///
    26. [Remark("超难")]
    27. SuperHard,
    28. ///
    29. /// 疯狂
    30. ///
    31. [Remark("疯狂")]
    32. Insane
    33. }

    4.递归回溯算法寻找答案

    1. ///
    2. /// 递归回溯算法
    3. ///
    4. public class SudokuSolver
    5. {
    6. public SudokuCell[,] SolveSudoku(SudokuCell[,] board)
    7. {
    8. var solution = new SudokuCell[board.GetLength(0), board.GetLength(1)];
    9. Array.Copy(board, solution, board.Length);
    10. if (BacktrackSolve(solution))
    11. {
    12. return solution;
    13. }
    14. else
    15. {
    16. // 没有找到解
    17. return null;
    18. }
    19. }
    20. private bool BacktrackSolve(SudokuCell[,] board)
    21. {
    22. for (int row = 0; row < 9; row++)
    23. {
    24. for (int col = 0; col < 9; col++)
    25. {
    26. if (board[row, col].Number == 0)
    27. {
    28. for (int num = 1; num <= 9; num++)
    29. {
    30. if (IsValid(board, row, col, num))
    31. {
    32. board[row, col].Number = num;
    33. if (BacktrackSolve(board))
    34. {
    35. return true;
    36. }
    37. board[row, col].Number = 0; // 回溯
    38. }
    39. }
    40. return false; // 所有数字都尝试过,没有找到合适的解
    41. }
    42. }
    43. }
    44. return true; // 数独已经填满,找到解
    45. }
    46. private bool IsValid(SudokuCell[,] board, int row, int col, int num)
    47. {
    48. // 检查同行是否有重复数字
    49. for (int i = 0; i < 9; i++)
    50. {
    51. if (board[row, i].Number == num)
    52. {
    53. return false;
    54. }
    55. }
    56. // 检查同列是否有重复数字
    57. for (int i = 0; i < 9; i++)
    58. {
    59. if (board[i, col].Number == num)
    60. {
    61. return false;
    62. }
    63. }
    64. // 检查同九宫格是否有重复数字
    65. int startRow = row - row % 3;
    66. int startCol = col - col % 3;
    67. for (int i = 0; i < 3; i++)
    68. {
    69. for (int j = 0; j < 3; j++)
    70. {
    71. if (board[startRow + i, startCol + j].Number == num)
    72. {
    73. return false;
    74. }
    75. }
    76. }
    77. return true; // 没有重复数字
    78. }
    79. }

    5.数独创建中心

    1. public class SudokuCenter : IDisposable
    2. {
    3. public bool IsStart { get; set; } = false;
    4. private int _width;
    5. private int _height;
    6. public const int CELLSNUMBER = 9;
    7. public const int CELLSNUMBER2 = 20;
    8. private int _cellSize;
    9. private int _rowSize;
    10. public int CellSize=> _cellSize;
    11. public int RowSize => _rowSize;
    12. public int Height => _height;
    13. public int Width => _width;
    14. public int Padding => CELLSNUMBER2;
    15. private Bitmap _bitmap;
    16. public Bitmap GetBitmap
    17. {
    18. get=>(Bitmap)_bitmap?.Clone();
    19. private set => _bitmap = value;
    20. }
    21. public SudokuCell[,] Suduku { get;private set; }
    22. public SudokuCell[,] PlayerSuduku { get; private set; }
    23. ///
    24. /// 生成棋盘图
    25. ///
    26. ///
    27. ///
    28. public void InitCheckerBoard(int w, int h)
    29. {
    30. w -= (CELLSNUMBER2 * 2 + 1);
    31. h -= (CELLSNUMBER2 * 2 + 1);
    32. _width = w;
    33. _height = h;
    34. _cellSize = _width / CELLSNUMBER;
    35. _rowSize = _height / CELLSNUMBER;
    36. Bitmap bitmap = new Bitmap(_width + CELLSNUMBER2, _height + CELLSNUMBER2);
    37. using (var g = Graphics.FromImage(bitmap))
    38. {
    39. g.SmoothingMode = SmoothingMode.AntiAlias;
    40. //g.Clear(Color.Gray);
    41. DrawCheckerBoard(g);
    42. }
    43. _bitmap?.Dispose();
    44. GetBitmap = bitmap;
    45. }
    46. public SudokuCell[,] GenerateSudoku(DifficultyLevel difficulty)
    47. {
    48. SudokuGenerator sudokuGenerator = new SudokuGenerator();
    49. Suduku = sudokuGenerator.GenerateSudoku(difficulty);
    50. PlayerSuduku = new SudokuCell[Suduku.GetLength(0), Suduku.GetLength(1)];
    51. Array.Copy(Suduku, PlayerSuduku, Suduku.Length);
    52. return Suduku;
    53. }
    54. public Color SudukuColor { get; set; }= Color.Black;
    55. public Color SolutionColor { get; set; } = Color.Red;
    56. public Color TransparentColor { get; } = Color.Transparent;
    57. public Font Font { get; set; }= new Font("Arial", 20, FontStyle.Bold);
    58. public Bitmap DrawSolution(SudokuCell[,] board)
    59. {
    60. using SolidBrush brush = new SolidBrush(SolutionColor);
    61. using SolidBrush brush2 = new SolidBrush(SudukuColor);
    62. var bm = GetBitmap;
    63. using var g = Graphics.FromImage(bm);
    64. for (int row = 0; row < CELLSNUMBER; row++)
    65. {
    66. for (int col = 0; col < CELLSNUMBER; col++)
    67. {
    68. int number = Suduku[row, col].Number;
    69. if (number != 0)
    70. {
    71. DrawString(g, row, col, number.ToString(), brush2);
    72. }
    73. else
    74. {
    75. number = board[row, col].Number;
    76. DrawString(g, row, col, number.ToString(), brush);
    77. }
    78. }
    79. }
    80. return bm;
    81. }
    82. public void DrawSudoku(Graphics g, SudokuCell[,] board)
    83. {
    84. using SolidBrush brush = new SolidBrush(SudukuColor);
    85. for (int row = 0; row < CELLSNUMBER; row++)
    86. {
    87. for (int col = 0; col < CELLSNUMBER; col++)
    88. {
    89. int num= board[row, col].Number;
    90. if((num != 0))
    91. {
    92. DrawString(g,row,col,num.ToString(), brush);
    93. }
    94. }
    95. }
    96. }
    97. public void DrawString(Graphics g,int row,int col,string number, SolidBrush brush)
    98. {
    99. int x = CELLSNUMBER2 + col * _cellSize + _cellSize / 2 - 8;
    100. int y = CELLSNUMBER2 + row * _rowSize + _rowSize / 2 - 10;
    101. g.DrawString(number, Font, brush, new Point(x, y));
    102. }
    103. public Rectangle DrawTransparent(Graphics g, int row, int col)
    104. {
    105. int off = 5;
    106. int off2 = 7;
    107. int x = CELLSNUMBER2 + col * _cellSize + off;
    108. int y = CELLSNUMBER2 + row * _rowSize+ off;
    109. using (SolidBrush brush = new SolidBrush(Color.White)) // 使用透明色进行擦除
    110. {
    111. var rec = new Rectangle(x, y, CellSize - off2, RowSize - off2);
    112. g.FillRectangle(brush, rec);
    113. return rec;
    114. }
    115. }
    116. public bool IsSolutionCorrect(SudokuCell[,] board, SudokuCell[,] solution)
    117. {
    118. for (int row = 0; row < CELLSNUMBER; row++)
    119. {
    120. for (int col = 0; col < CELLSNUMBER; col++)
    121. {
    122. if (board[row, col].Number != solution[row, col].Number)
    123. {
    124. return false;
    125. }
    126. }
    127. }
    128. return true;
    129. }
    130. public bool IsValidMove(SudokuCell[,] board, int row, int col, int num)
    131. {
    132. // 检查行是否合法
    133. for (int i = 0; i < CELLSNUMBER; i++)
    134. {
    135. if (board[i, col].Number == num)
    136. {
    137. return false;
    138. }
    139. }
    140. // 检查列是否合法
    141. for (int i = 0; i < CELLSNUMBER; i++)
    142. {
    143. if (board[row, i].Number == num)
    144. {
    145. return false;
    146. }
    147. }
    148. // 检查子网格是否合法
    149. int subgridRow = (row / 3) * 3;
    150. int subgridCol = (col / 3) * 3;
    151. for (int i = 0; i < 3; i++)
    152. {
    153. for (int j = 0; j < 3; j++)
    154. {
    155. if (board[subgridRow + i, subgridCol + j].Number == num)
    156. {
    157. return false;
    158. }
    159. }
    160. }
    161. return true;
    162. }
    163. private void DrawCheckerBoard(Graphics g)
    164. {
    165. using Pen pen = new Pen(Color.Black, 1);
    166. using Pen pen2 = new Pen(Color.Black, 2);
    167. using Font font = new Font("Arial", 10, FontStyle.Regular);
    168. using SolidBrush brush = new SolidBrush(Color.Black);
    169. for (int i = 0; i < CELLSNUMBER + 1; i++)
    170. {
    171. if (i == 0 || i % 3 == 0)
    172. {
    173. g.DrawLine(pen2, new Point(CELLSNUMBER2, CELLSNUMBER2 + i * _rowSize), new Point(CELLSNUMBER2 + _cellSize * CELLSNUMBER, CELLSNUMBER2 + i * _rowSize));
    174. g.DrawLine(pen2, new Point(CELLSNUMBER2 + i * _cellSize, CELLSNUMBER2 + 0), new Point(CELLSNUMBER2 + i * _cellSize, CELLSNUMBER2 + _rowSize * CELLSNUMBER));
    175. }
    176. else
    177. {
    178. g.DrawLine(pen, new Point(CELLSNUMBER2, CELLSNUMBER2 + i * _rowSize), new Point(CELLSNUMBER2 + _cellSize * CELLSNUMBER, CELLSNUMBER2 + i * _rowSize));
    179. g.DrawLine(pen, new Point(CELLSNUMBER2 + i * _cellSize, CELLSNUMBER2 + 0), new Point(CELLSNUMBER2 + i * _cellSize, CELLSNUMBER2 + _rowSize * CELLSNUMBER));
    180. }
    181. int x = CELLSNUMBER2 + i * _cellSize + _cellSize / 2 - 5;
    182. int y = 0;
    183. g.DrawString((i + 1).ToString(), font, brush, new Point(x, y));
    184. x = 0;
    185. y = CELLSNUMBER2 + i * _rowSize + _rowSize / 2 - 5;
    186. g.DrawString((i + 1).ToString(), font, brush, new Point(x, y));
    187. }
    188. }
    189. public void Dispose()
    190. {
    191. _bitmap?.Dispose();
    192. }
    193. }

     6.数字键盘

     

    1. public partial class FrmNumber : Form
    2. {
    3. public FrmNumber()
    4. {
    5. InitializeComponent();
    6. foreach (Control item in this.Controls)
    7. {
    8. item.Click += Item_Click;
    9. }
    10. }
    11. public Action NumberCallback;
    12. public Point ClickPoint { get; set; }
    13. public Point RowCell { get; set; }
    14. public Graphics Graphics { get; set; }
    15. private void Item_Click(object? sender, EventArgs e)
    16. {
    17. Button btn = sender as Button;
    18. NumberArg numberArg = new NumberArg();
    19. if (btn.Name == "btnClear")
    20. {
    21. numberArg.Type = NumberType.Clear;
    22. }
    23. else if (btn.Name == "btnClose")
    24. {
    25. numberArg.Type = NumberType.Close;
    26. }
    27. else
    28. {
    29. numberArg.Type = NumberType.Number;
    30. numberArg.Value = btn.Text;
    31. }
    32. numberArg.CllickPoint = ClickPoint;
    33. numberArg.RowCell = RowCell;
    34. numberArg.Graphics = Graphics;
    35. NumberCallback?.Invoke(numberArg);
    36. this.Close();
    37. }
    38. private void FrmNumber_FormClosing(object sender, FormClosingEventArgs e)
    39. {
    40. this.Dispose();
    41. }
    42. }
    43. public struct NumberArg
    44. {
    45. public NumberType Type { get; set; }
    46. public string Value { get; set; }
    47. public Point CllickPoint { get; set; }
    48. public Graphics Graphics { get; set; }
    49. public Point RowCell { get; set; }
    50. }
    51. public enum NumberType
    52. {
    53. Clear,
    54. Close,
    55. Number
    56. }

    7.主窗体 

     

    1. public partial class FrmMain : Form
    2. {
    3. private SudokuCenter _sudokuCenter;
    4. private System.Windows.Forms.Timer _timer;
    5. public FrmMain()
    6. {
    7. InitializeComponent();
    8. this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.OptimizedDoubleBuffer |
    9. ControlStyles.UserPaint |
    10. ControlStyles.AllPaintingInWmPaint,
    11. true);
    12. this.UpdateStyles();
    13. this.DoubleBuffered = true;
    14. _sudokuCenter = new SudokuCenter();
    15. _sudokuCenter.InitCheckerBoard(this.pbGameBack.Width, this.pbGameBack.Height);
    16. BindType(typeof(DifficultyLevel), this.cbDifficultyLevel, "Easy");
    17. }
    18. private void BindType(Type type, ComboBox comboBox, string defaultValue)
    19. {
    20. var enumValues = Enum.GetValues(type);
    21. var list = new List();
    22. int index = 0, curIndex = 0;
    23. foreach (Enum value in enumValues)
    24. {
    25. int hc = value.GetHashCode();
    26. list.Add(new IdValues
    27. {
    28. Id = hc.ToString(),
    29. Value = value.ToString(),
    30. Display= value.GetEnumDesc(),
    31. Standby = hc
    32. });
    33. if (value.ToString() == defaultValue)
    34. index = curIndex;
    35. curIndex++;
    36. }
    37. comboBox.ValueMember = "Id";
    38. comboBox.DisplayMember = "Display";
    39. comboBox.DataSource = list;
    40. comboBox.SelectedIndex = index;
    41. }
    42. private void pbGameBack_Paint(object sender, PaintEventArgs e)
    43. {
    44. if (sudukuBitmap != null)
    45. {
    46. e.Graphics.DrawImage(sudukuBitmap, 0, 0, pbGameBack.Width, pbGameBack.Height);
    47. }
    48. }
    49. public string Compute(long time)
    50. {
    51. if (time < 60)
    52. return $"00:{ChangeString(time)}";
    53. long minute = time / 60;
    54. if (minute < 60)
    55. return $"{ChangeString(minute)}:{ChangeString(time % 60)}";
    56. long hour = minute / 60;
    57. return $"{ChangeString(hour)}:{Compute(time - hour * 3600)}";
    58. }
    59. private string ChangeString(long val)
    60. {
    61. return val.ToString("D2");
    62. }
    63. ///
    64. /// 开始
    65. ///
    66. ///
    67. ///
    68. private void btnStart_Click(object sender, EventArgs e)
    69. {
    70. StartGame();
    71. }
    72. Bitmap sudukuBitmap;
    73. private void StartGame()
    74. {
    75. if (_sudokuCenter.IsStart)
    76. {
    77. if (MessageBox.Show("你正在开始游戏,确认重新开始吗?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel)
    78. {
    79. return;
    80. }
    81. }
    82. if (_timer != null)
    83. {
    84. _timer.Stop();
    85. _timer.Dispose();
    86. }
    87. time = 0;
    88. _timer = new System.Windows.Forms.Timer();
    89. _timer.Interval = 1000;
    90. _timer.Tick += timer_Tick;
    91. _timer.Start();
    92. DifficultyLevel level = (DifficultyLevel)(this.cbDifficultyLevel.Items[cbDifficultyLevel.SelectedIndex] as IdValues).Standby;
    93. var sudoku = _sudokuCenter.GenerateSudoku(level);
    94. this.pbGameBack.Image?.Dispose();
    95. sudukuBitmap?.Dispose();
    96. sudukuBitmap = null;
    97. sudukuBitmap = _sudokuCenter.GetBitmap;
    98. using var g = Graphics.FromImage(sudukuBitmap);
    99. _sudokuCenter.DrawSudoku(g, sudoku);
    100. _sudokuCenter.IsStart = true;
    101. pbGameBack.Invalidate();
    102. }
    103. long time = 0;
    104. private void timer_Tick(object? sender, EventArgs e)
    105. {
    106. lblTime.ExecBeginInvoke(() =>
    107. {
    108. lblTime.Text = Compute(++time);
    109. });
    110. }
    111. ///
    112. /// 答案
    113. ///
    114. ///
    115. ///
    116. private void btnSolution_Click(object sender, EventArgs e)
    117. {
    118. if (!_sudokuCenter.IsStart)
    119. {
    120. return;
    121. }
    122. if (MessageBox.Show("你正在开始游戏,确认显示答案吗?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel)
    123. {
    124. return;
    125. }
    126. SudokuSolver sudokuSolver = new SudokuSolver();
    127. var solveSudoku = sudokuSolver.SolveSudoku(_sudokuCenter.Suduku);
    128. var bm = _sudokuCenter.DrawSolution(solveSudoku);
    129. pbGameBack.Image?.Dispose();
    130. sudukuBitmap?.Dispose();
    131. sudukuBitmap = null;
    132. sudukuBitmap = bm;
    133. //pbGameBack.Image = bm;
    134. _sudokuCenter.IsStart = false;
    135. pbGameBack.Invalidate();
    136. }
    137. private void pbGameBack_MouseDown(object sender, MouseEventArgs e)
    138. {
    139. if (_sudokuCenter.Suduku == null || !_sudokuCenter.IsStart)
    140. return;
    141. int row = (e.Y - _sudokuCenter.Padding * 2) / _sudokuCenter.RowSize;
    142. int col = (e.X - _sudokuCenter.Padding * 2) / _sudokuCenter.CellSize;
    143. // 检测鼠标是否在小方格内
    144. if (row >= 0 && row < 9 && col >= 0 && col < 9)
    145. {
    146. var number = _sudokuCenter.Suduku[row, col].Number;
    147. if (number != 0)
    148. return;
    149. using (FrmNumber fn = new FrmNumber())
    150. {
    151. fn.NumberCallback = NumberCallback;
    152. Point p = pbGameBack.PointToScreen(Point.Empty);
    153. fn.StartPosition = FormStartPosition.Manual;
    154. fn.Location = new Point(p.X + e.X + (_sudokuCenter.CellSize >> 1), p.Y + e.Y + (_sudokuCenter.RowSize >> 1));
    155. fn.ClickPoint = new Point(e.X, e.Y);
    156. fn.RowCell = new Point(row, col);
    157. fn.ShowDialog();
    158. }
    159. }
    160. }
    161. private void NumberCallback(NumberArg arg)
    162. {
    163. switch (arg.Type)
    164. {
    165. case NumberType.Number:
    166. DrawString(arg.RowCell.X, arg.RowCell.Y, arg.Value);
    167. int num = Convert.ToInt32(arg.Value);
    168. if (cbPrompt.Checked)
    169. {
    170. bool status = _sudokuCenter.IsValidMove(_sudokuCenter.PlayerSuduku, arg.RowCell.X, arg.RowCell.Y, num);
    171. lblPrompt.Text = status ? "你真棒!" : "重复了";
    172. }
    173. else
    174. {
    175. lblPrompt.Text = "已写入";
    176. }
    177. _sudokuCenter.PlayerSuduku[arg.RowCell.X, arg.RowCell.Y].Number = num;
    178. pbGameBack.Invalidate(new Rectangle(SudokuCenter.CELLSNUMBER2 + arg.RowCell.Y * _sudokuCenter.CellSize, SudokuCenter.CELLSNUMBER2 + arg.RowCell.X * _sudokuCenter.RowSize, SudokuCenter.CELLSNUMBER2 + _sudokuCenter.CellSize, SudokuCenter.CELLSNUMBER2 + _sudokuCenter.RowSize));
    179. break;
    180. case NumberType.Clear:
    181. using (var g = Graphics.FromImage(sudukuBitmap))
    182. {
    183. _sudokuCenter.PlayerSuduku[arg.RowCell.X, arg.RowCell.Y].Number = 0;
    184. var rec= _sudokuCenter.DrawTransparent(g, arg.RowCell.X, arg.RowCell.Y);
    185. lblPrompt.Text = "已清除";
    186. pbGameBack.Invalidate(rec);
    187. }
    188. break;
    189. }
    190. }
    191. private void DrawString(int row, int col, string num)
    192. {
    193. using (var g = Graphics.FromImage(sudukuBitmap))
    194. {
    195. using SolidBrush brush = new SolidBrush(_sudokuCenter.SolutionColor);
    196. _sudokuCenter.DrawTransparent(g, row, col);
    197. _sudokuCenter.DrawString(g, row, col, num, brush);
    198. }
    199. }
    200. private void DrawString(Graphics g, int row, int col, string num)
    201. {
    202. using SolidBrush brush = new SolidBrush(_sudokuCenter.SolutionColor);
    203. _sudokuCenter.DrawTransparent(g, row, col);
    204. _sudokuCenter.DrawString(g, row, col, num, brush);
    205. pbGameBack.Invalidate(new Rectangle(SudokuCenter.CELLSNUMBER2 + col * _sudokuCenter.CellSize, SudokuCenter.CELLSNUMBER2 + row * _sudokuCenter.RowSize, _sudokuCenter.CellSize, _sudokuCenter.RowSize));
    206. }
    207. ///
    208. /// 提交
    209. ///
    210. ///
    211. ///
    212. private void btnSubmit_Click(object sender, EventArgs e)
    213. {
    214. if (!_sudokuCenter.IsStart)
    215. {
    216. return;
    217. }
    218. if (MessageBox.Show("你正在开始游戏,确认提交答案吗?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel)
    219. {
    220. return;
    221. }
    222. _timer.Stop();
    223. SudokuSolver sudokuSolver = new SudokuSolver();
    224. var solveSudoku = sudokuSolver.SolveSudoku(_sudokuCenter.Suduku);
    225. bool status = _sudokuCenter.IsSolutionCorrect(_sudokuCenter.PlayerSuduku, solveSudoku);
    226. if (status)
    227. {
    228. lblPrompt.Text = "全对了,你真棒!";
    229. MessageBox.Show("全对了,你真棒!", "恭喜");
    230. }
    231. else
    232. {
    233. lblPrompt.Text = "很遗憾,有错误!";
    234. MessageBox.Show("很遗憾,有错误!", "失败");
    235. for (int row = 0; row < SudokuCenter.CELLSNUMBER; row++)
    236. {
    237. for (int col = 0; col < SudokuCenter.CELLSNUMBER; col++)
    238. {
    239. if (solveSudoku[row, col].Number != _sudokuCenter.PlayerSuduku[row, col].Number)
    240. {
    241. this.DrawString(row, col, solveSudoku[row, col].Number.ToString());
    242. }
    243. }
    244. }
    245. pbGameBack.Invalidate();
    246. }
    247. _sudokuCenter.IsStart = false;
    248. }
    249. ///
    250. /// 重新开始
    251. ///
    252. ///
    253. ///
    254. private void btnRestart_Click(object sender, EventArgs e)
    255. {
    256. StartGame();
    257. }
    258. private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
    259. {
    260. _sudokuCenter.Dispose();
    261. this.pbGameBack.Image?.Dispose();
    262. this.pbGameBack.Dispose();
    263. if (_timer != null)
    264. {
    265. _timer.Stop();
    266. _timer.Dispose();
    267. }
    268. this.Dispose();
    269. }
    270. }

    8.其它

    1. public class RemarkAttribute : Attribute
    2. {
    3. ///
    4. /// 备注
    5. ///
    6. public string Remark { get; set; }
    7. public RemarkAttribute(string remark)
    8. {
    9. this.Remark = remark;
    10. }
    11. }
    12. public static class EnumEx
    13. {
    14. ///
    15. /// 根据枚举元素,获取该枚举元素的描述信息
    16. ///
    17. ///
    18. ///
    19. ///
    20. public static string GetEnumDesc<T>(this T tField) where T : Enum
    21. {
    22. var description = string.Empty; //结果
    23. var inputType = tField.GetType(); //输入的类型
    24. var descType = typeof(RemarkAttribute); //目标查找的描述类型
    25. var fieldStr = tField.ToString(); //输入的字段字符串
    26. var field = inputType.GetField(fieldStr); //目标字段
    27. var isDefined = field?.IsDefined(descType, false);//判断描述是否在字段的特性
    28. if (isDefined ?? false)
    29. {
    30. var enumAttributes = field.GetCustomAttributes(descType, false) as RemarkAttribute[]; //得到特性信息
    31. description = enumAttributes?.FirstOrDefault()?.Remark ?? string.Empty;
    32. // description = string.Join(',', enumAttributes?.Select(t => t.Remark));
    33. }
    34. return description;
    35. }
    36. }

     

    1. public class IdValues
    2. {
    3. public string Id { get; set; }
    4. public string Value { get; set; }
    5. public string Value2 { get; set; }
    6. public string Value3 { get; set; }
    7. public string Value4 { get; set; }
    8. public string Value5 { get; set; }
    9. public int Standby { get; set; }
    10. public string Display { get; set; }
    11. public static bool operator ==(IdValues idValues, IdValues idValues2)
    12. {
    13. return idValues.Equals(idValues2);
    14. }
    15. public static bool operator !=(IdValues idValues, IdValues idValues2)
    16. {
    17. return !idValues.Equals(idValues2);
    18. }
    19. public override int GetHashCode()
    20. {
    21. var code = (Id, Value, Value2, Value3, Value4, Value5, Standby).GetHashCode();
    22. return code;
    23. }
    24. public override bool Equals(object? obj)
    25. {
    26. return obj?.GetHashCode() == GetHashCode();
    27. }
    28. const int TARGET = 0x1F;
    29. ///
    30. /// 将连续字段的哈希代码左移两位或更多位来加权各个哈希代码(最佳情况下,超出位 31 的位应环绕,而不是被丢弃)
    31. ///
    32. ///
    33. ///
    34. ///
    35. public int ShiftAndWrap(int value, int positions = 3)
    36. {
    37. positions &= TARGET;
    38. uint number = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
    39. uint wrapped = number >> (32 - positions);
    40. return BitConverter.ToInt32(BitConverter.GetBytes((number << positions) | wrapped), 0);
    41. }
    42. }

     

    1. internal static class SystemEx
    2. {
    3. ///
    4. /// 跨线程操作控件
    5. ///
    6. ///
    7. ///
    8. public static void ExecBeginInvoke(this Control con, Action action)
    9. {
    10. if (action == null) return;
    11. if (con.InvokeRequired)
    12. {
    13. con.BeginInvoke(new Action(action));
    14. }
    15. else
    16. {
    17. action();
    18. }
    19. }
    20. ///
    21. /// 跨线程操作控件
    22. ///
    23. ///
    24. ///
    25. public static void ExecInvoke(this Control con, Action action)
    26. {
    27. if (action == null) return;
    28. if (con.InvokeRequired)
    29. {
    30. con.Invoke(new Action(action));
    31. }
    32. else
    33. {
    34. action();
    35. }
    36. }
    37. }

     

  • 相关阅读:
    nydusd 源码理解(一)
    STM32小项目———感应垃圾桶
    mysql8.0下载安装配置一条龙,无坑教学yyds
    设计原则学习
    电子邮件-架构真题(二十八)
    react设置代理
    C语言典范编程
    PostgreSQL安全
    再获新融资,宏景智驾B轮总融资超6亿元
    亚马逊商品详情API接口-(item_get-获得AMAZON商品详情接口),亚马逊详情API接口
  • 原文地址:https://blog.csdn.net/ftfmatlab/article/details/133176302