当前位置: 首页 > news >正文

C# 实现数独游戏

1.数独单元

 public struct SudokuCell{public SudokuCell() : this(0, 0, 0){}public SudokuCell(int x, int y, int number){X = x; Y = y; Number = number;}public int X { get; set; }public int Y { get; set; }public int Number { get; set; }}

2.数独创建

public class SudokuGenerator{private const int BoardSize = 9;private const int EmptyCellValue = 0;private Random random;private readonly ChaosRandomEx chaosRandomEx;public SudokuGenerator(){random = new Random();chaosRandomEx = new ChaosRandomEx();}public SudokuCell[,] GenerateSudoku(DifficultyLevel difficulty){SudokuCell[,] board = new SudokuCell[BoardSize, BoardSize];// 初始化数独网格for (int row = 0; row < BoardSize; row++){for (int col = 0; col < BoardSize; col++){board[row, col] = new SudokuCell(row, col, EmptyCellValue);}}// 填充数独网格FillSudoku(board);// 根据难度要求移除部分单元格的值RemoveCells(board, difficulty);return board;}private void FillSudoku(SudokuCell[,] board){SolveSudoku(board);}private bool SolveSudoku(SudokuCell[,] board){int row = 0;int col = 0;if (!FindEmptyCell(board, ref row, ref col)){// 所有单元格都已填满,数独已解决return true;}List<int> numbers = GetRandomNumberSequence();foreach (int num in numbers){if (IsValidMove(board, row, col, num)){// 尝试填充数字board[row, col].Number = num;if (SolveSudoku(board)){// 递归解决剩余的单元格return true;}// 回溯到上一个单元格board[row, col].Number = EmptyCellValue;}}return false;}private bool FindEmptyCell(SudokuCell[,] board, ref int row, ref int col){for (row = 0; row < BoardSize; row++){for (col = 0; col < BoardSize; col++){if (board[row, col].Number == EmptyCellValue){return true;}}}return false;}public bool IsValidMove(SudokuCell[,] board, int row, int col, int num){// 检查行是否合法for (int i = 0; i < BoardSize; i++){if (board[i, col].Number == num){return false;}}// 检查列是否合法for (int i = 0; i < BoardSize; i++){if (board[row, i].Number == num){return false;}}// 检查子网格是否合法int subgridRow = (row / 3) * 3;int subgridCol = (col / 3) * 3;for (int i = 0; i < 3; i++){for (int j = 0; j < 3; j++){if (board[subgridRow + i, subgridCol + j].Number == num){return false;}}}return true;}private List<int> GetRandomNumberSequence(){List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };Shuffle(numbers);return numbers;}private void Shuffle<T>(List<T> list){int n = list.Count;while (n > 1){n--;int k = random.Next(n + 1);T value = list[k];list[k] = list[n];list[n] = value;}}private void RemoveCells(SudokuCell[,] board, DifficultyLevel difficulty){int cellsToRemove = GetCellsToRemoveCount(difficulty);for (int i = 0; i < cellsToRemove; i++){int row = random.Next(BoardSize);int col = random.Next(BoardSize);if (board[row, col].Number != EmptyCellValue){board[row, col].Number = EmptyCellValue;}else{i--;}}}private int GetCellsToRemoveCount(DifficultyLevel difficulty){return difficulty switch{DifficultyLevel.Medium => 32,DifficultyLevel.Hard => 44,DifficultyLevel.VeryHard => 56,DifficultyLevel.SuperHard => 68,DifficultyLevel.Insane => 80,_ => 20};}}

3.数独难度等级

public enum DifficultyLevel{/// <summary>/// 简单/// </summary>[Remark("简单")]Easy,/// <summary>/// 中等/// </summary>[Remark("中等")]Medium,/// <summary>/// 困难/// </summary>[Remark("困难")]Hard,/// <summary>/// 极难/// </summary>[Remark("极难")]VeryHard,/// <summary>/// 超难/// </summary>[Remark("超难")]SuperHard,/// <summary>/// 疯狂/// </summary>[Remark("疯狂")]Insane}

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

/// <summary>/// 递归回溯算法/// </summary>public class SudokuSolver{public SudokuCell[,] SolveSudoku(SudokuCell[,] board){var solution = new SudokuCell[board.GetLength(0), board.GetLength(1)];Array.Copy(board, solution, board.Length);if (BacktrackSolve(solution)){return solution;}else{// 没有找到解return null;}}private bool BacktrackSolve(SudokuCell[,] board){for (int row = 0; row < 9; row++){for (int col = 0; col < 9; col++){if (board[row, col].Number == 0){for (int num = 1; num <= 9; num++){if (IsValid(board, row, col, num)){board[row, col].Number = num;if (BacktrackSolve(board)){return true;}board[row, col].Number = 0; // 回溯}}return false; // 所有数字都尝试过,没有找到合适的解}}}return true; // 数独已经填满,找到解}private bool IsValid(SudokuCell[,] board, int row, int col, int num){// 检查同行是否有重复数字for (int i = 0; i < 9; i++){if (board[row, i].Number == num){return false;}}// 检查同列是否有重复数字for (int i = 0; i < 9; i++){if (board[i, col].Number == num){return false;}}// 检查同九宫格是否有重复数字int startRow = row - row % 3;int startCol = col - col % 3;for (int i = 0; i < 3; i++){for (int j = 0; j < 3; j++){if (board[startRow + i, startCol + j].Number == num){return false;}}}return true; // 没有重复数字}}

5.数独创建中心

public class SudokuCenter : IDisposable{public bool IsStart { get; set; } = false;private int _width;private int _height;public const int CELLSNUMBER = 9;public const int CELLSNUMBER2 = 20;private int _cellSize;private int _rowSize;public int CellSize=> _cellSize;public int RowSize => _rowSize;public int Height => _height;public int Width => _width;public int Padding => CELLSNUMBER2;private Bitmap _bitmap;public Bitmap GetBitmap{get=>(Bitmap)_bitmap?.Clone();private set => _bitmap = value;}public SudokuCell[,] Suduku { get;private set; }public SudokuCell[,] PlayerSuduku { get; private set; }/// <summary>/// 生成棋盘图/// </summary>/// <param name="w"></param>/// <param name="h"></param>public void InitCheckerBoard(int w, int h){w -= (CELLSNUMBER2 * 2 + 1);h -= (CELLSNUMBER2 * 2 + 1);_width = w;_height = h;_cellSize = _width / CELLSNUMBER;_rowSize = _height / CELLSNUMBER;Bitmap bitmap = new Bitmap(_width + CELLSNUMBER2, _height + CELLSNUMBER2);using (var g = Graphics.FromImage(bitmap)){g.SmoothingMode = SmoothingMode.AntiAlias;//g.Clear(Color.Gray);DrawCheckerBoard(g);}_bitmap?.Dispose();GetBitmap = bitmap;}public SudokuCell[,] GenerateSudoku(DifficultyLevel difficulty){SudokuGenerator sudokuGenerator = new SudokuGenerator();Suduku = sudokuGenerator.GenerateSudoku(difficulty);PlayerSuduku = new SudokuCell[Suduku.GetLength(0), Suduku.GetLength(1)];Array.Copy(Suduku, PlayerSuduku, Suduku.Length);return Suduku;}public Color SudukuColor { get; set; }= Color.Black;public Color SolutionColor { get; set; } = Color.Red;public Color TransparentColor { get; } = Color.Transparent;public Font Font { get; set; }= new Font("Arial", 20, FontStyle.Bold);public Bitmap DrawSolution(SudokuCell[,] board){using SolidBrush brush = new SolidBrush(SolutionColor);using SolidBrush brush2 = new SolidBrush(SudukuColor);var bm = GetBitmap;using var g = Graphics.FromImage(bm);for (int row = 0; row < CELLSNUMBER; row++){for (int col = 0; col < CELLSNUMBER; col++){int number = Suduku[row, col].Number;if (number != 0){DrawString(g, row, col, number.ToString(), brush2);}else{number = board[row, col].Number;DrawString(g, row, col, number.ToString(), brush);}}}return bm;}public void DrawSudoku(Graphics g, SudokuCell[,] board){using SolidBrush brush = new SolidBrush(SudukuColor);for (int row = 0; row < CELLSNUMBER; row++){for (int col = 0; col < CELLSNUMBER; col++){int num= board[row, col].Number;if((num != 0)){DrawString(g,row,col,num.ToString(), brush);}}}}public void DrawString(Graphics g,int row,int col,string number, SolidBrush brush){int x = CELLSNUMBER2 + col * _cellSize + _cellSize / 2 - 8;int y = CELLSNUMBER2 + row * _rowSize + _rowSize / 2 - 10;g.DrawString(number, Font, brush, new Point(x, y));}public Rectangle DrawTransparent(Graphics g, int row, int col){int off = 5;int off2 = 7;int x = CELLSNUMBER2 + col * _cellSize + off;int y = CELLSNUMBER2 + row * _rowSize+ off;using (SolidBrush brush = new SolidBrush(Color.White)) // 使用透明色进行擦除{var rec = new Rectangle(x, y, CellSize - off2, RowSize - off2);g.FillRectangle(brush, rec);return rec;}}public bool IsSolutionCorrect(SudokuCell[,] board, SudokuCell[,] solution){for (int row = 0; row < CELLSNUMBER; row++){for (int col = 0; col < CELLSNUMBER; col++){if (board[row, col].Number != solution[row, col].Number){return false;}}}return true;}public bool IsValidMove(SudokuCell[,] board, int row, int col, int num){// 检查行是否合法for (int i = 0; i < CELLSNUMBER; i++){if (board[i, col].Number == num){return false;}}// 检查列是否合法for (int i = 0; i < CELLSNUMBER; i++){if (board[row, i].Number == num){return false;}}// 检查子网格是否合法int subgridRow = (row / 3) * 3;int subgridCol = (col / 3) * 3;for (int i = 0; i < 3; i++){for (int j = 0; j < 3; j++){if (board[subgridRow + i, subgridCol + j].Number == num){return false;}}}return true;}private void DrawCheckerBoard(Graphics g){using Pen pen = new Pen(Color.Black, 1);using Pen pen2 = new Pen(Color.Black, 2);using Font font = new Font("Arial", 10, FontStyle.Regular);using SolidBrush brush = new SolidBrush(Color.Black);for (int i = 0; i < CELLSNUMBER + 1; i++){if (i == 0 || i % 3 == 0){g.DrawLine(pen2, new Point(CELLSNUMBER2, CELLSNUMBER2 + i * _rowSize), new Point(CELLSNUMBER2 + _cellSize * CELLSNUMBER, CELLSNUMBER2 + i * _rowSize));g.DrawLine(pen2, new Point(CELLSNUMBER2 + i * _cellSize, CELLSNUMBER2 + 0), new Point(CELLSNUMBER2 + i * _cellSize, CELLSNUMBER2 + _rowSize * CELLSNUMBER));}else{g.DrawLine(pen, new Point(CELLSNUMBER2, CELLSNUMBER2 + i * _rowSize), new Point(CELLSNUMBER2 + _cellSize * CELLSNUMBER, CELLSNUMBER2 + i * _rowSize));g.DrawLine(pen, new Point(CELLSNUMBER2 + i * _cellSize, CELLSNUMBER2 + 0), new Point(CELLSNUMBER2 + i * _cellSize, CELLSNUMBER2 + _rowSize * CELLSNUMBER));}int x = CELLSNUMBER2 + i * _cellSize + _cellSize / 2 - 5;int y = 0;g.DrawString((i + 1).ToString(), font, brush, new Point(x, y));x = 0;y = CELLSNUMBER2 + i * _rowSize + _rowSize / 2 - 5;g.DrawString((i + 1).ToString(), font, brush, new Point(x, y));}}public void Dispose(){_bitmap?.Dispose();}}

