/// <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); }
/// <summary> /// Runs FictitiousPlay with the specified parameters. /// Some parameters are set by default (e.g. verbosity), the caller has a chance to overwrite them /// using Configure delegate. /// </summary> public StrategyTree[] Solve(ActionTree at, ChanceTree ct) { int playersCount = 2; DirectoryExt.Delete(BaseDir); Directory.CreateDirectory(BaseDir); string inputDir = Path.Combine(BaseDir, "input"); Directory.CreateDirectory(inputDir); string traceDir = Path.Combine(BaseDir, "trace"); string chanceTreeFile = Path.Combine(inputDir, "ct.dat"); string actionTreeFile = Path.Combine(inputDir, "at.dat"); ct.Write(chanceTreeFile); at.Write(actionTreeFile); if (VisualizeTrees) { VisActionTree.Show(at, actionTreeFile + ".gv"); VisChanceTree.Show(ct, chanceTreeFile + ".gv"); } Solver.ChanceTreeFile = chanceTreeFile; Solver.EqualCa = false; Solver.ActionTreeFile = actionTreeFile; Solver.OutputPath = BaseDir; Solver.SnapshotsCount = 2; Solver.Epsilon = Epsilon; Solver.ThreadsCount = 6; Solver.IsVerbose = true; Solver.IterationVerbosity = 10000; Solver.MaxIterationCount = 1000000000; if (Configure != null) { Configure(Solver); } Solver.Solve(); StrategyTree[] eqStrategies = new StrategyTree[playersCount]; for (int p = 0; p < playersCount; ++p) { string fileName = Solver.CurrentSnapshotInfo.StrategyFile[p]; eqStrategies[p] = StrategyTree.Read <StrategyTree>(fileName); if (VisualizeTrees) { VisStrategyTree.Show(eqStrategies[p], fileName + ".gv"); } } return(eqStrategies); }
private GameValue Solve(TestParams testParams, bool visualize, ConfigureSolver configureSolver) { if (visualize) { VisActionTree.Show(testParams.ActionTree, Path.Combine(_outDir, String.Format("{0}-at.gv", testParams.Name))); VisChanceTree.Show(testParams.ChanceTree, Path.Combine(_outDir, String.Format("{0}-ct.gv", testParams.Name))); for (int p = 0; p < testParams.StrategyTrees.Length; ++p) { VisStrategyTree.Show(testParams.StrategyTrees[p], Path.Combine(_outDir, string.Format("{0}-st-{1}.gv", testParams.Name, p))); } } // Make sure input is correct. for (int p = 0; p < testParams.ChanceTree.Nodes[0].Position; ++p) { string errorText; Assert.IsTrue(VerifyAbsStrategy.Verify(testParams.StrategyTrees[p], p, 0.000001, out errorText), errorText); } GameValue gv = new GameValue { ChanceTree = testParams.ChanceTree, ActionTree = testParams.ActionTree, Strategies = testParams.StrategyTrees }; gv.PrepareVis = visualize; if (configureSolver != null) { configureSolver(gv); } gv.Solve(); if (visualize) { for (int p = 0; p < testParams.ChanceTree.PlayersCount; ++p) { GameValue.Vis.Show(gv, p, Path.Combine(_outDir, String.Format("{0}-{1}-val.gv", testParams.Name, p))); } } Assert.AreEqual(2, gv.Values.Length); for (int p = 0; p < testParams.ChanceTree.PlayersCount; ++p) { Console.WriteLine("Game value pos {0}: {1}", p, gv.Values[p]); Assert.AreEqual(testParams.ExpectedResult[p], gv.Values[p], testParams.Epsilon); } return(gv); }
private void ShowTree(GameDefinition gd) { for (int pos = 0; pos < gd.MinPlayers; ++pos) { StrategyTree st = TreeHelper.CreateStrategyTree(gd, pos); string fileName = string.Format("{0}-{1}.gv", gd.Name, pos); using (TextWriter w = new StreamWriter(File.Open(Path.Combine(_outDir, fileName), FileMode.Create))) { VisStrategyTree vis = new VisStrategyTree { Output = w, CardNames = gd.DeckDescr.CardNames }; vis.Show(st, 3); } } }
private void Solve(TestParams testParams, bool visualize, ConfigureSolver configureSolver) { if (visualize) { VisActionTree.Show(testParams.ActionTree, Path.Combine(_outDir, String.Format("{0}-at.gv", testParams.Name))); VisChanceTree.Show(testParams.ChanceTree, Path.Combine(_outDir, String.Format("{0}-ct.gv", testParams.Name))); } StrategyTree [] eqStrategies = new StrategyTree[testParams.ChanceTree.PlayersCount]; string error; for (int heroPos = 0; heroPos < testParams.ChanceTree.PlayersCount; ++heroPos) { // Create and configure EqLp solver EqLp solver = new EqLp { HeroPosition = heroPos, ChanceTree = testParams.ChanceTree, ActionTree = testParams.ActionTree, }; if (configureSolver != null) { configureSolver(solver); } // Solve EqLp solver.Solve(); eqStrategies[heroPos] = solver.Strategy; if (visualize) { VisStrategyTree.Show(solver.Strategy, Path.Combine(_outDir, string.Format("{0}-eq-{1}.gv", testParams.Name, heroPos))); } // Verify the eq value and strategy Assert.AreEqual(testParams.ExpectedResult[heroPos], solver.Value, testParams.Epsilon, "Wrong eq value"); Assert.IsTrue(VerifyAbsStrategy.Verify(solver.Strategy, solver.HeroPosition, 1e-7, out error), error); } // Verify eq, use another (better) epsilon because EqLp and VerifyEq have better precision // than most of the reference game solvers like OCFR. Assert.IsTrue(VerifyEq.Verify(testParams.ActionTree, testParams.ChanceTree, eqStrategies, 1e-7, out error), error); }
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); ActionTree at = CreateActionTreeByGameDef.Create(gd); StrategyTree [] playerTrees = new StrategyTree[2]; for (int p = 0; p < 2; ++p) { ChanceTree pct = ExtractPlayerChanceTree.ExtractS(ct, p); StrategyTree st = CreateStrategyTreeByChanceAndActionTrees.CreateS(pct, at); playerTrees[p] = st; VisStrategyTree.Show(st, Path.Combine(_outDir, string.Format("pt-{0}.gv", p))); } }
public void Test_Leduc() { GameDefinition gd = XmlSerializerExt.Deserialize <GameDefinition>( Props.Global.Expand("${bds.DataDir}ai.pkr.metastrategy/leduc-he.gamedef.xml")); for (_heroPos = 0; _heroPos < gd.MinPlayers; ++_heroPos) { StrategyTree st = CreateValidStrategy(gd); string fileName = Path.Combine(_outDir, string.Format("{0}-{1}.gv", gd.Name, _heroPos)); VisStrategyTree.Show(st, fileName); string errorText; Assert.IsTrue(VerifyCondStrategy.Verify(st, _heroPos, out errorText)); // Now make some errors. if (_heroPos == 0) { st.Nodes[339].Probab += 0.1; Assert.IsFalse(VerifyCondStrategy.Verify(st, _heroPos, out errorText)); string expTextBegin = string.Format("Node {0}:", 291); Assert.AreEqual(expTextBegin, errorText.Substring(0, expTextBegin.Length)); st.Nodes[339].Probab -= 0.1; st.Nodes[348].Probab += 0.1; Assert.IsFalse(VerifyCondStrategy.Verify(st, _heroPos, out errorText)); expTextBegin = string.Format("Node {0}:", 345); Assert.AreEqual(expTextBegin, errorText.Substring(0, expTextBegin.Length)); } else { st.Nodes[435].Probab += 0.1; Assert.IsFalse(VerifyCondStrategy.Verify(st, _heroPos, out errorText)); string expTextBegin = string.Format("Node {0}:", 387); Assert.AreEqual(expTextBegin, errorText.Substring(0, expTextBegin.Length)); st.Nodes[435].Probab -= 0.1; st.Nodes[432].Probab += 0.1; Assert.IsFalse(VerifyCondStrategy.Verify(st, _heroPos, out errorText)); expTextBegin = string.Format("Node {0}:", 429); Assert.AreEqual(expTextBegin, errorText.Substring(0, expTextBegin.Length)); } } }
public void Test_AnalyzeS() { GameDefinition gd = XmlSerializerExt.Deserialize <GameDefinition>( Props.Global.Expand("${bds.DataDir}ai.pkr.metastrategy/kuhn.gamedef.xml")); string[] strategyFiles = new string[] { "eq-KunhPoker-0-s.xml", "eq-KunhPoker-1-s.xml" }; for (int pos = 0; pos < 2; ++pos) { string strFile = Path.Combine(_testResDir, strategyFiles[pos]); StrategyTree st = XmlToStrategyTree.Convert(strFile, gd.DeckDescr); VisStrategyTree.Show(st, Path.Combine(_outDir, string.Format("{0}-{1}.gv", gd.Name, pos))); AnalyzeStrategyTree an = new AnalyzeStrategyTree { StrategyTree = st, IsAbsolute = true, HeroPosition = pos, IsVerbose = true }; an.Analyze(); Assert.AreEqual(15, an.LeavesCount); if (pos == 0) { Assert.AreEqual(12, an.MovesCount); Assert.AreEqual(5, an.ZaspMovesCount); Assert.AreEqual(3, an.ZaspLeavesCount); Assert.AreEqual(1, an.Statistics.Count); Assert.AreEqual(5, an.Statistics[0].NZaspMovesCount); Assert.AreEqual(1 + 0.33333, an.Statistics[0].SumNZaspFold, 0.00001); Assert.AreEqual(0.66667 + 1 + 0.66667, an.Statistics[0].SumNZaspCall, 0.00001); Assert.AreEqual(0.33333 + 1, an.Statistics[0].SumNZaspRaise, 0.00001); } else { Assert.AreEqual(12, an.MovesCount); Assert.AreEqual(4, an.ZaspMovesCount); Assert.AreEqual(3, an.ZaspLeavesCount); Assert.AreEqual(1, an.Statistics.Count); Assert.AreEqual(6, an.Statistics[0].NZaspMovesCount); Assert.AreEqual(1 + 0.66667, an.Statistics[0].SumNZaspFold, 0.00001); Assert.AreEqual(0.66667 + 1 + 0.33333 + 1, an.Statistics[0].SumNZaspCall, 0.00001); Assert.AreEqual(0.33333 + 1, an.Statistics[0].SumNZaspRaise, 0.00001); } } }
public void Test_Eq() { GameDefinition gd = XmlSerializerExt.Deserialize <GameDefinition>("kuhn8.gamedef.xml"); ChanceTree ct = CreateChanceTreeByGameDef.Create(gd); VisChanceTree.Show(ct, "kuhn8-ct.gv"); ActionTree at = CreateActionTreeByGameDef.Create(gd); VisActionTree.Show(at, "kuhn8-at.gv"); double[] values; StrategyTree [] strategies = EqLp.Solve(at, ct, out values); Console.WriteLine("Kuhn8 eq values: {0}, {1}", values[0], values[1]); VisStrategyTree.Show(strategies[0], "kuhn8-eq-0.gv"); VisStrategyTree.Show(strategies[1], "kuhn8-eq-1.gv"); // Make strategy for T same as for Q //strategies[0].Nodes[strategies[0].FindNode("0d0 0p0", null)].Probab = 0.5; //strategies[0].Nodes[strategies[0].FindNode("0d0 0p0 1p1 0p1", null)].Probab = 0.5; //strategies[0].Nodes[strategies[0].FindNode("0d0 0p1", null)].Probab = 0.5; // Make strategy for Q same as for T strategies[0].Nodes[strategies[0].FindNode("0d2 0p0", null)].Probab = 0; strategies[0].Nodes[strategies[0].FindNode("0d2 0p0 1p1 0p1", null)].Probab = 0; strategies[0].Nodes[strategies[0].FindNode("0d2 0p1", null)].Probab = 1; VisStrategyTree.Show(strategies[0], "kuhn8-eq-0-adj.gv"); Br br = new Br { ActionTree = at, ChanceTree = ct, HeroPosition = 1 }; br.Strategies = new StrategyTree[] { strategies[0], null }; br.Solve(); StrategyTree br0 = br.Strategies[1]; Console.WriteLine("Br against pos 0: {0}", br.Value); VisStrategyTree.Show(strategies[1], "kuhn8-eq-br-0.gv"); }
public void Test_CallKK() { string outDir = Path.Combine(_outDir, "call-KK"); Directory.CreateDirectory(outDir); HePocketKind[] sbPockets = new HePocketKind[] { HePocketKind._AA, HePocketKind._KK, HePocketKind._AKs }; HePocketKind[] bbPockets = new HePocketKind[] { HePocketKind._AA, HePocketKind._KK, HePocketKind._QQ, HePocketKind._AKs }; string xmlAt = Props.Global.Expand("${bds.DataDir}ai.pkr.holdem.learn/bigcards-pf-1.xml"); ActionTree at = XmlToActionTree.Convert(xmlAt); VisActionTree.Show(at, Path.Combine(outDir, "at.gv")); BigCardsPreflop bc = new BigCardsPreflop(); bc.Solve(at, sbPockets, bbPockets); Console.WriteLine("Game values: {0}, {1}", bc.GameValues[0], bc.GameValues[1]); VisChanceTree.Show(bc.Ct, Path.Combine(outDir, "ct.gv")); VisStrategyTree.Show(bc.Strategies[0], Path.Combine(outDir, "st-0.gv")); VisStrategyTree.Show(bc.Strategies[1], Path.Combine(outDir, "st-1.gv")); }
/// <summary> /// Runs the solver with the specified parameters.. /// </summary> /// <param name="iterCounts">Number of iterations for each run, -1 - unlimited.</param> private StrategyTree RunSolver(TestParams testParams, bool visualize, bool trace, int [] iterCounts, ConfigureSolver configureSolver) { int playersCount = testParams.ChanceTree.PlayersCount; string baseDir = Path.Combine(_outDir, testParams.Name); DirectoryExt.Delete(baseDir); Directory.CreateDirectory(baseDir); string inputDir = Path.Combine(baseDir, "input"); Directory.CreateDirectory(inputDir); string traceDir = Path.Combine(baseDir, "trace"); if (trace) { Directory.CreateDirectory(traceDir); } string chanceTreeFile = Path.Combine(inputDir, "ct.dat"); string actionTreeFile = Path.Combine(inputDir, "at.dat"); testParams.ChanceTree.Write(chanceTreeFile); testParams.ActionTree.Write(actionTreeFile); if (visualize) { VisActionTree.Show(testParams.ActionTree, actionTreeFile + ".gv"); VisChanceTree.Show(testParams.ChanceTree, chanceTreeFile + ".gv"); } int runs = iterCounts.Length; Breb solver = null; for (int r = 0; r < runs; ++r) { // Create and configure a solver solver = new Breb { GameDef = testParams.GameDef, ActionTreeFile = actionTreeFile, ChanceTreeFile = chanceTreeFile, OutputPath = baseDir, SnapshotsCount = 2, Epsilon = testParams.Epsilon, ThreadsCount = DEFAULT_THREADS_COUNT, }; if (trace) { solver.TraceDir = traceDir; } solver.MaxIterationCount = iterCounts[r]; if (configureSolver != null) { configureSolver(solver); } solver.Solve(); } string fileName = solver.CurrentSnapshotInfo.StrategyFile; StrategyTree eqStrategy = StrategyTree.Read <StrategyTree>(fileName); if (visualize) { VisStrategyTree.Show(eqStrategy, fileName + ".gv"); } return(eqStrategy); }
private static bool ProcessStrategyTree() { StrategyTree tree; if (_cmdLine.Input != "") { if (_inputFormat == ".dat") { tree = UFTree.Read <StrategyTree>(_cmdLine.Input); } else if (_inputFormat == ".txt") { tree = DumpStrategyTree.FromTxt(_cmdLine.Input); } else { Console.Error.WriteLine("Unsupported input format '{0}' for tree kind '{1}'", _inputFormat, _cmdLine.TreeKind); return(false); } } else { ActionTree at = CreateActionTreeByGameDef.Create(_gd); ChanceTree ct = CreateChanceTreeByGameDef.Create(_gd); ChanceTree pct = ExtractPlayerChanceTree.ExtractS(ct, _cmdLine.Position); tree = CreateStrategyTreeByChanceAndActionTrees.CreateS(pct, at); } if (_outputFormat == ".gv") { using (TextWriter w = new StreamWriter(File.Open(_cmdLine.Output, FileMode.Create))) { VisStrategyTree vis = new VisStrategyTree { Output = w }; if (_gd != null) { vis.CardNames = _gd.DeckDescr.CardNames; } if (_cmdLine.ClearExpr) { vis.ShowExpr.Clear(); } vis.ShowExprFromString(_cmdLine.ShowExpr); vis.PruneIfExt = (t, n, s, d) => s[d].Round > _cmdLine.MaxRound; vis.MatchPath = _cmdLine.MatchPath; vis.Show(tree, _cmdLine.Root); } } else if (_outputFormat == ".xml") { using (TextWriter w = new StreamWriter(File.Open(_cmdLine.Output, FileMode.Create))) { XmlWriterSettings settings = new XmlWriterSettings(); settings.Encoding = Encoding.ASCII; settings.Indent = true; using (XmlWriter xmlWriter = XmlWriter.Create(w, settings)) { StrategyTreeToXml xmlizer = new StrategyTreeToXml { Output = xmlWriter }; if (_cmdLine.ClearExpr) { xmlizer.ShowExpr.Clear(); } xmlizer.ShowExprFromString(_cmdLine.ShowExpr); xmlizer.Convert(tree); } } } else if (_outputFormat == ".dat") { tree.Write(_cmdLine.Output); } else if (_outputFormat == ".txt") { DumpStrategyTree.ToTxt(tree, _cmdLine.Output); } else { Console.Error.WriteLine("Unsupported ouput format '{0}' for tree kind '{1}'", _outputFormat, _cmdLine.TreeKind); return(false); } return(true); }
private void Solve(TestParams testParams, bool visualize, ConfigureSolver configureSolver) { if (visualize) { VisActionTree.Show(testParams.ActionTree, Path.Combine(_outDir, String.Format("{0}-at.gv", testParams.Name))); VisChanceTree.Show(testParams.ChanceTree, Path.Combine(_outDir, String.Format("{0}-ct.gv", testParams.Name))); for (int p = 0; p < testParams.StrategyTrees.Length; ++p) { VisStrategyTree.Show(testParams.StrategyTrees[p], Path.Combine(_outDir, string.Format("{0}-st-{1}.gv", testParams.Name, p))); } } // Make sure input is correct. for (int p = 0; p < testParams.ChanceTree.Nodes[0].Position; ++p) { string errorText; Assert.IsTrue(VerifyAbsStrategy.Verify(testParams.StrategyTrees[p], p, 0.000001, out errorText), errorText); } for (int heroPos = 0; heroPos < testParams.ChanceTree.PlayersCount; ++heroPos) { // Create and configure Br solver Br br = new Br { HeroPosition = heroPos, ChanceTree = testParams.ChanceTree, ActionTree = testParams.ActionTree, }; br.Strategies = new StrategyTree[testParams.ChanceTree.PlayersCount]; for (int opp = 0; opp < testParams.ChanceTree.PlayersCount; ++opp) { if (opp == heroPos) { continue; } br.Strategies[opp] = testParams.StrategyTrees[opp]; } br.PrepareVis = visualize; if (configureSolver != null) { configureSolver(br); } // Solve Br br.Solve(); if (visualize) { Br.Vis.Show(br, Path.Combine(_outDir, String.Format("{0}-br-{1}.gv", testParams.Name, heroPos))); } // Verify the Br value and strategy Assert.AreEqual(testParams.ExpectedResult[heroPos], br.Value, testParams.Epsilon, "Wrong BR value"); string error; Assert.IsTrue(VerifyAbsStrategy.Verify(br.Strategies[br.HeroPosition], br.HeroPosition, out error), error); // Verify Br strategy has the expected value by running an independent GameValue algo on it. GameValue gv = new GameValue { ActionTree = br.ActionTree, ChanceTree = br.ChanceTree, Strategies = br.Strategies }; gv.Solve(); Assert.AreEqual(testParams.ExpectedResult[heroPos], gv.Values[br.HeroPosition], testParams.Epsilon, "Wrong GameValue value"); } }