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 @@
-
-
+
+
+
-
-
+
+
+
+
@@ -50,6 +53,6 @@
-
+
diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs
index 1ffff961ef224609ea64222aa882b4148159460e..3d579ba98e37aa10a18a54e993508afccefb5163 100644
--- a/MainWindow.xaml.cs
+++ b/MainWindow.xaml.cs
@@ -16,7 +16,7 @@ namespace Chess
///
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 @@
-
+
-
+
+
-
+
-
+
+
@@ -107,7 +109,7 @@
-
+
diff --git a/QiPanPage.xaml.cs b/QiPanPage.xaml.cs
index f372f96ed018887433f403ef1daed1dc020b4c52..7f57386f484c5cb6577292c475fca2233276438e 100644
--- a/QiPanPage.xaml.cs
+++ b/QiPanPage.xaml.cs
@@ -117,9 +117,12 @@ namespace Chess
{
case 1: // 人机对战
this.PersonVsPC.Visibility = Visibility.Visible;
+ this.chkAIEasyMode.IsChecked = Settings.Default.AIEasyMode; //默认简单模式
break;
case 2: // 电脑对战
this.PCVsPc.Visibility = Visibility.Visible;
+
+ StopAutoMoveCanJu(sender, e); //停止自动走
break;
case 3: // 自由打谱
this.FreeDaPu.Visibility = Visibility.Visible;
@@ -135,6 +138,7 @@ namespace Chess
{
GlobalValue.qiZiArray[i].SetDied();
}
+ Chess.Engine.XQEngine.InitEngine();
string fen = CanJuData.Rows[CanJuIndex]["FENstring"].ToString();
GlobalValue.QiPan = Engine.XQEngine.ConvertFenStrToQiPan(fen);
for (int i = 0; i <= 8; i++)
@@ -165,6 +169,8 @@ namespace Chess
private void ResetBtnClick(object sender, RoutedEventArgs e)
{
GlobalValue.Reset();
+ CanJuIndex = 0;
+ GlobalValue.BestMoveInfoText = Engine.XQEngine.UcciInfo.GetBestMove(false); // 调用象棋引擎,得到下一步推荐着法
}
///
@@ -267,6 +273,7 @@ namespace Chess
///
private void HuiQiButton(object sender, RoutedEventArgs e)
{
+ GlobalValue.IsGameOver = false;
GlobalValue.HuiQi();
if (MainWindow.menuItem == GlobalValue.PERSON_PC || MainWindow.menuItem == GlobalValue.CANJU_POJIE)
{
@@ -390,7 +397,16 @@ namespace Chess
///
private void ReStartCanJu(object sender, RoutedEventArgs e)
{
+ Chess.Engine.XQEngine.InitEngine();
string fen = CanJuData.Rows[CanJuIndex]["FENstring"].ToString();
+ fen = "1rbakab1r/9/1cn3nc1/pR2p1p1p/2p6/6P2/P1P1P3P/2N1C2C1/9/2BAKABNR"; //b 车八进六
+ //fen = "1rbakab1r/9/c1n3nc1/pR2p1p1p/2p6/6P2/P1P1P3P/2N1C2C1/9/2BAKABNR"; //w 炮2平1
+ //fen = "1rbakab1r/9/c1n3nc1/p1R1p1p1p/2p6/6P2/P1P1P3P/2N1C2C1/9/2BAKABNR"; //b 车八平七
+ //fen = "1rbakab1r/2c6/2n3nc1/p1R1p1p1p/2p6/6P2/P1P1P3P/2N1C2C1/9/2BAKABNR";//w 炮1退1 //这一步取值错了,应该红方走
+ //fen = "1rbakab1r/c8/2n3nc1/p1R1p1p1p/2p6/6P2/P1P1P3P/2N1C2C1/9/2BAKABNR"; //b 炮1平3
+
+
+
GlobalValue.QiPan = Engine.XQEngine.ConvertFenStrToQiPan(fen);
for (int i = 0; i < 32; i++)
{
@@ -463,6 +479,7 @@ namespace Chess
if (step != null) step.LunchStep(); else break;
GlobalValue.Delay(Settings.Default.MoveDelayTime);
}
+
GlobalValue.EnableGameStop = true;
AutoMoveCanJuQiZi.IsEnabled = true;
StopAutoMove.IsEnabled = false;
@@ -491,5 +508,12 @@ namespace Chess
PCVsPcStopAutoMove.IsEnabled = false;
}
+ private void chkEchoHelpStep_Click(object sender, RoutedEventArgs e)
+ {
+ if (!(bool)chkEchoHelpStep.IsChecked)
+ GlobalValue.arrows.HideAllPath(); // 隐藏提示箭头
+ else
+ GlobalValue.arrows.ShowAllPath();
+ }
}
}
diff --git a/README.md b/README.md
index 41790ecee966dcebf849a2a18cefbeeaa935af40..d5cb3951398dfcd49f209c3993545a70205dc994 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,11 @@
喜欢象棋,也喜欢编程,所以,有了这个象棋软件。
软件设计上,借鉴了国内知名象棋软件通行的设计思想,具有友好的操作界面,符合大众使用习惯。
+#### 5.2新增功能:
+1.新增了皮卡鱼引擎的使用!算力提升!
+2.重构了引擎使用方式,大大加快了运行速度!
+3.增加了更多的设置功能,比如红黑棋引擎自定义,算力和速度相关等。
+
#### 主要功能如下:
1. 人机对战,测试自己的象棋水平。
2. 电脑对战,观看电脑控制红黑双方棋子如何攻杀。
@@ -12,6 +17,7 @@
5. 残局破解,测试残局能力。系统自带30个残局,有视频破解教程。
6. 残局设计,可不断收集、扩展残局库。
+
[](https://gitee.com/cygsd/Chess/raw/Chess/ReadmePic/%E4%B8%BB%E8%8F%9C%E5%8D%95.png)
[](https://gitee.com/cygsd/Chess/raw/Chess/ReadmePic/%E4%BA%BA%E6%9C%BA%E5%AF%B9%E6%88%98.png)
[](https://gitee.com/cygsd/Chess/raw/Chess/ReadmePic/%E6%A3%8B%E8%B0%B1%E6%95%B0%E6%8D%AE%E5%BA%93.png)
@@ -36,6 +42,7 @@
* 窗口背景可任意更换。
* 具备界面主题选择功能,可选择个人喜好的主题。
* 自动保存用户设置,下次打开软件时,自动使用上次保存的设置。
+* 增加了简单模式切换。
#### 正在开发的功能,以及开发目标
@@ -109,10 +116,10 @@ for (int i = 0; i < 9; i++)
#### 参与贡献
-1. Fork 本仓库:暂无
-2. 新建 Feat_xxx 分支:暂无
-3. 提交代码:暂无
-4. 新建 Pull Request:暂无
+1. Fork 本仓库:superitman2023
+2. 新建 Feat_xxx 分支:superitman2023
+3. 提交代码:superitman2023
+4. 新建 Pull Request:superitman2023
#### 参考资料
@@ -180,3 +187,7 @@ for (int i = 0; i < 9; i++)
#### 特技
1. 感谢Gitee!
+
+
+
+
diff --git a/Settings.Designer.cs b/Settings.Designer.cs
index 00945f00f46699f6871d9f49dd80b75963a35473..286af6b88af19a36263a11b907ca2ab6184d4ede 100644
--- a/Settings.Designer.cs
+++ b/Settings.Designer.cs
@@ -12,7 +12,7 @@ namespace Chess {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.3.0.0")]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.7.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@@ -166,5 +166,53 @@ namespace Chess {
this["CanJuIndex"] = value;
}
}
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("False")]
+ public bool AIEasyMode {
+ get {
+ return ((bool)(this["AIEasyMode"]));
+ }
+ set {
+ this["AIEasyMode"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("0")]
+ public int PCBlackAI {
+ get {
+ return ((int)(this["PCBlackAI"]));
+ }
+ set {
+ this["PCBlackAI"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("1")]
+ public int PCRedAI {
+ get {
+ return ((int)(this["PCRedAI"]));
+ }
+ set {
+ this["PCRedAI"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("False")]
+ public bool WriteDebug {
+ get {
+ return ((bool)(this["WriteDebug"]));
+ }
+ set {
+ this["WriteDebug"] = value;
+ }
+ }
}
}
diff --git a/Settings.settings b/Settings.settings
index a1a6cba6b71f220ae25a34d53ea46e98abcb0684..41f4066d6e1e14efa7a3cffe89ba580d9e452579 100644
--- a/Settings.settings
+++ b/Settings.settings
@@ -35,5 +35,17 @@
0
+
+ False
+
+
+ 0
+
+
+ 1
+
+
+ False
+
\ No newline at end of file
diff --git a/SubWindow/SystemSetting.xaml b/SubWindow/SystemSetting.xaml
index 98ead60f92441d61039413dee998d248df1f0b67..e1767ae22ac2fd5b713b50f0a2528b66840c26ab 100644
--- a/SubWindow/SystemSetting.xaml
+++ b/SubWindow/SystemSetting.xaml
@@ -6,30 +6,49 @@
xmlns:local="clr-namespace:Chess.SubWindow"
xmlns:Chess="clr-namespace:Chess" xmlns:CustomClass="clr-namespace:Chess.CustomClass"
mc:Ignorable="d"
- Title="设置" Height="500" Width="630" WindowStartupLocation="CenterScreen" ResizeMode="NoResize" Loaded="OnWindowLoaded" Unloaded="OnWindowUnloaded">
+ Title="设置" Height="550" Width="630" WindowStartupLocation="CenterScreen" ResizeMode="NoResize" Loaded="OnWindowLoaded" Unloaded="OnWindowUnloaded">
-
+
+
+
+
+
-
+
-
-
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -44,14 +63,17 @@
+
+
+
-
+
+
-
+
-
diff --git a/SubWindow/SystemSetting.xaml.cs b/SubWindow/SystemSetting.xaml.cs
index 36f1c8c8072aa252abf43e750ff183243037efc7..241617764039df4c3be732a5b504d799154cf072 100644
--- a/SubWindow/SystemSetting.xaml.cs
+++ b/SubWindow/SystemSetting.xaml.cs
@@ -94,5 +94,7 @@ namespace Chess.SubWindow
SystemColor systemColor = new SystemColor();
systemColor.Show();
}
+
+
}
}