 6.数字键盘

 

 public partial class FrmNumber : Form{public FrmNumber(){InitializeComponent();foreach (Control item in this.Controls){item.Click += Item_Click;}}public Action<NumberArg> NumberCallback;public Point ClickPoint {  get; set; }public Point RowCell { get; set; }public Graphics Graphics { get; set; }private void Item_Click(object? sender, EventArgs e){Button btn = sender as Button;NumberArg numberArg = new NumberArg();if (btn.Name == "btnClear"){numberArg.Type = NumberType.Clear;}else if (btn.Name == "btnClose"){numberArg.Type = NumberType.Close;}else{numberArg.Type = NumberType.Number;numberArg.Value = btn.Text;}numberArg.CllickPoint = ClickPoint;numberArg.RowCell = RowCell;numberArg.Graphics = Graphics;NumberCallback?.Invoke(numberArg);this.Close();}private void FrmNumber_FormClosing(object sender, FormClosingEventArgs e){this.Dispose();}}public struct NumberArg{public NumberType Type { get; set; }public string Value { get; set; }public Point CllickPoint { get; set; }public Graphics Graphics { get; set; }public Point RowCell { get; set; }}public enum NumberType{Clear,Close,Number}

7.主窗体 

 

public partial class FrmMain : Form{private SudokuCenter _sudokuCenter;private System.Windows.Forms.Timer _timer;public FrmMain(){InitializeComponent();this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.OptimizedDoubleBuffer |ControlStyles.UserPaint |ControlStyles.AllPaintingInWmPaint,true);this.UpdateStyles();this.DoubleBuffered = true;_sudokuCenter = new SudokuCenter();_sudokuCenter.InitCheckerBoard(this.pbGameBack.Width, this.pbGameBack.Height);BindType(typeof(DifficultyLevel), this.cbDifficultyLevel, "Easy");}private void BindType(Type type, ComboBox comboBox, string defaultValue){var enumValues = Enum.GetValues(type);var list = new List<IdValues>();int index = 0, curIndex = 0;foreach (Enum value in enumValues){int hc = value.GetHashCode();list.Add(new IdValues{Id = hc.ToString(),Value = value.ToString(),Display= value.GetEnumDesc(),Standby = hc});if (value.ToString() == defaultValue)index = curIndex;curIndex++;}comboBox.ValueMember = "Id";comboBox.DisplayMember = "Display";comboBox.DataSource = list;comboBox.SelectedIndex = index;}private void pbGameBack_Paint(object sender, PaintEventArgs e){if (sudukuBitmap != null){e.Graphics.DrawImage(sudukuBitmap, 0, 0, pbGameBack.Width, pbGameBack.Height);}}public string Compute(long time){if (time < 60)return $"00:{ChangeString(time)}";long minute = time / 60;if (minute < 60)return $"{ChangeString(minute)}:{ChangeString(time % 60)}";long hour = minute / 60;return $"{ChangeString(hour)}:{Compute(time - hour * 3600)}";}private string ChangeString(long val){return val.ToString("D2");}/// <summary>/// 开始/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btnStart_Click(object sender, EventArgs e){StartGame();}Bitmap sudukuBitmap;private void StartGame(){if (_sudokuCenter.IsStart){if (MessageBox.Show("你正在开始游戏,确认重新开始吗?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel){return;}}if (_timer != null){_timer.Stop();_timer.Dispose();}time = 0;_timer = new System.Windows.Forms.Timer();_timer.Interval = 1000;_timer.Tick += timer_Tick;_timer.Start();DifficultyLevel level = (DifficultyLevel)(this.cbDifficultyLevel.Items[cbDifficultyLevel.SelectedIndex] as IdValues).Standby;var sudoku = _sudokuCenter.GenerateSudoku(level);this.pbGameBack.Image?.Dispose();sudukuBitmap?.Dispose();sudukuBitmap = null;sudukuBitmap = _sudokuCenter.GetBitmap;using var g = Graphics.FromImage(sudukuBitmap);_sudokuCenter.DrawSudoku(g, sudoku);_sudokuCenter.IsStart = true;pbGameBack.Invalidate();}long time = 0;private void timer_Tick(object? sender, EventArgs e){lblTime.ExecBeginInvoke(() =>{lblTime.Text = Compute(++time);});}/// <summary>/// 答案/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btnSolution_Click(object sender, EventArgs e){if (!_sudokuCenter.IsStart){return;}if (MessageBox.Show("你正在开始游戏,确认显示答案吗?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel){return;}SudokuSolver sudokuSolver = new SudokuSolver();var solveSudoku = sudokuSolver.SolveSudoku(_sudokuCenter.Suduku);var bm = _sudokuCenter.DrawSolution(solveSudoku);pbGameBack.Image?.Dispose();sudukuBitmap?.Dispose();sudukuBitmap = null;sudukuBitmap = bm;//pbGameBack.Image = bm;_sudokuCenter.IsStart = false;pbGameBack.Invalidate();}private void pbGameBack_MouseDown(object sender, MouseEventArgs e){if (_sudokuCenter.Suduku == null || !_sudokuCenter.IsStart)return;int row = (e.Y - _sudokuCenter.Padding * 2) / _sudokuCenter.RowSize;int col = (e.X - _sudokuCenter.Padding * 2) / _sudokuCenter.CellSize;// 检测鼠标是否在小方格内if (row >= 0 && row < 9 && col >= 0 && col < 9){var number = _sudokuCenter.Suduku[row, col].Number;if (number != 0)return;using (FrmNumber fn = new FrmNumber()){fn.NumberCallback = NumberCallback;Point p = pbGameBack.PointToScreen(Point.Empty);fn.StartPosition = FormStartPosition.Manual;fn.Location = new Point(p.X + e.X + (_sudokuCenter.CellSize >> 1), p.Y + e.Y + (_sudokuCenter.RowSize >> 1));fn.ClickPoint = new Point(e.X, e.Y);fn.RowCell = new Point(row, col);fn.ShowDialog();}}}private void NumberCallback(NumberArg arg){switch (arg.Type){case NumberType.Number:DrawString(arg.RowCell.X, arg.RowCell.Y, arg.Value);int num = Convert.ToInt32(arg.Value);if (cbPrompt.Checked){bool status = _sudokuCenter.IsValidMove(_sudokuCenter.PlayerSuduku, arg.RowCell.X, arg.RowCell.Y, num);lblPrompt.Text = status ? "你真棒!" : "重复了";}else{lblPrompt.Text = "已写入";}_sudokuCenter.PlayerSuduku[arg.RowCell.X, arg.RowCell.Y].Number = num;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));break;case NumberType.Clear:using (var g = Graphics.FromImage(sudukuBitmap)){_sudokuCenter.PlayerSuduku[arg.RowCell.X, arg.RowCell.Y].Number = 0;var rec= _sudokuCenter.DrawTransparent(g, arg.RowCell.X, arg.RowCell.Y);lblPrompt.Text = "已清除";pbGameBack.Invalidate(rec);}break;}}private void DrawString(int row, int col, string num){using (var g = Graphics.FromImage(sudukuBitmap)){using SolidBrush brush = new SolidBrush(_sudokuCenter.SolutionColor);_sudokuCenter.DrawTransparent(g, row, col);_sudokuCenter.DrawString(g, row, col, num, brush);}}private void DrawString(Graphics g, int row, int col, string num){using SolidBrush brush = new SolidBrush(_sudokuCenter.SolutionColor);_sudokuCenter.DrawTransparent(g, row, col);_sudokuCenter.DrawString(g, row, col, num, brush);pbGameBack.Invalidate(new Rectangle(SudokuCenter.CELLSNUMBER2 + col * _sudokuCenter.CellSize, SudokuCenter.CELLSNUMBER2 + row * _sudokuCenter.RowSize, _sudokuCenter.CellSize, _sudokuCenter.RowSize));}/// <summary>/// 提交/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btnSubmit_Click(object sender, EventArgs e){if (!_sudokuCenter.IsStart){return;}if (MessageBox.Show("你正在开始游戏,确认提交答案吗?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel){return;}_timer.Stop();SudokuSolver sudokuSolver = new SudokuSolver();var solveSudoku = sudokuSolver.SolveSudoku(_sudokuCenter.Suduku);bool status = _sudokuCenter.IsSolutionCorrect(_sudokuCenter.PlayerSuduku, solveSudoku);if (status){lblPrompt.Text = "全对了,你真棒!";MessageBox.Show("全对了,你真棒!", "恭喜");}else{lblPrompt.Text = "很遗憾,有错误!";MessageBox.Show("很遗憾,有错误!", "失败");for (int row = 0; row < SudokuCenter.CELLSNUMBER; row++){for (int col = 0; col < SudokuCenter.CELLSNUMBER; col++){if (solveSudoku[row, col].Number != _sudokuCenter.PlayerSuduku[row, col].Number){this.DrawString(row, col, solveSudoku[row, col].Number.ToString());}}}pbGameBack.Invalidate();}_sudokuCenter.IsStart = false;}/// <summary>/// 重新开始/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btnRestart_Click(object sender, EventArgs e){StartGame();}private void FrmMain_FormClosing(object sender, FormClosingEventArgs e){_sudokuCenter.Dispose();this.pbGameBack.Image?.Dispose();this.pbGameBack.Dispose();if (_timer != null){_timer.Stop();_timer.Dispose();}this.Dispose();}}

8.其它

