void PrepareChanceIndex_OnNodeBegin(ChanceTree tree, PrepareChanceIndexContext[] stack, int depth) { PrepareChanceIndexContext context = stack[depth]; Int64 n = context.NodeIdx; int round = (depth - 1) / _playersCount; if (depth > 0) { stack[depth - 1].ChanceIdx.CopyTo(context.ChanceIdx, 0); int curPlayer = tree.Nodes[n].Position; context.ChanceIdx[curPlayer] += CalculateChanceOffset(round, curPlayer) * tree.Nodes[n].Card; int oppChanceIdx = 0; int oppChanceIdxOffset = 1; for (int p = 0; p < _playersCount; ++p) { if (p == HeroPosition) { continue; } oppChanceIdx += oppChanceIdxOffset * context.ChanceIdx[p]; oppChanceIdxOffset *= _chanceIndexSizes[p][round]; } if (curPlayer == _playersCount - 1) { // All players got cards in this round - store the node index. _chanceTreeNodes[round][context.ChanceIdx[HeroPosition]][oppChanceIdx] = (int)n; } } }
void OnNodeEnd(ChanceTree tree, Context[] stack, int depth) { Context context = stack[depth]; Int64 n = context.NodeIdx; if (context.IsLeaf) { // Do for 2 players now UInt32[] ranks = new UInt32[_gd.MinPlayers]; double[] inpot = new double[_gd.MinPlayers]; double[] expResult = new double[_gd.MinPlayers]; int[][] hands = new int[_gd.MinPlayers][]; double inPotOfEachPlayer = 1.0 / _gd.MinPlayers; for (int p = 0; p < _gd.MinPlayers; ++p) { inpot[p] = inPotOfEachPlayer; hands[p] = context.Hands[p].ToArray(); } _gd.GameRules.Showdown(_gd, hands, ranks); Showdown.CalcualteHi(inpot, ranks, expResult, 0); double [] potShare = new double[_gd.MinPlayers]; tree.Nodes[n].GetPotShare(0x3, potShare); for (int p = 0; p < _gd.MinPlayers; ++p) { double actualResult = potShare[p] - inPotOfEachPlayer; Assert.AreEqual(expResult[p], actualResult); } _verifyLeaf(tree, context); } }
static int Main(string[] args) { if (!Parser.ParseArgumentsWithUsage(args, _cmdLine)) { return(1); } if (_cmdLine.DebuggerLaunch) { Debugger.Launch(); } if (_cmdLine.ChanceTrees.Length != 2) { Console.WriteLine("Can compare 2 chance trees, but was specified {0}", _cmdLine.ChanceTrees.Length); return(1); } ChanceTree[] chanceTrees = new ChanceTree[2]; for (int i = 0; i < 2; ++i) { chanceTrees[i] = ChanceTree.Read <ChanceTree>(_cmdLine.ChanceTrees[i]); } CompareChanceTrees cmp = new CompareChanceTrees { AllowDifferentStructure = _cmdLine.AllowDifferentStructure, IsVerbose = true }; cmp.Compare(chanceTrees[0], chanceTrees[1]); return(0); }
public void Test_CreateCt() { int oppCount = 2; var pockets = PocketHelper.GetAllPockets(); //var pockets = new HePocketKind[] { HePocketKind._AA, HePocketKind._76s, HePocketKind._72o }; var pocketDist = PocketHelper.GetProbabDistr(pockets); double[,] ptPeMax = MultiplayerPocketProbability.ComputePreferenceMatrixPeMax(pockets); string xmlAt = Props.Global.Expand("${bds.DataDir}ai.pkr.holdem.learn/nlpf-1.xml"); ActionTree at = XmlToActionTree.Convert(xmlAt); string[] actionLabels = CreateActionLabels(at, 0); Dictionary <string, int> actionLabelToId = new Dictionary <string, int>(); for (int i = 0; i < actionLabels.Length; ++i) { actionLabelToId.Add(actionLabels[i], i); } double[] oppDist = MultiplayerPocketProbability.Compute(oppCount, pocketDist, ptPeMax); ChanceTree ct = PreflopStrategy.CreateCt(pockets, oppDist); //GameDefinition gd = XmlSerializerExt.Deserialize<GameDefinition>(Props.Global.Expand("${bds.DataDir}ai.pkr.metastrategy/${0}", "kuhn.gamedef.xml")); //at = CreateActionTreeByGameDef.Create(gd); //ct = CreateChanceTreeByGameDef.Create(gd); VisChanceTree.Show(ct, Path.Combine(_outDir, "ct.gv")); VisActionTree.Show(at, Path.Combine(_outDir, "at.gv")); StrategyTree[] st = SolveAndVerifyVerifySolution(at, ct, 0.001, false); double[,] fs = FlattenStrategy(st[0], 0, pockets.Length, actionLabelToId); Console.WriteLine("Result for opponent count: {0}", oppCount); Console.Write("{0,4}", oppCount); foreach (string al in actionLabels) { Console.Write("{0,20}", al); } Console.WriteLine(); int raiseCount = 0; for (int c = 0; c < pockets.Length; ++c) { Console.Write("{0,4}", HePocket.KindToString(pockets[c])); for (int j = 0; j < actionLabels.Length; ++j) { Console.Write("{0,20}", Math.Round(fs[c, j] * 100, 0)); } if (fs[c, actionLabels.Length - 1] > 0.9) { raiseCount += HePocket.KindToRange(pockets[c]).Length; } Console.WriteLine(); } Console.WriteLine("Raise count: {0}", raiseCount); }
public static ChanceTree Create(GameDefinition gd) { // First pass - count nodes. GlobalContext gc = new GlobalContext { GameDef = gd }; GameContext root = new GameContext { GameState = new GameState(gd), Global = gc }; ProcessGameContext(root); // Create the tree. int nodeCount = root.ChildCount + 1; ChanceTree ct = new ChanceTree(nodeCount); // Clear memory to ensure stable values in unused fields. ct.SetNodesMemory(0); // Second pass - initialize nodes. gc.Tree = ct; gc.NodeId = 0; gc.TotalCombCountOfLeaves = root.CombCountOfLeaves; root.CombCountOfLeaves = 0; ProcessGameContext(root); ct.Version.Description = String.Format("Chance tree (gamedef: {0})", gd.Name); return(ct); }
static int Main(string[] args) { if (!Parser.ParseArgumentsWithUsage(args, _cmdLine)) { return(1); } if (_cmdLine.DebuggerLaunch) { Debugger.Launch(); } CtMcGen.Tree input = new CtMcGen.Tree(); input.Read(_cmdLine.Input); long leavesCount = input.CalculateLeavesCount(); Console.WriteLine("Input file: leaves: {0:#,#}, samples: {1:#,#}, av. samples: {2:#,#}", leavesCount, input.SamplesCount, input.SamplesCount / (ulong)leavesCount); ChanceTree ct = input.ConvertToChanceTree(); ct.Write(_cmdLine.Output); return(0); }
public void Test_ReadWrite() { IChanceAbstraction[] chanceAbstractions = new IChanceAbstraction[] { new LeducHeChanceAbstraction(LeducHeChanceAbstraction.FractionalResult), new LeducHeChanceAbstraction(LeducHeChanceAbstraction.FractionalResult) }; CtMcGen.Tree tree1 = CtMcGen.Generate(_leducHeGd, chanceAbstractions, false, 10000, (int)DateTime.Now.Ticks, null); ChanceTree ct1 = tree1.ConvertToChanceTree(); string fileName = Path.Combine(_outDir, "ctmcgen-tree.dat"); tree1.Write(fileName); CtMcGen.Tree tree2 = new CtMcGen.Tree(); tree2.Read(fileName); // Compare public data Assert.AreEqual(tree1.CalculateLeavesCount(), tree2.CalculateLeavesCount()); Assert.AreEqual(tree1.SamplesCount, tree2.SamplesCount); Assert.AreEqual(tree1.Version, tree2.Version); ChanceTree ct2 = tree2.ConvertToChanceTree(); // Compare two chance trees, they must be exactly the same. CompareChanceTrees cmp = new CompareChanceTrees(); cmp.Compare(ct1, ct2); Assert.AreEqual(0, cmp.SumProbabDiff); for (int p = 0; p < chanceAbstractions.Length; ++p) { Assert.AreEqual(0, cmp.SumPotShareDiff[p]); } }
static int Main(string[] args) { if (!Parser.ParseArgumentsWithUsage(args, _cmdLine)) { return(1); } if (_cmdLine.DebuggerLaunch) { Debugger.Launch(); } ChanceTree ct = ChanceTree.Read <ChanceTree>(_cmdLine.ChanceTree); if (_cmdLine.Verify) { Console.Write("Verifying tree ..."); VerifyChanceTree.VerifyS(ct); Console.WriteLine(" OK"); } AnalyzeChanceTree.AnalyzeS(ct); return(0); }
public ChanceTree Extract(ChanceTree ct, int position) { if (position >= ct.PlayersCount) { throw new ArgumentOutOfRangeException( string.Format("Position {0} is out of range (players count: {1})", position, ct.PlayersCount)); } _position = position; WalkUFTreePP <ChanceTree, Context> wt = new WalkUFTreePP <ChanceTree, Context>(); wt.OnNodeBegin = OnNodeBegin; _nodeCount = 0; _tempRoot = new TempNode { Card = -1, Probab = 1 }; wt.Walk(ct); ChanceTree newTree = new ChanceTree(_nodeCount + 1); // Reset memory to clear results. newTree.SetNodesMemory(0); _nodeCount = 0; CopyFromTemp(newTree, _tempRoot, 0); // Overwrite root position newTree.Nodes[0].Position = 1; newTree.Version.Description = String.Format("Player {0} chance tree from {1}", position, ct.Version.Description); return(newTree); }
/// <summary> /// Solves the game by fictitious play and verifies the solution. /// </summary> /// <param name="snapshotAfter">Number of iterations to make an intermediate snapshot after. -1 for no intermediate snapshot.</param> /// <param name="configureSolver"></param> private StrategyTree[] SolveAndVerifyVerifySolution(ActionTree at, ChanceTree ct, double epsilon, bool useLp) { if (useLp) { double[] gv; StrategyTree[] st = EqLp.Solve(at, ct, out gv); VisStrategyTree.Show(st[0], Path.Combine(_outDir, "st-0.gv")); VisStrategyTree.Show(st[1], Path.Combine(_outDir, "st-1.gv")); Console.WriteLine("LP gv: {0}, {1}", gv[0], gv[1]); } FictPlayHelper fp = new FictPlayHelper { Epsilon = epsilon, VisualizeTrees = true, BaseDir = Path.Combine(_outDir, "fp") }; StrategyTree[] eqStrategies = fp.Solve(at, ct); string error; // Verify consistency of strategies for (int p = 0; p < 2; ++p) { Assert.IsTrue(VerifyAbsStrategy.Verify(eqStrategies[p], p, 1e-7, out error), string.Format("Pos {0}: {1}", p, error)); } // Run VerifyEq on the computed strategies. Assert.IsTrue(VerifyEq.Verify(at, ct, eqStrategies, 3 * epsilon, out error), error); return(eqStrategies); }
void OnNodeBegin(ChanceTree tree, Context[] stack, int depth) { Context context = stack[depth]; Int64 n = context.NodeIdx; if (depth == 0) { stack[depth].CurTempNode = _tempRoot; } else { stack[depth].CurTempNode = stack[depth - 1].CurTempNode; } if (tree.Nodes[n].Position == _position) { int card = tree.Nodes[n].Card; TempNode childTempNode; if (!stack[depth].CurTempNode.Children.TryGetValue(card, out childTempNode)) { childTempNode = new TempNode { Card = card }; stack[depth].CurTempNode.Children.Add(card, childTempNode); _nodeCount++; } childTempNode.Probab += tree.Nodes[n].Probab; stack[depth].CurTempNode = childTempNode; } }
public StrategyTree Create(ChanceTree playerChanceTree, ActionTree actionTree) { Creator c = new Creator { ActionTree = actionTree, PlayerChanceTree = playerChanceTree }; // Start from 1 because the root is skipped. c.NodeCount = 1; c.Walk(); c.StrategyTree = new StrategyTree(c.NodeCount); c.NodeCount = 1; c.Walk(); // Set root c.StrategyTree.SetDepth(0, 0); c.StrategyTree.Nodes[0].IsDealerAction = false; c.StrategyTree.Nodes[0].Position = actionTree.Nodes[0].Position; c.StrategyTree.Nodes[0].Amount = 0; c.StrategyTree.Nodes[0].Probab = 0; c.StrategyTree.Version.Description = String.Format("Strategy tree from {0}, {1}", actionTree.Version.Description, playerChanceTree.Version.Description); return(c.StrategyTree); }
void OnNodeBegin(ChanceTree tree, Context[] stack, int depth) { Context context = stack[depth]; Int64 n = context.NodeIdx; context.IsLeaf = true; context.Hands = new List <int> [_gd.MinPlayers]; if (depth == 0) { for (int p = 0; p < _gd.MinPlayers; ++p) { context.Hands[p] = new List <int>(); } } else { stack[depth - 1].IsLeaf = false; for (int p = 0; p < _gd.MinPlayers; ++p) { context.Hands[p] = new List <int>(stack[depth - 1].Hands[p]); } context.Hands[tree.Nodes[n].Position].Add(tree.Nodes[n].Card); } }
public void Test_Merge() { IChanceAbstraction[] chanceAbstractions = new IChanceAbstraction[] { new LeducHeChanceAbstraction(LeducHeChanceAbstraction.FractionalResult), new LeducHeChanceAbstraction(LeducHeChanceAbstraction.FractionalResult) }; CtMcGen.Tree tree1 = CtMcGen.Generate(_leducHeGd, chanceAbstractions, false, 10000, 333, null); CtMcGen.Tree tree2 = CtMcGen.Generate(_leducHeGd, chanceAbstractions, false, 10000, 333, null); UInt64 expSamplesCount = tree1.SamplesCount + tree2.SamplesCount; string fileName = Path.Combine(_outDir, "ctmcgen-tree2.dat"); tree2.Write(fileName); tree1.Read(fileName); Assert.AreEqual(expSamplesCount, tree1.SamplesCount); ChanceTree ct1 = tree1.ConvertToChanceTree(); ChanceTree ct2 = tree2.ConvertToChanceTree(); // Compare two chance trees, they must be exactly the same. CompareChanceTrees cmp = new CompareChanceTrees(); cmp.Compare(ct1, ct2); Assert.AreEqual(0, cmp.SumProbabDiff); for (int p = 0; p < chanceAbstractions.Length; ++p) { Assert.AreEqual(0, cmp.SumPotShareDiff[p]); } }
public static bool Verify(ActionTree at, ChanceTree ct, StrategyTree[] strategies, double epsilon, out string message) { message = ""; // No need to check preconditions, GameValue does it GameValue gv = new GameValue { ActionTree = at, ChanceTree = ct, Strategies = strategies }; gv.Solve(); for (int p = 0; p < at.PlayersCount; ++p) { StrategyTree[] strategiesCopy = (StrategyTree[])strategies.Clone(); Br br = new Br { ActionTree = at, ChanceTree = ct, Strategies = strategiesCopy, HeroPosition = p }; br.Solve(); if (!FloatingPoint.AreEqual(gv.Values[p], br.Value, epsilon)) { message = String.Format("Unequal values for pos {0}: eq: {1}, br: {2}, eps: {3}", p, gv.Values[p], br.Value, epsilon); return(false); } } return(true); }
public static void ToTxt(ChanceTree t, string fileName) { using (TextWriter w = new StreamWriter(File.Open(fileName, FileMode.Create, FileAccess.Write, FileShare.Write))) { ToTxt(t, w); } }
void FinalizeChanceTree_OnNodeEnd(ChanceTree tree, WalkUFTreePPContext[] stack, int depth) { if (depth > 0) { tree.Nodes[stack[depth - 1].NodeIdx].Probab += tree.Nodes[stack[depth].NodeIdx].Probab; } }
public void Test_AnalyzeS() { GameDefinition gd = XmlSerializerExt.Deserialize <GameDefinition>( Props.Global.Expand("${bds.DataDir}ai.pkr.metastrategy/kuhn.gamedef.xml")); ChanceTree ct0 = CreateChanceTreeByGameDef.Create(gd); AnalyzeChanceTree.AnalyzeS(ct0); }
/// <summary> /// Compares trees verbose. /// </summary> /// <param name="ct1"></param> /// <param name="ct2"></param> public static void CompareS(ChanceTree ct1, ChanceTree ct2) { CompareChanceTrees comparer = new CompareChanceTrees { IsVerbose = true }; comparer.Compare(ct1, ct2); }
protected override void OnTreeBeginFunc(UFToUniAdapter aTree, int aRoot) { ChanceTree tree = (ChanceTree)(aTree.UfTree); GraphAttributes.label = tree.Version.Description; GraphAttributes.fontsize = 20; base.OnTreeBeginFunc(aTree, aRoot); }
public static void VerifyS(ChanceTree ct, double epsilon) { VerifyChanceTree vct = new VerifyChanceTree { Epsilon = epsilon }; vct.Verify(ct); }
/// <summary> /// Runs the analysis in verbose mode. /// </summary> public static void AnalyzeS(ChanceTree ct) { AnalyzeChanceTree analyzer = new AnalyzeChanceTree { IsVerbose = true }; analyzer.Analyze(ct); }
void VerifyPostion(ChanceTree tree, Int64 n, int expectedPos) { if (tree.Nodes[n].Position != expectedPos) { throw new ApplicationException(String.Format("Node {0} - wrong position {1}, expected {2}", n, tree.Nodes[n].Position, expectedPos)); } }
void Calculate_Chance_OnNodeBegin(ChanceTree tree, CalculateChanceContext[] stack, int depth) { CalculateChanceContext context = stack[depth]; Int64 n = context.NodeIdx; // We are interested in nodes up to chanceDepth. // Now we are traversing the whole tree in each round, but ignore the nodes of rounds // greater than the round of the current action leave. This can be optimized by indexing if necessary. // But this probably will not bring much because the most of work is done in the last round: // there are more action nodes and the whole chance tree must be traversed. if (depth > _chanceDepth) { return; } if (depth > 0) { context.Round = stack[depth - 1].Round; context.StrategicProbab = stack[depth - 1].StrategicProbab; stack[depth - 1].ChanceIdx.CopyTo(context.ChanceIdx, 0); if (tree.Nodes[n].Position == 0) { context.Round++; } int curPlayer = tree.Nodes[n].Position; context.ChanceIdx[curPlayer] += CalculateChanceOffset(context.Round, curPlayer) * tree.Nodes[n].Card; int player = _playersCount - _chanceDepth + depth - 1; if (player >= 0) { double[] probabArray = _spArrays[player][_actionTreeNodeIdx]; double playerStrategicProbab = probabArray[context.ChanceIdx[player]]; context.StrategicProbab *= playerStrategicProbab; if (depth == _chanceDepth) { double[] potShares = new double[_playersCount]; UInt16 activePlayers = ActionTree.Nodes[_actionTreeNodeIdx].ActivePlayers; Debug.Assert(context.Round == _roundsCount - 1 || CountBits.Count(activePlayers) == 1, "Must be either chance leaf or single active player"); ChanceTree.Nodes[n].GetPotShare(activePlayers, potShares); double chanceProbab = ChanceTree.Nodes[n].Probab; double probab = chanceProbab * context.StrategicProbab; double pot = _strategicState.Pot; for (int p = 0; p < _playersCount; ++p) { double playerValue = probab * (pot * potShares[p] - _strategicState.InPot[p]); _gameValues[p] += playerValue; if (PrepareVis) { _visLeaveValues[p][_actionTreeNodeIdx][context.ChanceIdx[p]] += playerValue; } } } } } }
public void Test_Kuhn() { GameDefinition gd = XmlSerializerExt.Deserialize <GameDefinition>( Props.Global.Expand("${bds.DataDir}ai.pkr.metastrategy/kuhn.gamedef.xml")); ChanceTree ct = CreateChanceTreeByGameDef.Create(gd); double [] expectedProbabs = new double[] { 1, 1.0 / 3, 1.0 / 3, 1.0 / 3 }; CreateAndVerifyPlayerTrees(gd, ct, expectedProbabs); }
public void Compare(ChanceTree ct0, ChanceTree ct1) { if (IsVerbose) { Output.WriteLine("Compare chance trees"); Output.WriteLine("0: '{0}'", ct0.Version.Description); Output.WriteLine("1: '{0}'", ct1.Version.Description); } if (ct0.PlayersCount != ct1.PlayersCount) { throw new ApplicationException(String.Format("Player counts differ: {0} != {1}", ct0.PlayersCount, ct1.PlayersCount)); } CompareUFTrees <ChanceTree, ChanceTree> comp = new CompareUFTrees <ChanceTree, ChanceTree>(); _playersCount = ct0.PlayersCount; _maxDepth = ct0.CalculateRoundsCount() * _playersCount; LeavesCount = new int[2]; SumPotShareDiff = new double[_playersCount]; AveragePotShareDiff = new double[_playersCount]; SumProbabDiff = 0; MaxProbabDiff = double.MinValue; MaxPotShareDiff = new double[_playersCount].Fill(i => double.MinValue); CompareTrees(ct0, ct1); double leavesCount = (LeavesCount[0] + LeavesCount[1]) * 0.5; AverageProbabDiff = SumProbabDiff / leavesCount; AverageRelProbabDiff = SumRelProbabDiff / leavesCount; for (int p = 0; p < _playersCount; ++p) { AveragePotShareDiff[p] = SumPotShareDiff[p] / leavesCount; } if (IsVerbose) { for (int p = 0; p < _playersCount; ++p) { Output.WriteLine("p {0}: leaves: {1:#,#}", p, LeavesCount[p]); } Output.WriteLine("Probab diff : max {0,-20} sum {1,-20} av {2,-20}", MaxProbabDiff, SumProbabDiff, AverageProbabDiff); Output.WriteLine("Rel pr diff : max {0,-20} sum {1,-20} av {2,-20}", MaxRelProbabDiff, SumRelProbabDiff, AverageRelProbabDiff); for (int p = 0; p < _playersCount; ++p) { Output.WriteLine("Pot share diff p {0}: max {1,-20} sum {2,-20} av {3,-20}", p, MaxPotShareDiff[p], SumPotShareDiff[p], AveragePotShareDiff[p]); } } // This prevents the chance trees from premature garbage collection. string dummy = ct0.ToString() + ct1.ToString(); }
public static StrategyTree CreateStrategyTree(GameDefinition gd, int pos) { ChanceTree ct = CreateChanceTreeByGameDef.Create(gd); ChanceTree pct = ExtractPlayerChanceTree.ExtractS(ct, 0); ActionTree at = CreateActionTreeByGameDef.Create(gd); StrategyTree st = CreateStrategyTreeByChanceAndActionTrees.CreateS(pct, at); return(st); }
public void Test_CompareS() { GameDefinition gd = XmlSerializerExt.Deserialize <GameDefinition>( Props.Global.Expand("${bds.DataDir}ai.pkr.metastrategy/kuhn.gamedef.xml")); ChanceTree ct1 = CreateChanceTreeByGameDef.Create(gd); ChanceTree ct2 = CreateChanceTreeByGameDef.Create(gd); CompareChanceTrees.CompareS(ct1, ct2); }
public void Verify(ChanceTree ct) { _playersCount = ct.Nodes[0].Position; _areAllPosInvalid = true; WalkUFTreePP <ChanceTree, Context> wt = new WalkUFTreePP <ChanceTree, Context>(); wt.OnNodeBegin = OnNodeBegin; wt.OnNodeEnd = OnNodeEnd; wt.Walk(ct); }
public static void Show(ChanceTree ct, string fileName) { using (TextWriter w = new StreamWriter(File.Open(fileName, FileMode.Create))) { VisChanceTree vis = new VisChanceTree { Output = w }; vis.Show(ct); } }