private void CompareNodes(ChanceTreeNode *pNode0, ChanceTreeNode *pNode1) { double probab0 = pNode0->Probab; double probab1 = pNode1->Probab; double probabDiff = Math.Abs(probab0 - probab1); SumProbabDiff += probabDiff; MaxProbabDiff = Math.Max(MaxProbabDiff, probabDiff); double relProbabDiff = (probab0 + probab1) != 0 ? probabDiff / (probab0 + probab1) / 2 : 0; SumRelProbabDiff += relProbabDiff; MaxRelProbabDiff = Math.Max(MaxRelProbabDiff, relProbabDiff); UInt16[] activePlayers; activePlayers = ActivePlayers.Get(_playersCount, 2, _playersCount); double[] potShares0 = new double[_playersCount]; double[] potShares1 = new double[_playersCount]; foreach (UInt16 ap in activePlayers) { pNode0->GetPotShare(ap, potShares0); pNode1->GetPotShare(ap, potShares1); for (int p = 0; p < _playersCount; ++p) { double potShareDiff = Math.Abs(potShares0[p] - potShares1[p]); SumPotShareDiff[p] += potShareDiff; MaxPotShareDiff[p] = Math.Max(MaxPotShareDiff[p], potShareDiff); } } }
public void Test_GetActivePlayers() { UInt16[] ap; // Total: 0 ap = ActivePlayers.Get(0, 0, 0); Assert.AreEqual(1, ap.Length); Array.Sort(ap); Assert.AreEqual(0, ap[0]); // Total: 1 ap = ActivePlayers.Get(1, 0, 0); Assert.AreEqual(1, ap.Length); Array.Sort(ap); Assert.AreEqual(0, ap[0]); ap = ActivePlayers.Get(1, 0, 1); Assert.AreEqual(2, ap.Length); Array.Sort(ap); Assert.AreEqual(0, ap[0]); Assert.AreEqual(1, ap[1]); // Total: 2 ap = ActivePlayers.Get(2, 0, 0); Assert.AreEqual(1, ap.Length); Array.Sort(ap); Assert.AreEqual(0, ap[0]); ap = ActivePlayers.Get(2, 0, 1); Assert.AreEqual(3, ap.Length); Array.Sort(ap); Assert.AreEqual(0, ap[0]); Assert.AreEqual(1, ap[1]); Assert.AreEqual(2, ap[2]); ap = ActivePlayers.Get(2, 1, 1); Assert.AreEqual(2, ap.Length); Array.Sort(ap); Assert.AreEqual(1, ap[0]); Assert.AreEqual(2, ap[1]); ap = ActivePlayers.Get(2, 0, 2); Assert.AreEqual(4, ap.Length); Array.Sort(ap); Assert.AreEqual(0, ap[0]); Assert.AreEqual(1, ap[1]); Assert.AreEqual(2, ap[2]); Assert.AreEqual(3, ap[3]); // Total: 3 ap = ActivePlayers.Get(3, 2, 2); Assert.AreEqual(3, ap.Length); Array.Sort(ap); Assert.AreEqual(3, ap[0]); Assert.AreEqual(5, ap[1]); Assert.AreEqual(6, ap[2]); ap = ActivePlayers.Get(3, 3, 3); Assert.AreEqual(1, ap.Length); Array.Sort(ap); Assert.AreEqual(7, ap[0]); }
public void Test_Convert() { GameDefinition gd = XmlSerializerExt.Deserialize <GameDefinition>( Props.Global.Expand("${bds.DataDir}ai.pkr.metastrategy/leduc-he.gamedef.xml")); string testDir = UTHelper.GetTestResourceDir(Assembly.GetExecutingAssembly()); ChanceTree ct1 = CreateChanceTreeByGameDef.Create(gd); // DumpChanceTree.ToTxt(ct1, Console.Out); MemoryStream ms = new MemoryStream(); using (TextWriter tw = new StreamWriter(ms)) { DumpChanceTree.ToTxt(ct1, tw); } byte[] buf = ms.ToArray(); ms = new MemoryStream(buf); ChanceTree ct2; using (TextReader tr = new StreamReader(ms)) { ct2 = DumpChanceTree.FromTxt(tr); } Assert.AreEqual(ct1.Version, ct2.Version); Assert.AreEqual(ct1.NodesCount, ct2.NodesCount); int roundsCount = ct1.CalculateRoundsCount(); double[] potShare1 = new double[ct1.PlayersCount]; double[] potShare2 = new double[ct1.PlayersCount]; for (Int64 n = 0; n < ct2.NodesCount; ++n) { Assert.AreEqual(ct1.GetDepth(n), ct2.GetDepth(n)); Assert.AreEqual(ct1.Nodes[n].Position, ct2.Nodes[n].Position); Assert.AreEqual(ct1.Nodes[n].Card, ct2.Nodes[n].Card); Assert.AreEqual(ct1.Nodes[n].Probab, ct2.Nodes[n].Probab); if (ct1.GetDepth(n) == ct1.PlayersCount * roundsCount) { UInt16 [] activePlayerMasks = ActivePlayers.Get(ct1.PlayersCount, 2, ct1.PlayersCount); foreach (UInt16 ap in activePlayerMasks) { ct1.Nodes[n].GetPotShare(ap, potShare1); ct2.Nodes[n].GetPotShare(ap, potShare2); Assert.AreEqual(potShare1, potShare2); } } } }
public static void ToTxt(ChanceTree t, TextWriter w) { int roundsCount = t.CalculateRoundsCount(); if (t.PlayersCount != 2) { throw new ApplicationException("Only 2 players are supported"); } w.WriteLine("SeralizationFormat {0}", SERIALIZATION_FORMAT); XmlWriterSettings s = new XmlWriterSettings { Indent = false, NewLineChars = "" }; w.Write("Version "); XmlSerializerExt.Serialize(t.Version, w, s); w.WriteLine(); w.WriteLine("NodesCount {0}", t.NodesCount); w.WriteLine("RoundsCount {0}", roundsCount); double [] potShare = new double[t.PlayersCount]; for (Int64 n = 0; n < t.NodesCount; ++n) { w.WriteLine("Id {0}", n); byte depth = t.GetDepth(n); w.WriteLine("D {0}", depth); w.WriteLine("P {0}", t.Nodes[n].Position); w.WriteLine("C {0}", t.Nodes[n].Card); w.WriteLine("Pr {0}", TextDumpHelper.DoubleToBinString(t.Nodes[n].Probab)); if (depth == roundsCount * t.PlayersCount) { UInt16 [] activePlayerMasks = ActivePlayers.Get(t.PlayersCount, 2, t.PlayersCount); foreach (UInt16 ap in activePlayerMasks) { t.Nodes[n].GetPotShare(ap, potShare); w.Write("Ps {0:X}", ap); foreach (double ps in potShare) { w.Write(" {0}", TextDumpHelper.DoubleToBinString(ps)); } w.WriteLine(); } } } }
public void Test_Kuhn() { GameDefinition gd = XmlSerializerExt.Deserialize <GameDefinition>( Props.Global.Expand("${bds.DataDir}ai.pkr.metastrategy/kuhn.gamedef.xml")); IChanceAbstraction[] abstractions = new IChanceAbstraction [] { new KuhnChanceAbstraction(), new KuhnChanceAbstraction() }; ChanceTree ct = CreateChanceTreeByGameDef.Create(gd); ChanceTree act = CreateChanceTreeByAbstraction.CreateS(gd, abstractions); VerifyChanceTree.VerifyS(act); VisChanceTree.Show(act, Path.Combine(_outDir, gd.Name + "-abct.gv")); UInt16[] activePlayersOne = ActivePlayers.Get(gd.MinPlayers, 1, 1); UInt16[] activePlayersAll = ActivePlayers.Get(gd.MinPlayers, 1, gd.MinPlayers); int maxDepth = gd.RoundsCount * gd.MinPlayers; Assert.AreEqual(act.PlayersCount, gd.MinPlayers); Assert.AreEqual(ct.NodesCount, act.NodesCount); double[] expPotShares = new double[gd.MinPlayers]; double[] actPotShares = new double[gd.MinPlayers]; for (int i = 0; i < ct.NodesCount; ++i) { Assert.AreEqual(ct.Nodes[i].Position, act.Nodes[i].Position); Assert.AreEqual(ct.Nodes[i].Card, act.Nodes[i].Card); // Kuhn abstraction has the same card Assert.AreEqual(ct.Nodes[i].Probab, act.Nodes[i].Probab); if (i == 0) { continue; } UInt16[] activePlayers = ct.GetDepth(i) == maxDepth ? activePlayersAll : activePlayersOne; foreach (UInt16 ap in activePlayers) { ct.Nodes[i].GetPotShare(ap, expPotShares); act.Nodes[i].GetPotShare(ap, actPotShares); Assert.AreEqual(expPotShares, actPotShares, String.Format("Node: {0}, ap: {1}", i, ap)); } } }
public static ChanceTree FromTxt(TextReader r) { int ln = 0; int serializationFormat = int.Parse(TextDumpHelper.ReadTag(r, ref ln, "SeralizationFormat")); if (serializationFormat > SERIALIZATION_FORMAT) { throw new ApplicationException(String.Format("Line {0}: serialization format {1} is not supported by this version, max supported {2}", ln, serializationFormat, SERIALIZATION_FORMAT)); } string value; value = TextDumpHelper.ReadTag(r, ref ln, "Version"); StringReader sr = new StringReader(value); BdsVersion v; XmlSerializerExt.Deserialize(out v, sr); Int64 nodesCount = Int64.Parse(TextDumpHelper.ReadTag(r, ref ln, "NodesCount")); int roundsCount = int.Parse(TextDumpHelper.ReadTag(r, ref ln, "RoundsCount")); ChanceTree t = new ChanceTree(nodesCount); t.SetNodesMemory(0); // Clear memory to ensure zeros at unused fields t.Version.CopyFrom(v); char [] separators = new char[] { ' ', '\t' }; for (Int64 n = 0; n < nodesCount; ++n) { Int64 id = Int64.Parse(TextDumpHelper.ReadTag(r, ref ln, "Id")); if (id != n) { throw new ApplicationException(String.Format("Line {0}: wrong node id '{1}', expected '{2}'", ln, id, n)); } byte depth = byte.Parse(TextDumpHelper.ReadTag(r, ref ln, "D")); t.SetDepth(n, depth); t.Nodes[n].Position = int.Parse(TextDumpHelper.ReadTag(r, ref ln, "P")); t.Nodes[n].Card = int.Parse(TextDumpHelper.ReadTag(r, ref ln, "C")); t.Nodes[n].Probab = TextDumpHelper.BinStringToDouble(TextDumpHelper.ReadTag(r, ref ln, "Pr")); if (depth == t.PlayersCount * roundsCount) { double[] potShare = new double[t.PlayersCount]; UInt16[] activePlayerMasks = ActivePlayers.Get(t.PlayersCount, 2, t.PlayersCount); for (int a = 0; a < activePlayerMasks.Length; ++a) { value = TextDumpHelper.ReadTag(r, ref ln, "Ps"); string[] parts = value.Split(separators, StringSplitOptions.RemoveEmptyEntries); if (parts.Length != t.PlayersCount + 1) { throw new ApplicationException( String.Format("Line {0}: wrong number of values: '{1}', expected '{2}'", ln, parts.Length, t.PlayersCount + 1)); } UInt16 activePlayers = UInt16.Parse(parts[0], NumberStyles.AllowHexSpecifier); for (int i = 1; i < parts.Length; ++i) { potShare[i - 1] = TextDumpHelper.BinStringToDouble(parts[i]); } t.Nodes[n].SetPotShare(activePlayers, potShare); } } } return(t); }
private void OnNodeBegin(ChanceTree tree, AnalyzeContext[] stack, int depth) { AnalyzeContext context = stack[depth]; Int64 n = context.NodeIdx; int card = tree.Nodes[n].Card; if (depth > 0) { int round = (depth - 1) / _playersCount; int pos = tree.Nodes[n].Position; if (_seenCards[round][pos].Length <= card) { Array.Resize(ref _seenCards[round][pos], card + 1); } _seenCards[round][pos][card] = true; } bool isLeaf = tree.GetDepth(n) == _maxDepth; if (!isLeaf) { return; } LeavesCount++; bool isZeroNode = false; double probab = tree.Nodes[n].Probab; if (probab == 0) { ZeroChanceLeavesCount++; isZeroNode = true; } UInt16[] activePlayers = ActivePlayers.Get(_playersCount, 2, _playersCount); double[] potShares = new double[_playersCount]; double totalPotShare = 0; foreach (UInt16 ap in activePlayers) { tree.Nodes[n].GetPotShare(ap, potShares); for (int p = 0; p < _playersCount; ++p) { SumPotShares[p] += potShares[p]; totalPotShare += potShares[p]; } } if (probab > 0 && totalPotShare == 0) { ZeroPotSharesCount++; isZeroNode = true; } if (isZeroNode && _zeroNodesLog != null) { _zeroNodesLog.Write("Node: {0,10} probab: {1:0.0000}, total pot share: {2:0.0000} ", n, probab, totalPotShare); for (int i = 1; i <= depth; ++i) { _zeroNodesLog.Write("{0} ", tree.Nodes[stack[i].NodeIdx].ToStrategicString(null)); } _zeroNodesLog.WriteLine(); } }