 public class RemarkAttribute : Attribute{/// <summary>/// 备注/// </summary>public string Remark { get; set; }public RemarkAttribute(string remark){this.Remark = remark;}}public static class EnumEx{/// <summary>/// 根据枚举元素,获取该枚举元素的描述信息/// </summary>/// <typeparam name="T"></typeparam>/// <param name="tField"></param>/// <returns></returns>public static string GetEnumDesc<T>(this T tField) where T : Enum{var description = string.Empty; //结果var inputType = tField.GetType(); //输入的类型var descType = typeof(RemarkAttribute); //目标查找的描述类型var fieldStr = tField.ToString();                //输入的字段字符串var field = inputType.GetField(fieldStr);        //目标字段var isDefined = field?.IsDefined(descType, false);//判断描述是否在字段的特性if (isDefined ?? false){var enumAttributes = field.GetCustomAttributes(descType, false) as RemarkAttribute[];  //得到特性信息description = enumAttributes?.FirstOrDefault()?.Remark ?? string.Empty;//  description = string.Join(',', enumAttributes?.Select(t => t.Remark));}return description;}}

 

 public class IdValues{public string Id { get; set; }public string Value { get; set; }public string Value2 { get; set; }public string Value3 { get; set; }public string Value4 { get; set; }public string Value5 { get; set; }public int Standby { get; set; }public string Display { get; set; }public static bool operator ==(IdValues idValues, IdValues idValues2){return idValues.Equals(idValues2);}public static bool operator !=(IdValues idValues, IdValues idValues2){return !idValues.Equals(idValues2);}public override int GetHashCode(){var code = (Id, Value, Value2, Value3, Value4, Value5, Standby).GetHashCode();return code;}public override bool Equals(object? obj){return obj?.GetHashCode() == GetHashCode();}const int TARGET = 0x1F;/// <summary>/// 将连续字段的哈希代码左移两位或更多位来加权各个哈希代码(最佳情况下,超出位 31 的位应环绕,而不是被丢弃)/// </summary>/// <param name="value"></param>/// <param name="positions"></param>/// <returns></returns>public int ShiftAndWrap(int value, int positions = 3){positions &= TARGET;uint number = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);uint wrapped = number >> (32 - positions);return BitConverter.ToInt32(BitConverter.GetBytes((number << positions) | wrapped), 0);}}

 

