diff --git a/App.config b/App.config index 34bcd2ff2087511fe6fee357da65d0ebab7f3cb5..752e990340b8ac4418aadccd77792a29eeae8601 100644 --- a/App.config +++ b/App.config @@ -44,6 +44,18 @@ 0 + + False + + + 0 + + + 1 + + + False + \ No newline at end of file diff --git a/Chess.csproj b/Chess.csproj index c283e4c91351f6dd0a7c1a818642fa558d87b9c7..9bb7b6cd1c4b672aaa960dde14742a6601561f78 100644 --- a/Chess.csproj +++ b/Chess.csproj @@ -41,6 +41,10 @@ + + + + @@ -145,6 +149,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/CustomClass/PathPoint.xaml.cs b/CustomClass/PathPoint.xaml.cs index b1b64a3e81890e12b79c1acbd4df25f1e2743845..84724331a3566387887893dc6fb3d569bce495c8 100644 --- a/CustomClass/PathPoint.xaml.cs +++ b/CustomClass/PathPoint.xaml.cs @@ -104,7 +104,7 @@ namespace Chess // 电脑对战,第一步需人为走出。此处暂保留,后期可能删除 if (MainWindow.menuItem == 100) { - while (GlobalValue.EnableGameStop == false && GlobalValue.IsGameOver == false) + while (GlobalValue.EnableGameStop == false && GlobalValue.IsGameOver == false ) { GlobalValue.Delay(Settings.Default.MoveDelayTime); Qipu.StepCode step = Engine.XQEngine.UcciInfo.GetBestSetp(); diff --git a/CustomClass/Qipu.cs b/CustomClass/Qipu.cs index 0210a0bd755037966db79befaae0a75d55d4cdb8..e77343f6fac4df24060cc27dbf4a1962dde46aa1 100644 --- a/CustomClass/Qipu.cs +++ b/CustomClass/Qipu.cs @@ -306,11 +306,11 @@ namespace Chess.CustomClass string str = ""; QiPuRecord record = this.Cursor; if (record.IsRoot()) return str; - for (int i = 0; i < 20; i++) + for (int i = 0; i < 6; i++) { if (!record.IsRoot()) { - str += " " + record.StepData.UcciStep; + str =record.StepData.UcciStep + " " + str; record = record.GetParent(); } } diff --git a/Engine/XQEngine.cs b/Engine/XQEngine.cs index f106cb4f1f6755fe1824aebbf108598bba60e60c..fa5863699d7700374749453da36afc6c0d86d5ea 100644 --- a/Engine/XQEngine.cs +++ b/Engine/XQEngine.cs @@ -2,46 +2,285 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Threading.Tasks; +using System.Windows; namespace Chess.Engine { + using Newtonsoft.Json.Linq; + using System; + using System.DirectoryServices; + using System.IO; + using System.Text; + using System.Text.RegularExpressions; + using System.Threading; + using System.Windows.Input; + using System.Windows.Media; + using System.Xml.Linq; + + //输入调试用涵数 + public class FileWriter + { + public static void AppendToFile(string content) + { + if (!Settings.Default.WriteDebug) + { + return; + } + string filePath = Environment.CurrentDirectory + "\\debug.txt"; + try + { + using (StreamWriter writer = File.AppendText(filePath)) + { + //writer.WriteLine(DateTime.Now.ToString()); + writer.WriteLine(content); + writer.Close(); + } + + //Console.WriteLine("内容已成功追加到文件中。"); + } + catch (Exception ex) + { + Console.WriteLine("追加内容到文件时出现错误: " + ex.Message); + } + } + } public class XQEngine { + public static Process proEngine_eleeye; + public static Process proEngine_pikafish; public static UcciInfoClass UcciInfo = new(); // 推荐着法存储类 + ~XQEngine() + { + CloseEngine_eleeye(); + CloseEngine_pikafish(); + } + + static void KillProcessesByName(string processName) + { + Process[] processes = Process.GetProcessesByName(processName); + + foreach (Process process in processes) + { + process.Kill(); + process.WaitForExit(); + } + } + + /// + /// 初始化调用象棋引擎,调入局面库 + /// + + + public static void InitEngine() + { + //CloseEngine(); + //InitEngine_pikafish(1, 1); + } + + public static void CloseEngine() + { + CloseEngine_eleeye(); + CloseEngine_pikafish(); + } + + /// - /// 调用象棋引擎eleeye.exe,获取推荐走棋着法 + /// /// /// 思考限制时间 /// 计算深度 /// public static string CallEngine(int thinkTime, int depth) { + + if (Settings.Default.AIEasyMode) + { + thinkTime = 1;//用简易模式调用象棋引擎 + depth = 1; //预留参用,未启用 + } + + if (GlobalValue.SideTag == GlobalValue.BLACKSIDE) + { + //增加一个PC1 使用引擎,PC2 使用引擎选项设置参数,可以灵活使用。 + if (Settings.Default.PCBlackAI==1) + return CallEngine_eleeye(thinkTime); + else + return CallEngine_pikafish(thinkTime); + } + + else + { + if (Settings.Default.PCRedAI == 1) + return CallEngine_eleeye(thinkTime); + else + return CallEngine_pikafish(thinkTime); + } + } + + static void CloseEngine_eleeye() + { + if (proEngine_eleeye != null) // && !proEngine_eleeye.HasExited) + { + proEngine_eleeye.StandardInput.WriteLine("quit"); + proEngine_eleeye.WaitForExit(); + + proEngine_eleeye.StandardInput.Close(); + proEngine_eleeye.Close(); + } + KillProcessesByName("eleeye"); + } + + static void CloseEngine_pikafish() + { + if (proEngine_pikafish != null) //&& !proEngine_pikafish.HasExited) + { + proEngine_pikafish.StandardInput.WriteLine("quit"); + proEngine_pikafish.WaitForExit(); + proEngine_pikafish.StandardInput.Close(); + proEngine_pikafish.Close(); + } + KillProcessesByName("pikafish"); + } + + static bool EngineOutputReceived = false; + static string EngineOutput = string.Empty; + static string EngineProcess_ReadToEnd() + { + //处理异步管道输出涵数 + EngineOutput = string.Empty; // 清空缓存 + EngineOutputReceived = false; // 重置标志 + // 等待异步事件处理完成 + long WaitTime = 0; + while (!EngineOutputReceived && WaitTime< Settings.Default.MoveDelayTime) + { + System.Threading.Thread.Sleep(10); // 避免循环过快占用 CPU + WaitTime += 1; //// 避免无结果死循环 + } + + EngineOutputReceived = false; // 重置标志 + string output = EngineOutput; + EngineOutput = string.Empty; // 清空缓存 + return output; + } + + static void EngineProcess_OutputDataReceived(object sender, DataReceivedEventArgs e) + { + if (e.Data != null) + { + EngineOutput = EngineOutput + e.Data + Environment.NewLine ; + + if (e.Data.Contains("bestmove")) + EngineOutputReceived = true; + } + } + + + static string CallEngine_eleeye(int thinkTime) + { //这个引擎在某些FEN下有问题比如:position fen 1rbakab1r/c8/2n3nc1/p1R1p1p1p/2p6/6P2/P1P1P3P/2N1C2C1/9/2BAKABNR w moves g3g4 c6c5 b0b6 b7a7 b6c6 a7a8 + //应该到红方走,给出的结果是黑方继续走 + //depth 和 time 只需要一个,不需要执行两次 + GlobalValue.EngineMode = GlobalValue.EngineTypes.eleeye; string fenstr = QiPanDataToFenStr(); - Process proEngine = new() + + if (proEngine_eleeye == null || proEngine_eleeye.HasExited) { - StartInfo = new ProcessStartInfo() + + proEngine_eleeye = new Process() { - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - RedirectStandardInput = true, - CreateNoWindow = true, - FileName = "Engine/eleeye.exe" - } - }; - proEngine.Start(); - proEngine.StandardInput.WriteLine("ucci"); - proEngine.StandardInput.WriteLine("setoption batch on"); - proEngine.StandardInput.WriteLine("position fen " + fenstr); - proEngine.StandardInput.WriteLine("go time " + thinkTime.ToString()); - proEngine.StandardInput.WriteLine("go depth " + depth.ToString()); - proEngine.StandardInput.WriteLine("quit"); - string output = proEngine.StandardOutput.ReadToEnd(); - proEngine.Close(); + StartInfo = new ProcessStartInfo() + { + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + CreateNoWindow = true, + FileName = "Engine/eleeye.exe" + } + }; + + proEngine_eleeye.OutputDataReceived += EngineProcess_OutputDataReceived; // 添加事件处理程序 + proEngine_eleeye.Start(); + + proEngine_eleeye.StandardInput.WriteLine("ucci"); + proEngine_eleeye.StandardInput.WriteLine("setoption name Repetition Rule value ChineseRule"); + proEngine_eleeye.StandardInput.WriteLine("setoption batch on"); + } + proEngine_eleeye.StandardInput.WriteLine("position fen " + fenstr); + proEngine_eleeye.StandardInput.WriteLine("go time " + thinkTime.ToString()); + //proEngine_eleeye.StandardInput.WriteLine("go depth " + depth.ToString()); + + proEngine_eleeye.BeginOutputReadLine(); // 开始异步读取标准输出 + string output = EngineProcess_ReadToEnd(); + proEngine_eleeye.CancelOutputRead(); // 停止异步读取标准输出 + + FileWriter.AppendToFile("------------CallEngine_eleeye:---------------"); + FileWriter.AppendToFile("position fen " + fenstr); + FileWriter.AppendToFile("go time " + thinkTime.ToString()); + // FileWriter.AppendToFile("go depth " + depth.ToString()); + FileWriter.AppendToFile(output); + + if (!output.Contains("nobestmove") && output.Contains("bestmove")) + { + int start = output.IndexOf("info depth"); + output = output[start..]; + output = output.Replace("bye" + Environment.NewLine, ""); + } + else + { + output = "No BestMove!"; + } + + + return output; + } + + + static string CallEngine_pikafish(int thinkTime) + { + //depth 和 time 只需要一个,不需要执行两次 + GlobalValue.EngineMode = GlobalValue.EngineTypes.pikafish; + thinkTime = Settings.Default.MoveDelayTime / 100; //Math.Min(thinkTime, 10); + string fenstr = QiPanDataToFenStr(); + + if (proEngine_pikafish == null || proEngine_pikafish.HasExited) + { + proEngine_pikafish = new Process() + { + StartInfo = new ProcessStartInfo() + { + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + CreateNoWindow = true, + FileName = "Engine/pikafish.exe" + } + }; + + proEngine_pikafish.OutputDataReceived += EngineProcess_OutputDataReceived; // 添加事件处理程序 + proEngine_pikafish.Start(); + + proEngine_pikafish.StandardInput.WriteLine("uci"); + proEngine_pikafish.StandardInput.WriteLine("setoption name Repetition Rule value ChineseRule"); + } + proEngine_pikafish.StandardInput.WriteLine("position fen " + fenstr); + //proEngine_pikafish.StandardInput.WriteLine("go depth " + depth.ToString()); + proEngine_pikafish.StandardInput.WriteLine("go movetime " + thinkTime.ToString()); + + proEngine_pikafish.BeginOutputReadLine(); // 开始异步读取标准输出 + string output = EngineProcess_ReadToEnd(); + proEngine_pikafish.CancelOutputRead(); // 停止异步读取标准输出 + + FileWriter.AppendToFile("------------CallEngine_pikafish:---------------"); + FileWriter.AppendToFile("position fen " + fenstr); + //FileWriter.AppendToFile("go depth " + depth.ToString()); + FileWriter.AppendToFile("go movetime " + thinkTime.ToString()); + FileWriter.AppendToFile(output); + if (!output.Contains("nobestmove")) { - // 裁剪掉无用信息 int start = output.IndexOf("info depth"); output = output[start..]; output = output.Replace("bye" + Environment.NewLine, ""); @@ -50,9 +289,12 @@ namespace Chess.Engine { output = "No BestMove!"; } + return output; } + + // UCCI标准棋子名称,小写为黑方,对应0-15,大写为红方,对应16-31,见GlobalValue.qiZiCnName棋子名称数组 private static readonly string[] Fen = { "k","a","a","b","b","n","n","r","r","c","c","p","p","p","p","p", @@ -125,6 +367,7 @@ namespace Chess.Engine /// 棋谱数组int[9,10] public static int[,] ConvertFenStrToQiPan(string fen) { + int[,] output = new int[9, 10]; int col, row; col = 0; @@ -187,14 +430,39 @@ namespace Chess.Engine { return; } + string[] strarr = _InfoStrLine.Split(" "); Depth = int.Parse(strarr[Array.IndexOf(strarr, "depth") + 1]); // 搜索深度 - Score = int.Parse(strarr[Array.IndexOf(strarr, "score") + 1]); // 分值 - int start = Array.IndexOf(strarr, "pv") + 1; // “pv”后边是着法,着法可能仅有一个,也可能是一串。 - for (int i = start; i < strarr.Length; i++) + + if (!_InfoStrLine.Contains("score")) + { + return; + } + + if (GlobalValue.EngineMode == GlobalValue.EngineTypes.pikafish) + { + //if (_InfoStrLine.Contains("seldepth")) + //新增的引擎差异处理 + //数据格式: info depth 6 seldepth 6 multipv 1 score cp 22 nodes 1446 nps 482000 hashfull 0 tbhits 0 time 3 pv h2e2 b9c7 b2a2 h9g7 h0g2 + Score = int.Parse(strarr[Array.IndexOf(strarr, "score") + 2]); // 分值 + + int start = Array.IndexOf(strarr, "pv") + 1; // “pv”后边是着法,着法可能仅有一个,也可能是一串。 + for (int i = start; i < strarr.Length; i++) + //for (int i = start;i<= start+1 && i < strarr.Length; i++) //为加快速度只显示一个后边着法 + { + UcciStrList.Add(strarr[i].Trim()); + } + } + else if (GlobalValue.EngineMode == GlobalValue.EngineTypes.eleeye) { - UcciStrList.Add(strarr[i].Trim()); + Score = int.Parse(strarr[Array.IndexOf(strarr, "score") + 1]); // 分值 + int start = Array.IndexOf(strarr, "pv") + 1; // “pv”后边是着法,着法可能仅有一个,也可能是一串。 + for (int i = start; i < strarr.Length; i++) + { + UcciStrList.Add(strarr[i].Trim()); + } } + FirstStep = GetStep(UcciStrList[0], GlobalValue.QiPan); CnStrList = UcciStrToCnStr(UcciStrList, GlobalValue.QiPan); } @@ -248,7 +516,7 @@ namespace Chess.Engine public class UcciInfoClass { private string _InfoSource; - private string InfoSource // 象棋引擎返回的多行字符串,需里进行解析,并保存到相应变量中。 + private string InfoSource // 象棋引擎返回的多行字符串,需在这里进行解析,并保存到相应变量中。 { get { return _InfoSource; } set @@ -263,34 +531,59 @@ namespace Chess.Engine } string keystr = "bestmove"; // 最佳着法 int start = _InfoSource.IndexOf(keystr); + if (start > -1) { string uccistr = InfoSource.Substring(start + keystr.Length, 5).Trim(); Bestmove = UcciStrToCnStr(uccistr, GlobalValue.QiPan, false); + BestmoveUci = uccistr; + if (start + keystr.Length + 12 + 5 < InfoSource.Length) + { + string uccistr2 = InfoSource.Substring(start + keystr.Length + 12, 5).Trim(); + Ponder = UcciStrToCnStr(uccistr2, GlobalValue.QiPan, false); + } + } - keystr = "ponder"; // 后续的最佳着法 - start = InfoSource.IndexOf(keystr); - if (start > -1) + int end = InfoSource.IndexOf("bestmove"); // 删除bestmove后面所有字符 + string[] bufArr = InfoSource[..end].Trim().Split(Environment.NewLine); // 按行分割字符串为数组 + + InfoList.Clear(); + if (GlobalValue.EngineMode == GlobalValue.EngineTypes.eleeye) { - string uccistr = InfoSource.Substring(start + keystr.Length, 5).Trim(); - Ponder = UcciStrToCnStr(uccistr, GlobalValue.QiPan, false); + foreach (string str in bufArr) + { + PvClass pvc = new() + { + InfoStrLine = str + }; + InfoList.Add(pvc); + } } - - int end = InfoSource.IndexOf("bestmove"); // 删除bestmove所在行 - string[] bufArr = InfoSource[..end].Trim().Split(Environment.NewLine); // 按行分割字符串为数组 - - foreach (string str in bufArr) + else if (GlobalValue.EngineMode == GlobalValue.EngineTypes.pikafish) { - PvClass pvc = new() + //string str = bufArr.LastOrDefault(); //为不重复记录,加快处理,只记录最后一条有效路径 + //PvClass pvc = new() + //{ + // InfoStrLine = str; + //}; + //InfoList.Add(pvc); + + foreach (string str in bufArr) { - InfoStrLine = str - }; - InfoList.Add(pvc); + PvClass pvc = new() + { + InfoStrLine = str + }; + InfoList.Add(pvc); + } + } + } } - private string Bestmove; // 最佳着法 + public static string Bestmove; // 最佳着法 + public static string BestmoveUci; // 最佳着法Uci写法 private string Ponder; // 后续的最佳着法 private List InfoList { get; set; } public UcciInfoClass() @@ -305,13 +598,32 @@ namespace Chess.Engine /// 最佳着法 public string GetBestMove(bool showarrow) { - InfoSource = CallEngine(10, 5); // 调用象棋引擎,获得下一步着法信息 + int thinkTime = Settings.Default.MoveDelayTime / 100;// Math.Min(thinkTime, 10); + int depth = Settings.Default.MoveDelayTime / 200; // Math.Min(depth, 1); + + InfoSource = CallEngine(thinkTime, depth); // 调用象棋引擎,获得下一步着法信息 + string str = ""; if (InfoList.Count > 0) { int maxscore = InfoList.Max(x => x.Score); - str = InfoList.FirstOrDefault(x => x.Score == maxscore).GetMove(); - str = $"最佳着法({maxscore}分):{System.Environment.NewLine} {str}"; + int MaxScoreIndex = 0; + // str = InfoList.FirstOrDefault(x => x.Score == maxscore).GetMove(); + if (GlobalValue.EngineMode== GlobalValue.EngineTypes.eleeye) + { + MaxScoreIndex = 0; + } + + else if (GlobalValue.EngineMode == GlobalValue.EngineTypes.pikafish) + { + MaxScoreIndex = InfoList.Count - 1; + } + //int maxscore = InfoList[MaxScoreIndex].Score; + if (InfoList[MaxScoreIndex].CnStrList.Count > 0) + { + str = InfoList[MaxScoreIndex].CnStrList[0];// InfoList.FirstOrDefault(x => x.Score == maxscore).GetMove(); + str = $"最佳着法({maxscore}分):{System.Environment.NewLine} {str}"; + } } else { @@ -358,7 +670,55 @@ namespace Chess.Engine } public CustomClass.Qipu.StepCode GetBestSetp() { - if (InfoList.Count > 0) return InfoList[0].FirstStep; + if (InfoList.Count > 0) + { + int MaxScoreIndex = 0; + + + if (GlobalValue.EngineMode == GlobalValue.EngineTypes.eleeye) + { + MaxScoreIndex = 0; //最一个就是最优解; + } + else if (GlobalValue.EngineMode == GlobalValue.EngineTypes.pikafish) + { + MaxScoreIndex = InfoList.Count - 1; //最后一个就是最优解 + } + + if (Settings.Default.AIEasyMode == true) + { + //寻找最低分数的招数 + // 初始化最小值和索引 + int minScore = int.MaxValue; + int minScoreIndex = -1; + + for (int i = 0; i < InfoList.Count; i++) + { + if (InfoList[i].Score < minScore) + { + minScore = InfoList[i].Score; + minScoreIndex = i; + } + } + MaxScoreIndex = minScoreIndex; + } + else + { + if (GlobalValue.EngineMode == GlobalValue.EngineTypes.eleeye) + { + MaxScoreIndex = 0; //最一个就是最优解; + } + else if (GlobalValue.EngineMode == GlobalValue.EngineTypes.pikafish) + { + MaxScoreIndex = InfoList.Count - 1; //最后一个就是最优解 + } + + } + //GlobalValue.CmdRecorder.Push(InfoList[MaxScoreIndex].UcciStrList[0]); //记录当前出招 + FileWriter.AppendToFile(InfoList[MaxScoreIndex].FirstStep.UcciStep); + FileWriter.AppendToFile(InfoList[MaxScoreIndex].CnStrList[0]); + return InfoList[MaxScoreIndex].FirstStep; + } + return null; } } @@ -409,6 +769,10 @@ namespace Chess.Engine int y0 = rows.IndexOf(ucciStr[1]); int x1 = cols.IndexOf(ucciStr[2]); // 目标位置 int y1 = rows.IndexOf(ucciStr[3]); + if (x0<0 || y0 < 0 || x1<0 || y1 < 0 ) + { + return ""; + } string resultstr = ""; int qizi = qipan[x0, y0]; if (qizi > -1) diff --git a/Engine/pikafish.nnue b/Engine/pikafish.nnue new file mode 100644 index 0000000000000000000000000000000000000000..34b037d761b4d8425d5c9a1d0300df0c15fdc671 Binary files /dev/null and b/Engine/pikafish.nnue differ diff --git a/GlobalValue.cs b/GlobalValue.cs index fc0b7900be9701900ff03091650ae9b688021334..427086b9f1c4b27a415646f4b7ae336fadd785c2 100644 --- a/GlobalValue.cs +++ b/GlobalValue.cs @@ -8,16 +8,23 @@ using Chess.CustomClass; using System.Windows.Media; using System.Windows.Threading; using System.ComponentModel; +using Chess.Engine; namespace Chess { internal class GlobalValue { + public enum EngineTypes {eleeye,pikafish}; public const float GRID_WIDTH = 67.5f; //棋盘格大小为 67.5*67.5 public const bool BLACKSIDE = false; // 黑方 public const bool REDSIDE = true; //红方 - public static bool _sideTag; + //public static bool IsAI_EasyMode = false; //AI 简单模式 + + public static EngineTypes EngineMode= EngineTypes.pikafish; //定义引擎的类型 + + private static bool _sideTag; + public static bool SideTag // 当前走棋方 { get { return _sideTag; } @@ -27,6 +34,7 @@ namespace Chess Settings.Default.CurrentSide = value; } } + private static bool _isGameOver; public static bool IsGameOver // 游戏结束标志 { @@ -55,7 +63,6 @@ namespace Chess public const int CANJU_DESIGN = 5; public const int CANJU_POJIE = 6; - #region // 用户界面元素 public static PathPoint[,] pathPointImage = new PathPoint[9, 10]; // 棋子可走路径的圆点标记 public static QiZi[] qiZiArray = new QiZi[32]; // 棋子数组,所有棋子均在此数组中 @@ -369,7 +376,7 @@ namespace Chess /// private static void AnimationMove(int qiZi, int x0, int y0, int x1, int y1) { - const double delayTime = 200.0; // 动画延续时间,毫秒 + double delayTime = 0;// Settings.Default.MoveDelayTime /5; // 动画延续时间,毫秒 double Grid_y0 = 0.0; #region 棋子有效位置检测 @@ -442,6 +449,7 @@ namespace Chess /// public static void Reset() { + foreach (QiZi item in qiZiArray) { item.SetInitPosition(); // 所有棋子的位置信息复位 @@ -479,11 +487,11 @@ namespace Chess /// public static void HuiQi() { + //这个涵数反复悔棋有偶发BUG,有待测试 2024-2-4 if (Qipu.QiPuList.Count < 1) { return; } - Qipu.StepCode step = Qipu.QiPuList[^1].StepData; // ^1:索引运算符,表示倒数第一个 qiZiArray[step.QiZi].Select(); // 重新计算可移动路径 qiZiArray[step.QiZi].SetPosition(step.X0, step.Y0); diff --git a/GuPuLianXiPage.xaml.cs b/GuPuLianXiPage.xaml.cs index 2a724c42be4e4dd712bee0929fe1917fc60aed5d..120f7d8f8daf88268480ff1436a74c66196bc61d 100644 --- a/GuPuLianXiPage.xaml.cs +++ b/GuPuLianXiPage.xaml.cs @@ -87,6 +87,7 @@ namespace Chess QiPanChange(false); GlobalValue.Reset(); openQiPuGrid.Visibility = Visibility.Visible; + //chkISAIEasyMode.Visibility = Visibility.Visible; ; } /// @@ -273,5 +274,7 @@ namespace Chess { openQiPuGrid.Visibility = Visibility.Visible; } + + } } diff --git a/MainWindow.xaml b/MainWindow.xaml index 9c7962eabcd0f9a0127bbe082cedd668b78dfd43..df31f3d42000988249c5392eb4c1ff9b24a02f10 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -4,7 +4,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Chess" x:Name="MainWin" mc:Ignorable="d" - Title="中国象棋 单机版 V5.0" ResizeMode="CanResize" WindowStartupLocation="CenterScreen" Closing="OnMainWindowClose" + Title="中国象棋 单机版 V5.01" ResizeMode="CanResize" WindowStartupLocation="CenterScreen" Closing="OnMainWindowClose" Icon="/picture/象128.png" SizeToContent="Manual" ScrollViewer.VerticalScrollBarVisibility="Disabled" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" WindowState="Normal" Loaded="OnLoad" @@ -26,17 +26,20 @@ - public partial class MainWindow : Window { - + public static int menuItem; public MainWindow() { @@ -30,6 +30,7 @@ namespace Chess /// private void OnMainWindowClose(object sender, System.ComponentModel.CancelEventArgs e) { + Engine.XQEngine.CloseEngine(); Settings.Default.Save(); // 保存用户更改的设置 Environment.Exit(0); // 关闭所有窗口,并释放所有资源,包括相关辅助窗口。 } @@ -51,10 +52,12 @@ namespace Chess MainMenu.Visibility = Visibility.Visible; ReturnButton.Visibility = Visibility.Hidden; menuItem = 0; + GlobalValue.EnableGameStop = true; } private void OnUnloaded(object sender, RoutedEventArgs e) { + Environment.Exit(0); } @@ -127,7 +130,7 @@ namespace Chess private void WindowSizeChanged(object sender, SizeChangedEventArgs e) { - Title = $"China Chess 单机版 V5.0 {Width} x {Height}"; + Title = $"China Chess 单机版 V5.2 {Width} x {Height}"; } /// /// 键盘输入处理 @@ -159,6 +162,8 @@ namespace Chess TestWindow tw=new TestWindow(); tw.Show(); } + + } /// /// 转换器。将文件名字符串转换为BitMapImage实例。 diff --git a/QiPanPage.xaml b/QiPanPage.xaml index 0d57675e8ec3e65570b92ae1f6c6c9e4ffc1aac1..f2339f3f327967f2b37f4cd1aa573f902b1f9f06 100644 --- a/QiPanPage.xaml +++ b/QiPanPage.xaml @@ -79,18 +79,20 @@ - +