private void MenuContinuousEval_Click(object sender, EventArgs e) { App_inGame = false; string fileName = @"G:\象棋\全局\1-23届五羊杯\第01届五羊杯象棋赛(1981)\第01局-胡荣华(红先负)柳大华.PGN"; PgnFileStruct pgn = pos.ReadPgnFile(fileName); pos.FromFEN(pgn.StartFEN); engine.FromFEN(pgn.StartFEN); engine.SearchQuiesce(-5000, 5000, 10, 0); for (int i = 1; i < pgn.MoveList.Count; i++) { MOVE step = pgn.MoveList[i]; engine.MakeMove(step); int score = -engine.SearchQuiesce(-5000, 5000, 10, 0); if (i % 2 == 1) { Console.Write("{0}. {1} ", (i + 1) / 2, score); } else { Console.WriteLine(score); } } //Write2Csv(@"G:\xqtest\eval.csv", pos.ivpc, totalMoves, 48); /* 用顶级人类选手的对局来测试评估审局函数的有效性。 * 理想情况下,双方分数应呈锯齿状交替上升,除去吃子的步骤,应该稳定渐变。 */ }
//http://blog.sina.com.cn/s/blog_5fd97aa90100vq5p.html public RepititionResult RuleTest(string filename) { Debug.Assert(filename != null); PgnFileStruct pgn = ReadPgnFile(filename); FromFEN(pgn.StartFEN); foreach (MOVE mv in pgn.MoveList) { Console.WriteLine(mv); MakeMove(mv, true); RepititionResult rep = Repitition(); switch (rep) { case RepititionResult.WIN: if (sdPlayer == 0) { Console.WriteLine("黑方负"); } else { Console.WriteLine("红方负"); } break; case RepititionResult.LOSE: if (sdPlayer == 0) { Console.WriteLine("黑方胜"); } else { Console.WriteLine("红方胜"); } break; case RepititionResult.DRAW: Console.WriteLine("不变作和"); break; default: break; } } return(RepititionResult.NONE); }
bool ReadPGN(string filename, int maxHeight) { POSITION pos = new POSITION(); PgnFileStruct pgn = pos.ReadPgnFile(filename); if (pgn.StartFEN != POSITION.cszStartFen) { Console.WriteLine("非开局或全局谱"); return(false); } int result; switch (pgn.Result) { case "0-1": result = -1; break; case "1-0": result = 1; break; case "1/2-1/2": result = 0; break; default: return(false); } pos.FromFEN(pgn.StartFEN); int height = 0; foreach (MOVE mv in pgn.MoveList) { pos.MakeMove(mv, false); ulong key = pos.Key; if (Book.TryGetValue(key, out BookEntry entry)) { switch (result) { case 1: entry.win++; Debug.Assert(entry.win < ushort.MaxValue); break; case 0: entry.draw++; Debug.Assert(entry.loss < ushort.MaxValue); break; case -1: entry.loss++; Debug.Assert(entry.draw < ushort.MaxValue); break; default: Debug.Fail("Unknown result"); break; } Book[key] = entry; } else { ulong mirror_key = pos.CalculateZobrist(true); if (Book.TryGetValue(mirror_key, out entry)) { switch (result) { case 1: entry.win++; Debug.Assert(entry.win < ushort.MaxValue); break; case 0: entry.draw++; Debug.Assert(entry.loss < ushort.MaxValue); break; case -1: entry.loss++; Debug.Assert(entry.draw < ushort.MaxValue); break; default: Debug.Fail("Unknown result"); break; } Book[mirror_key] = entry; } else { entry = new BookEntry(); switch (result) { case 1: entry.win = 1; break; case 0: entry.draw = 1; break; case -1: entry.loss = 1; break; default: Debug.Fail("Unknown result"); return(false); } Book.Add(key, entry); } } height++; if (height > maxHeight) { return(true); } } return(true); }
//暂不支持(变招)识别 public PgnFileStruct ReadPgnFile(string szFileName) { Debug.Assert(szFileName != null); PgnFileStruct PGN = new PgnFileStruct(); FromFEN(cszStartFen); PGN.StartFEN = cszStartFen; PGN.MoveList = new List <MOVE>(); PGN.CommentList = new List <string>(); using (StreamReader fp = new StreamReader(szFileName, Encoding.GetEncoding("GB2312"))) { string pattern = @"\A\[(\w+)\s""(.*)""\]\Z"; Regex reg = new Regex(pattern); Match m; string line = ""; while (fp.Peek() > -1) { line = fp.ReadLine(); m = reg.Match(line); if (m.Success) { switch (m.Groups[1].Value) { case "Format": PGN.Format = m.Groups[2].Value; break; case "Game": if (m.Groups[2].Value != "Chinese Chess") { Console.WriteLine("非中国象棋棋谱"); return(PGN); } break; case "Event": PGN.Event = m.Groups[2].Value; break; case "Date": PGN.Date = m.Groups[2].Value; break; case "Round": PGN.Round = m.Groups[2].Value; break; case "FEN": FromFEN(m.Groups[2].Value); PGN.StartFEN = m.Groups[2].Value; break; case "Result": PGN.Result = m.Groups[2].Value; break; case "Site": PGN.Site = m.Groups[2].Value; break; case "RedTeam": PGN.RedTeam = m.Groups[2].Value; break; case "BlackTeam": PGN.BlackTeam = m.Groups[2].Value; break; case "Red": PGN.Red = m.Groups[2].Value; break; case "Black": PGN.Black = m.Groups[2].Value; break; case "ECCO": PGN.ECCO = m.Groups[2].Value; break; case "Opening": PGN.Opening = m.Groups[2].Value; break; case "Variation": PGN.Variation = m.Groups[2].Value; break; case "BlackElo": PGN.BlackElo = m.Groups[2].Value; break; case "RedElo": PGN.RedElo = m.Groups[2].Value; break; default: Debug.WriteLine("Unknown label {0}", m.Groups[2].Value); break; } } else { //Now comes the move and comment list line += "\n" + fp.ReadToEnd(); } } int index; string comment = ""; //int phase = 2; //phase = 0是序号,1是move#1,2是 move#2 do { //get move list till next comment index = line.IndexOf('{'); string content; if (index < 0) { content = line; } else if (index == 0) { int index1 = line.IndexOf('}'); if (index1 > 0) {//is comment comment = line.Substring(1, index1 - 1); line = line.Substring(index1 + 1); } continue; } else { content = line.Substring(0, index); line = line.Substring(index); } string[] words = content.Split(new char[] { ' ', '\n', '\r', '.' }, StringSplitOptions.RemoveEmptyEntries); foreach (string s in words) { pattern = @"\A(\d+)\Z"; m = Regex.Match(s, pattern); if (m.Success) {//is a move number //Debug.WriteLine(m.Groups[1].Value); //if (phase != 2 && m.Groups[1].Value != "2")//第一回合如果黑方先走,只有move#2 //{ // Console.WriteLine("棋谱错误,缺少着法"); // return false; //} //phase = 0; } else if (s.Length == 4) {//is a Chinese move //Debug.WriteLine(s); MOVE mv = ParseWord(s); if (mv.pcSrc == 0) { Console.WriteLine("警告:棋谱错误!"); return(PGN); } MakeMove(mv); PGN.CommentList.Add(comment); PGN.MoveList.Add(mv); comment = null; //phase++; } else if (s.Length == 5) {// is a ICCS format move Tuple <int, int> coord = ICCS2Move(s); MOVE mv = new MOVE(coord.Item1, coord.Item2, pcSquares[coord.Item1], pcSquares[coord.Item2]); MakeMove(mv); PGN.CommentList.Add(comment); PGN.MoveList.Add(mv); comment = null; } else { PGN.CommentList.Add(comment); if (s != PGN.Result) { Debug.WriteLine(s); } goto CHECK_RESULT; } } } while (line.Length > 0 & index >= 0); } CHECK_RESULT: //Sometime the result is recorded in the last comment if (PGN.Result == "*") { string s = PGN.CommentList[PGN.CommentList.Count - 1]; if (s != null) { if (s.Contains("红胜") || s.Contains("黑负")) { PGN.Result = "1-0"; } else if (s.Contains("和")) { PGN.Result = "1/2-1/2"; } else if (s.Contains("红负") || s.Contains("黑胜")) { PGN.Result = "0-1"; } } } return(PGN); }
public void TestEval() { //int Compare(KeyValuePair<string, int> a, KeyValuePair<string, int> b) //{ // return a.Value.CompareTo(b.Value); //} string sourceDirectory = @"G:\象棋\全局\1-23届五羊杯"; IEnumerable <string> pgnFiles = Directory.EnumerateFiles(sourceDirectory, "*.pgn", SearchOption.AllDirectories); int nFile = 0; int totalMoves = 0; int totalSteps = 0; List <double> redDelta = new List <double>(); List <double> blackDelta = new List <double>(); List <double> seq = new List <double>(); foreach (string fileName in pgnFiles) { Console.WriteLine(fileName.Substring(sourceDirectory.Length + 1)); PgnFileStruct pgn = ReadPgnFile(fileName); List <MOVE> iMoveList = pgn.MoveList; nFile++; int nSteps = iMoveList.Count; totalSteps += nSteps; bool[] captures = new bool[nSteps]; FromFEN(pgn.StartFEN); ivpc = new int[nSteps, 48]; Complex_Evaluate(); List <KeyValuePair <string, int> > mv_vals = new List <KeyValuePair <string, int> >(); for (int i = 1; i < nSteps; i++) { MOVE step = iMoveList[i]; captures[i] = pcSquares[step.sqDst] > 0; if (pcSquares[step.sqDst] == 0) { mv_vals.Clear(); //List<MOVE> moves = GenerateMoves(); int bookmovevalue = 0; string bookmovekey = step.ToString(); foreach (MOVE move in GenerateMoves()) { if (move.pcDst == 0) { MovePiece(move); string key = move.ToString(); int val = Complex_Evaluate(); mv_vals.Add(new KeyValuePair <string, int>(key, val)); UndoMovePiece(move); if (key == bookmovekey) { bookmovevalue = val; } } } if (i % 2 == 0) //从小到大排序 { mv_vals.Sort(delegate(KeyValuePair <string, int> a, KeyValuePair <string, int> b) { return(a.Value.CompareTo(b.Value)); }); } else //从大到小排序 { mv_vals.Sort(delegate(KeyValuePair <string, int> a, KeyValuePair <string, int> b) { return(b.Value.CompareTo(a.Value)); }); } int index = mv_vals.IndexOf(new KeyValuePair <string, int>(bookmovekey, bookmovevalue)); seq.Add(index); //totalMoves += moves.Count; Console.WriteLine("{0}. Book move: {1} {2}", i, bookmovekey, index); foreach (var m in mv_vals) { //Console.WriteLine("{0}. {1} {2} / {3}", j++, m.Key, m.Value, moves.Count); } } MakeMove(step, true); Console.WriteLine("-------------------"); } for (int i = 1; i < nSteps; i += 2) { if (!captures[i]) { redDelta.Add(ivpc[i, 1] - ivpc[i - 1, 1]); } } for (int i = 2; i < nSteps; i += 2) { if (!captures[i]) { blackDelta.Add(ivpc[i, 1] - ivpc[i - 1, 1]); } } break; } double redMean = Statistics.Mean(redDelta); double redVar = Statistics.Variance(redDelta); Console.WriteLine("Red mean:{0}, var:{1}", redMean, redVar); double blackMean = Statistics.Mean(blackDelta); double blackVar = Statistics.Variance(blackDelta); Console.WriteLine("Black mean:{0}, var:{1}", blackMean, blackVar); Console.WriteLine("Score: red{0}, black{1}, average{2}", redVar / redMean, blackVar / blackMean, (redVar + blackVar) / (redMean - blackMean)); Console.WriteLine("Move average sequence: {0} of {1}", Statistics.Mean(seq), totalMoves / totalSteps); }