// Use custom implementation for optitmization reasons. protected void ProcessChildren(ActionTreeNode node) { for (int c = 0; c < node.Children.Count; ++c) { node.Children[c].StrategyFactor = node.StrategyFactor; TraverseSubtree(node.Children[c], node); } }
protected bool OnNodeBegin(ActionTreeNode node, ActionTreeNode parent) { if (node.ActionKind == Ak.s) { Debug.Assert(node.State.LastActor == -1); // This is a point where a bucket is transformed to the next round's buckets. // Here we do not have know the probability of transformation from // mc[r].bucket -> mc[r+1].bucket, because this probability i // is inherently taken into account by Monte-Carlo method. } else if (parent != null && parent.State.CurrentActor == 1 - _ourPos && !parent.State.IsDealerActing) { // Opponent have acted - apply strategic probability. Debug.Assert(node.State.Round == parent.State.Round); int bucket = _mc[node.State.Round].bucket; int parentFreq = parent.OppBuckets.Counts[bucket]; int nodeFreq = node.OppBuckets.Counts[bucket]; if (parentFreq != 0) { node.StrategyFactor *= (double)nodeFreq / parentFreq; } else { Debug.Assert(nodeFreq == 0); node.StrategyFactor = 0; } } if (node.Children.Count == 0) { // Terminal node. Debug.Assert(node.State.IsGameOver); double value; if (node.State.IsShowdownRequired) { // Noone folded - do showdown. value = node.State.Pot / 2 * _showdownValue; } else if (node.State.Players[_ourPos].IsFolded) { // We folded value = -node.State.Players[_ourPos].InPot; } else { // Opponent folded Debug.Assert(node.State.Players[1 - _ourPos].IsFolded); value = node.State.Players[1 - _ourPos].InPot; } value *= node.StrategyFactor; node.Value += value; } return(node.StrategyFactor > 0); }
protected bool TraverseSubtree(ActionTreeNode node, ActionTreeNode parent) { if (!OnNodeBegin(node, parent)) { return(false); } ProcessChildren(node); return(true); }
public void ApplyData(ActionTreeNode root, MonteCarloData [] mc, int ourPos, int showdownValue, double strategyFactor) { _mc = mc; _ourPos = ourPos; _showdownValue = showdownValue; root.StrategyFactor = strategyFactor; TraverseSubtree(root, null); }
public static bool TreeGetChild(ActionTree tree, ActionTreeNode n, ref int i, out ActionTreeNode child) { if (i < n.Children.Count) { child = n.Children[i++]; return(true); } child = null; return(false); }
public ActionTree(GameDefinition gameDef, Bucketizer bucketizer) { Version = new BdsVersion(Assembly.GetExecutingAssembly()); GameDef = gameDef; Bucketizer = bucketizer; Positions = new ActionTreeNode[GameDef.MinPlayers]; for (int p = 0; p < Positions.Length; ++p) { Positions[p] = new ActionTreeNode(); Positions[p].State = new GameState(gameDef, gameDef.MinPlayers); } }
private void ProcessPlayerActions() { for (int a = _strategyPath.Count - 1; a < _gameRecord.Actions.Count; ++a) { PokerAction pa = _gameRecord.Actions[a]; log.InfoFormat("{0} process {1} of pos {2}", _name, pa.Kind, pa.Position); ActionTreeNode nextNode = CurStrategyNode.FindChildByAction(pa.Kind); Debug.Assert(nextNode.State.LastActor == pa.Position); _strategyPath.Add(nextNode); if (pa.Kind == Ak.d && pa.Position == _pos) { OnDeal(pa.Cards); } } }
private PokerAction GetBestAction(GameState CurGameState) { Debug.Assert(CurStrategyNode.State.CurrentActor == _pos); double maxVal = double.MinValue; ActionTreeNode bestNode = null; foreach (ActionTreeNode child in CurStrategyNode.Children) { double childValue = CurGameState.Round == 0 ? child.PreflopValues[(int)_pocketKind] : child.Value; if (childValue > maxVal) { bestNode = child; maxVal = childValue; } else if (childValue == maxVal) { if (ActionPreference(child.ActionKind) > ActionPreference(bestNode.ActionKind)) { bestNode = child; } } } PokerAction result; if (bestNode != null) { result = new PokerAction { Kind = bestNode.ActionKind }; } else { Debug.Assert(CurStrategyNode.Children.Count > 0); // We have never been here - just call result = PokerAction.c(0); } return(result); }
protected override bool OnNodeBeginFunc(GenTree tree, GenNode node, List <ActionTreeBuilderContext> stack, int depth) { base.OnNodeBeginFunc(tree, node, stack, depth); ActionTreeNode atNode; if (depth == 0) { atNode = _atTree.Positions[_pos]; } else { atNode = new ActionTreeNode(); stack[depth - 1].AtNode.Children.Add(atNode); } stack[depth].AtNode = atNode; atNode.State = node.State; atNode.ActionKind = node.Action.Kind; atNode.Id = NodesCount; NodesCount++; GameState gs = atNode.State; if (gs.IsGameOver) { if (gs.Players[1 - _pos].IsFolded) { atNode.OppBuckets = new Buckets(0, 0); // If we fold, it is never used } else { atNode.OppBuckets = new Buckets(_atTree.Bucketizer.BucketCount[gs.Round], 0); } return(false); } atNode.OppBuckets = new Buckets(depth > 0 ? _atTree.Bucketizer.BucketCount[gs.Round] : 0, 0); return(true); }
public static void DoMonteCarlo( ActionTree tree, int ourPos, CardSet pocket, int round, string sharedCardsAsString, List <ActionTreeNode> strategyPath, int repetitionsCount) { string[] sharedCards = sharedCardsAsString.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); ActionTreeNode curStrategyNode = strategyPath[strategyPath.Count - 1]; // Here we sometimes use the knowledge about the game definition. _clearValues.Walk(tree, curStrategyNode); MonteCarloData[] mc = new MonteCarloData[tree.GameDef.RoundsCount]; for (int r = 0; r < mc.Length; ++r) { mc[r] = new MonteCarloData(); } // Fill known public data. for (int r = 1; r <= round; ++r) { int sharedCount = tree.GameDef.SharedCardsCount[r]; mc[r].boardSize = mc[r - 1].boardSize + sharedCount; mc[r].shared = StdDeck.Descriptor.GetCardSet(sharedCards, mc[r - 1].boardSize, sharedCount); mc[r].board = mc[r - 1].board | mc[r].shared; Debug.Assert(mc[r].shared.CountCards() == sharedCount); Debug.Assert(mc[r].board.CountCards() == mc[r].boardSize); } Debug.Assert(mc[round].boardSize == sharedCards.Length); MonteCarloDealer mcDealer = new MonteCarloDealer(); ApplyMonteCarloData applyMc = new ApplyMonteCarloData(); mcDealer.Initialize(pocket | mc[round].board); Debug.Assert(mcDealer.Cards.Length + pocket.CountCards() + mc[round].boardSize == 52); for (int repetition = 0; repetition < repetitionsCount * 10; ++repetition) { mcDealer.Shuffle(7); // 2 for opponent, up to 5 for the board CardSet mcPocket = StdDeck.Descriptor.GetCardSet(mcDealer.Cards, 0, 2); Debug.Assert(mc[0].board.IsEmpty()); int sharedDealt = 0; for (int r = 0; r < tree.GameDef.RoundsCount; ++r) { if (r > round) { mc[r].boardSize = mc[r - 1].boardSize + tree.GameDef.SharedCardsCount[r]; mc[r].shared = StdDeck.Descriptor.GetCardSet(mcDealer.Cards, 2 + sharedDealt, tree.GameDef.SharedCardsCount[r]); sharedDealt += tree.GameDef.SharedCardsCount[r]; Debug.Assert(!mc[r - 1].board.Contains(mc[r].shared)); Debug.Assert(!mcPocket.Contains(mc[r].shared)); mc[r].board = mc[r - 1].board | mc[r].shared; } mc[r].bucket = tree.Bucketizer.GetBucket(mcPocket, mc[r].board, r); } double strategyFactor = 1; // Go through the strategy path, skip the b-node Debug.Assert(strategyPath[0].ActionKind == Ak.b); // Start from pos. 2 to skip deals (where OppBuckets always contains 0s if ourPos == 0). for (int pathIndex = 2; pathIndex < strategyPath.Count; pathIndex++) { ActionTreeNode pathNode = strategyPath[pathIndex]; Debug.Assert(pathNode.ActionKind != Ak.b); // Take nodes where opponent acts. if (pathNode.State.CurrentActor == 1 - ourPos) { // nextNode always exists because this function is called when we act ActionTreeNode nextNode = strategyPath[pathIndex + 1]; Debug.Assert(pathNode.State.Round == nextNode.State.Round); int freq = pathNode.OppBuckets.Counts[mc[pathNode.State.Round].bucket]; int nextFreq = nextNode.OppBuckets.Counts[mc[pathNode.State.Round].bucket]; double coef = freq == 0 ? 0 : (double)nextFreq / freq; strategyFactor *= coef; } } if (strategyFactor > 0) { int showdownValue = Showdown(pocket, mcPocket, mc[tree.GameDef.RoundsCount - 1].board, mc[tree.GameDef.RoundsCount - 1].boardSize + 2); applyMc.ApplyData(curStrategyNode, mc, ourPos, showdownValue, strategyFactor); repetition += 9; } } FinalizeMonteCarloData finalizer = new FinalizeMonteCarloData(); finalizer.Finalize(tree, curStrategyNode, ourPos); }