 internal static class SystemEx{/// <summary>/// 跨线程操作控件/// </summary>/// <param name="con"></param>/// <param name="action"></param>public static void ExecBeginInvoke(this Control con, Action action){if (action == null) return;if (con.InvokeRequired){con.BeginInvoke(new Action(action));}else{action();}}/// <summary>/// 跨线程操作控件/// </summary>/// <param name="con"></param>/// <param name="action"></param>public static void ExecInvoke(this Control con, Action action){if (action == null) return;if (con.InvokeRequired){con.Invoke(new Action(action));}else{action();}}}

 

相关文章:

C# 实现数独游戏

1.数独单元 public struct SudokuCell{public SudokuCell() : this(0, 0, 0){}public SudokuCell(int x, int y, int number){X x; Y y; Number number;}public int X { get; set; }public int Y { get; set; }public int Number { get; set; }} 2.数独创建 public class …...

vscode + conda+ ffmpeg + numpy 的安装方式

Windows 搭建 环境 遇到的错误点&#xff1a; 解决&#xff0c;使用conda init conda activate myenv usage: conda-script.py [-h] [–no-plugins] [-V] COMMAND … conda-script.py: error: argument COMMAND: invalid choice: ‘activate’ (choose from ‘clean’, ‘comp…...

Python Union联合类型注解

视频版教程 Python3零基础7天入门实战视频教程 我们看下如下的示例&#xff1a; my_list2: list[int] [1, 2, 3, 4] my_dict2: dict[str, float] {"python222": 3.14, "java1234": 4.35} l1 [1, "python222", True] # 如何注解多种元素类型…...

提高接口自动化测试效率:使用 JMESPath 实现断言和数据提取!

前言 做接口自动化&#xff0c;断言是比不可少的。如何快速巧妙的提取断言数据就成了关键&#xff0c;当然也可以提高用例的编写效率。笔者在工作中接触到了JMESPath&#xff0c;那到底该如何使用呢&#xff1f;带着疑惑一起往下看。 JMESPath是啥&#xff1f; JMESPath 是一…...

【Linux操作系统教程】用户管理与权限管理你真的懂了吗(三)

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。&#x1f60a; 座右铭&#xff1a;不想…...

华为全联接大会2023 | 尚宇亮:携手启动O3社区发布

2023年9月20日&#xff0c;在华为全联接大会2023上&#xff0c;华为正式发布“联接全球服务工程师&#xff0c;聚合用户服务经验”的知识经验平台&#xff0c;以“Online 在线、Open 开放、Orchestration 协同”为理念&#xff0c;由华为、伙伴和客户携手&#xff0c;共同构建知…...

MySQL数据库查缺补漏——基础篇

MySQL数据库查缺补漏-基础篇 基础篇 net start mysql80[服务名] net stop mysql80 create database pshdhx default charset utf8mb4; 为什么不使用utf8&#xff1f;因为其字符占用三个字节&#xff0c;有四个字节的字符&#xff0c;所有需要设置为utf8mb4; 数值类型&…...

ESP8266 WiFi物联网智能插座—电能计量

目录 1、芯片功能 2、性能指标 3、寄存器说明 4、UART通信协议 4.1、写操作帧格式和时序 4.2、读操作帧格式和时序 4.3、读取全电参数数据包 4.4、配置波特率 4.5、UART保护机制 5、功能说明 5.1、电流电压瞬态波形计量 5.2、有功功率 5.3、有功功率防潜动 5.4、电能计量 5.5、…...

“智慧”北京,人工智能引领“新风尚”

原创 | 文 BFT机器人 北京时间&#xff0c;9月15日&#xff0c;北京人工智能产业峰会暨中关村科学城科创大赛颁奖典礼在北京中关村举行&#xff0c;同时惠阳还举行了“中关村人工智能大模型产业集聚区”启动建设的揭牌仪式。 此次大会围绕北京AI产业的建设与发展&#xff0c;各…...

狮子鱼社区团购小程序v18.1独立全开源版+小程序前端

狮子鱼社区团购商城系统小程序V18.1独立开源版&#xff0c;该系统本身就非常完善也没更新的必要&#xff0c;此系统拿来即用非常方便&#xff0c;同一版一样人类小徐特别优化很多细节首页美化了下&#xff0c;如小程序端授权窗口美化了下&#xff0c;该版本用户授权接口正常。功…...

深拷贝和浅拷贝的区别

本文内容 主要阐述下深拷贝和浅拷贝的区别 通俗理解 深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体&#xff0c;而不是引用。 假设B复制了A&#xff0c;修改A的时候&#xff0c;看B是否发生变化&#xff1a; 如果B跟着也变了&#xff0c;说明是浅拷贝&…...

利用优化算法提高爬虫任务调度效率

目录 一、任务调度优化的重要性 二、选择合适的优化算法 三、建立任务调度模型 四、设计适应性函数 五、算法实施和调优 六、性能评估和优化结果分析 代码示例 总结 随着网络信息的爆炸式增长&#xff0c;网络爬虫在信息获取和数据挖掘等领域的应用越来越广泛。然而&am…...

Swiper的使用流程

1.官网查看演示 Swiper演示 - Swiper中文网 2.找到想使用的 比如想使用 卡片切换(255) 记住这个名字 3.去下载示例 下载Swiper - Swiper中文网 4.找到对应文件 5.根据里面引入的东西加到自己的页面 一定要引入swiper的 js 和 css html结构要按示例对应的三层结构 需要 …...

如何快速实现一个可视化看板?

一、用python实现一个可视化数据看板&#xff0c;最多支持多大体量的数据处理&#xff1f; Python可以通过多种可视化库来实现数据看板&#xff0c;例如Matplotlib、Seaborn、Plotly等。这些库可以处理各种规模的数据&#xff0c;从小型数据集到大型数据集都可以应用。 对于小型…...

基于PyTorch搭建FasterRCNN实现目标检测

基于PyTorch搭建FasterRCNN实现目标检测 1. 图像分类 vs. 目标检测 图像分类是一个我们为输入图像分配类标签的问题。例如&#xff0c;给定猫的输入图像&#xff0c;图像分类算法的输出是标签“猫”。 在目标检测中&#xff0c;我们不仅对输入图像中存在的对象感兴趣。我们还…...

线性表应用(非递减合并、分解链表、删除线性表)

将两个非递减的有序链表合并为一个非递增的有序链表。要求结果链表仍使用原来两个链表的存储空间&#xff0c;不另外占用其它的存储空间。表中允许有重复的数据。 #include<iostream> using namespace std; typedef struct list {int data;list* next; }list,*linklist;…...

【C++面向对象侯捷下】1.导读

文章目录 来源&#xff1a;我的百度网盘 百科全书 专家书籍 C标准库 C编译器...

Ubuntu22.04 vnc远程黑屏

一、原因 原因是Ubuntu22.04使用的gnome启用了Wayland。vnc、teamviewer、向日葵、todesk等均无法使用或者远程黑屏等。 简单的说vnc、teamviewer、向日葵、todesk等均基于xorg实现&#xff08;xorg太流行&#xff09;&#xff0c;并不兼容Wayland&#xff0c;所以vnc无法正常…...

【1区TOP】Elsevier旗下CCF推荐,仅3个月左右录用!

01 期刊简介 CCF推荐人工智能类SCIE&EI 【期刊概况】IF&#xff1a;8.0-9.0&#xff0c;JCR1区&#xff0c;中科院2区TOP&#xff1b; 【版面类型】正刊&#xff1b; 【检索情况】SCIE&EI双检&#xff0c;CCF推荐&#xff1b; 【数据库收录年份】1992年&#xff…...

CentOS下安装Python3

一、电脑有网络&#xff1a; 1、直接使用yum包管理安装&#xff1a; yum是CentOS的默认包管理器&#xff0c;在安装软件时非常方便。要安装Python3&#xff0c;可以使用以下命令&#xff1a; sudo yum install python3等待安装完成后&#xff0c;查看python3是否安装完成 //不…...

微信小程序底部安全区域高度获取

CSS 属性 safe-area-inset-bottom safe-area-inset-bottom 就是安全区的高度 padding-bottom:env(safe-area-inset-bottom); wx.getSystemInfoSync() wx.getSystemInfoSync()可以获取系统信息 let system wx.getSystemInfoSync() let bottomSafe system.screenHeight -…...

虚拟机部署linux网络连接配置

1、虚拟机安装linux后&#xff0c;配置网络访问 虚拟机网络设置为NAT模式 linux网络配置好IP&#xff0c;主要是以下网络配置 2、linux没有ifconfig命令&#xff0c;ifconfig命令是在net-tools.x86_64包里 yum install net-tools.x86_64安装...

2591. 将钱分给最多的儿童(Java)

给你一个整数 money &#xff0c;表示你总共有的钱数&#xff08;单位为美元&#xff09;和另一个整数 children &#xff0c;表示你要将钱分配给多少个儿童。 你需要按照如下规则分配&#xff1a; 所有的钱都必须被分配。 每个儿童至少获得 1 美元。 没有人获得 4 美元。 请你…...

c++23中的新功能之十五类tuple类型的完全支持

一、std::tuple和std::pair 在传统的C里一直有一个问题让开发者不爽&#xff0c;就是无法返回多个值。一般来说&#xff0c;返回多个都建议采用封装的模式&#xff0c;比如弄一个结构体或者类啥的。这样做一定时没有问题的&#xff0c;但对于一些只返回一些简单值并且只在偶尔…...

iPhone15线下购买,苹果零售店前门店排长队

今年的苹果新品发布会于北京时间 9 月 13 日凌晨举行&#xff0c;并于 9 月 15 日&#xff08;周五&#xff09;开启订购&#xff0c;9 月 22 日&#xff08;周五&#xff09;起正式发售。 据多位网友反馈&#xff0c;首批苹果 iPhone15 系列手机、Apple Watch Ultra 2 / Seri…...

Vue3如何优雅的加载大量图片?

前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 表妹一键制作自己的五星红旗国庆头像&#xff0c;超好看 最近开发了一个功能&#xff0c;页面首页会加载大量的图片&#xff0c;初次进入页面时&#xff…...

Go语言开发环境搭建指南:快速上手构建高效的Go开发环境

Go 官网&#xff1a;https://go.dev/dl/ Go 语言中文网&#xff1a;https://studygolang.com/dl 下载 Go 的语言包 进入官方网站 Go 官网 或 Go 语言中文网&#xff1a; 选择下载对应操作系统的安装包&#xff1a; 等待下载完成&#xff1a; 安装 Go 的语言包 双击运行上…...

flex布局与float布局

float布局 俩栏 三栏 flex布局...

【C语言】字符函数和字符串函数(含模拟)

前言&#xff1a; 在做OJ题或阅读代码时或多或少会遇到一些字符函数和字符串函数&#xff0c; 如果不认识或不熟悉就会造成不便&#xff0c; 本篇文章主要是为了这方面而存在&#xff0c; 此篇介绍各个字符串的功能与使用方法&#xff0c; 下一篇会讲解如何模拟这些函数 重点&a…...

基于YOLOv8模型的条形码二维码检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOv8模型的条形码二维码检测系统可用于日常生活中检测与定位条形码与二维码目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目标检测…...

相亲网站做推广的照片是谁/培训机构需要哪些证件

一.概述 linux中不区分进程和线程,都认为是个任务,都是创建一个task_struct.如何区分?线程是共享相同地址空间,而进程是独占地址空间. 多线程共享同一进程的地址空间 优点: 通信方便,可以通过全局变量. 缺点: 访问共享数据时需要考虑同步和互斥. 二.线程共享资源: 可执行的指令…...

惠州网站建设制作/网站建设公司大型

一、链表题目 1、从尾到头打印链表 使用栈&#xff08;也可以使用数组&#xff0c;逆序输出&#xff09; /** * public class ListNode { * int val; * ListNode next null; * * ListNode(int val) { * this.val val; * } * …...

做彩票网站代理/淘宝大数据查询平台

如何玩转iPhone手机&#xff1f;最近手机连接投影仪被大家关注&#xff0c;那么苹果手机是如何连接投影仪的呢&#xff1f;新出的iPhone8可以连接吗&#xff1f;跟随小编一起来了解一下详细的步骤教程吧。苹果手机与投影仪连接的方法教程&#xff08;步骤&#xff09; 1、第一次…...

存量权益登记在哪个网站上做/手机一键优化

1 迭代器 1.1 定义迭代器是指能用next&#xff08;it&#xff09;函数取值的对象&#xff08;实例&#xff09; 1.2 说明1 用iter函数可返回一个可迭代对象的迭代器2 迭代器是访问可迭代对象的一种方式3 迭代器只能往前&#xff0c;不能后退 1.3 示例L [1,1,2,3,5,8] it iter…...

网站怎么做脚注/北京优化靠谱的公司

打开Eclipse下该文件&#xff1a;\configuration\.settings\org.eclipse.ui.ide.prefs 删除&#xff1a;“RECENT_WORKSPACES” 后面不用的工作空间。转载于:https://www.cnblogs.com/ace-9527/p/4957975.html...

解决wordpress主题缺少style.css无法安装的方法/谷歌seo推广培训班

一、docker是什么 1、为什么会有docker 一款产品从开发到上线&#xff0c;从操作系统&#xff0c;到运行环境&#xff0c;再到应用配置。作为开发运维之间的协作我们需要关心很多东西&#xff0c;这也是很多互联网公司都不得不面对的问题&#xff0c;特别是各种版本的迭代之后…...