public void Initialize(CardSet deadCards) { CardSet full = StdDeck.Descriptor.FullDeck; Debug.Assert(full.CountCards() == 52); full.Remove(deadCards); _cards = StdDeck.Descriptor.GetIndexesAscending(full).ToArray(); }
public static float Calculate(CardSet board) { CalulateParam param = new CalulateParam(); int boardSize = board.CountCards(); int toDeal = 7 - boardSize; CardEnum.Combin(StdDeck.Descriptor, toDeal, board, CardSet.Empty, OnDeal, param); return((float)(param.Sum / EnumAlgos.CountCombin(52 - boardSize, toDeal))); }
public static float CalculateFast(CardSet pocket, CardSet board) { int boardSize = board.CountCards(); if (boardSize == 5) { int[] hand = new int[7]; List <int> pocketL = StdDeck.Descriptor.GetIndexesAscending(pocket); List <int> boardL = StdDeck.Descriptor.GetIndexesAscending(board); pocketL.CopyTo(hand, 0); boardL.CopyTo(hand, 2); return(Calculate(hand, 7)); } return(CalculateFast(pocket, board, boardSize + 2)); }
public void Test_CombinArray_CardSet() { CardSet[] arr = CardEnum.Combin(StdDeck.Descriptor, 2, CardSet.Empty, CardSet.Empty); Assert.AreEqual(1326, arr.Length); CardSet prev = arr[0]; Assert.AreEqual(2, prev.CountCards()); for (int i = 1; i < arr.Length; ++i) { CardSet cur = arr[i]; Assert.Less(prev.bits, cur.bits); Assert.AreEqual(2, cur.CountCards()); prev = cur; } }
void CombinRecursive( // Deck parameters CardSet[] deck, int suitCount, int deckSize, // Initial call parameters int n, // Algorithm parameters int depth, CardSet result1, int r1, int s1, int maxSuit, // Debug and test parameters ref int counter ) { if (depth == n) { Debug.Assert(result1.CountCards() == n); counter++; _list.Add(result1); if (Verbose) { Console.WriteLine("{0,6}: {1}", counter, result1); } return; } int r2 = r1; int s2 = s1 + 1; if (s2 >= suitCount) { s2 = 0; r2++; } for (; (r2 + s2) < deckSize + 1 - (n - depth);) { int maxSuit2 = r2 == r1 ? maxSuit : Math.Max(maxSuit, s2); //int maxSuit2 = Math.Max(maxSuit, s2); CardSet result2 = deck[r2 + s2]; Debug.Assert(!result2.IsIntersectingWith(result1)); result2.UnionWith(result1); CombinRecursive(deck, suitCount, deckSize, n, depth + 1, result2, r2, s2, maxSuit2, ref counter); s2++; if (s2 > Math.Min(maxSuit + 1, suitCount - 1)) { s2 = 0; r2 += suitCount; } } }
public static float CalculateFast(CardSet board) { NormSuit ns = new NormSuit(); Entry searchEntry = new Entry(); searchEntry.CardSet = ns.Convert(board).bits; int round = HeHelper.HandSizeToRound[board.CountCards() + 2]; Entry [] lut = _luts[round - 1]; int idx = Array.BinarySearch(lut, searchEntry); if (idx < 0) { throw new ApplicationException(string.Format("Cannot find LUT entry for board: '{0}'", StdDeck.Descriptor.GetCardNames(board))); } return(lut[idx].Ahvo); }
private void VerifyCombination(ref CardSet cs) { _combinationsCount++; Assert.IsFalse(cs.IsIntersectingWith(_dead)); Assert.IsTrue(cs.Contains(_shared)); CardSet uniqueMask = new CardSet { bits = cs.bits & (~_shared.bits) }; Assert.AreEqual(_enumCount, uniqueMask.CountCards()); // Use the fact that CardEnum generate masks in ascending order to check uniqueness if (_enumCount > 0) { Assert.Greater(uniqueMask.bits, _lastCs); } _lastCs = uniqueMask.bits; }
/// <summary> /// Returns a cardset containing only cards of suites that are either a flush-draw /// or a flush. A flush draw is a set of cards of one suit that still can produce a flush, /// e.g. any single card for 5-hands, or 7c 8c Ad Kd for 7-hands. /// If the flush (5+ cards of one suit) is present, this function preserves /// only 5 highest flush cards, to prevent 6-hands like /// Ac Qc Jc Tc 9c 2c and Ac Qc Jc Tc 9c 3c from being different. /// This function is public to make some unit-tests. /// </summary> public static CardSet ExtractFlush(CardSet hand, int maxHandSize) { int handSize = hand.CountCards(); uint half = (uint)hand.bits; _suits[0] = (half & 0xFFFF); _suits[1] = (half >> 16); half = (uint)(hand.bits >> 32); _suits[2] = (half & 0xFFFF); _suits[3] = (half >> 16); for (int i = 0; i < 4; ++i) { int suitCount = CountBits.Count(_suits[i]); if (suitCount + (maxHandSize - handSize) >= 5) { // Flush is possible // Preserve the 5 highest cards. uint bit = 0x00000001; while (suitCount > 5) { if ((_suits[i] & bit) != 0) { suitCount--; _suits[i] &= ~(bit); } bit <<= 1; } } else { // Flush is impossible, delete the cards. _suits[i] = 0; } } CardSet result = CardSet.Empty; for (int i = 0; i < 4; ++i) { result.bits |= (((UInt64)_suits[i]) << (i * 16)); } return(result); }
private void FillFinalHands(State state, CardSet cards) { for (int c = 0; c < 52; ++c) { if (state.Table[c] != 0) { // Already done. continue; } CardSet nextCard = StdDeck.Descriptor.CardSets[c]; if (nextCard.IsIntersectingWith(cards)) { continue; } CardSet finalHand = cards | nextCard; Debug.Assert(finalHand.CountCards() == _maxHandSize); UInt32 handRank = CardSetEvaluator.Evaluate(ref finalHand); state.Table[c] = (Int32)handRank; } }
private void VerifyCombinationParam(int [] cards, int param) { CardSet cs = StdDeck.Descriptor.GetCardSet(cards); Assert.AreEqual(_combinationsCount, param); _combinationsCount1++; Assert.IsFalse(cs.IsIntersectingWith(_dead)); Assert.IsTrue(cs.Contains(_shared)); CardSet uniqueCs = new CardSet { bits = cs.bits & (~_shared.bits) }; Assert.AreEqual(_enumCount, uniqueCs.CountCards()); // Use the fact that CardEnum generate masks in ascending order to check uniqueness if (_enumCount > 0) { Assert.Greater(uniqueCs.bits, _lastCs1); } _lastCs1 = uniqueCs.bits; }
public static Result CalculateNoVerify(CardSet[] csRange1, CardSet[] csRange2) { UInt64 totalValue = 0; uint count = 0; NormSuit ns = new NormSuit(); Dictionary <CardSet, UInt32> knonwValues = new Dictionary <CardSet, UInt32>(); foreach (CardSet cs1 in csRange1) { foreach (CardSet cs2 in csRange2) { if (cs1.IsIntersectingWith(cs2)) { continue; } CardSet union = ns.Convert(cs1); union.UnionWith(ns.Convert(cs2)); ns.Reset(); Debug.Assert(union.CountCards() == 4); UInt32 knownValue; if (!knonwValues.TryGetValue(union, out knownValue)) { int[] h1 = StdDeck.Descriptor.GetIndexesAscending(cs1).ToArray(); int[] h2 = StdDeck.Descriptor.GetIndexesAscending(cs2).ToArray(); knownValue = CalculateMatchupValue(h1, h2); knonwValues.Add(union, knownValue); } totalValue += knownValue; count++; } } Result r = new Result(); r.Equity = (float)totalValue / count / _boardsCount / 2; r.Count = count; return(r); }
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); }
bool FinalizeDeal(ref string currentDeal) { if (currentDeal == "") { return true; } if (_gameState.IsPlayerActing(_position)) { ShowMessage("Is's agents turn"); return false; } List<Ak> allowedActions = _gameState.GetAllowedActions(GameDef); if (!allowedActions.Contains(Ak.d)) { ShowMessage(string.Format("Wrong action: 'd', expected: '{0}'", ActionKindListToString(allowedActions))); return false; } CardSet cs = StdDeck.Descriptor.GetCardSet(currentDeal); int dealRound = _gameState.Round +1; int expectedCardsCount = dealRound == 0 ? GameDef.PrivateCardsCount[dealRound] : GameDef.SharedCardsCount[dealRound]; if (cs.CountCards() != expectedCardsCount) { ShowMessage(string.Format("Wrong cards count: {0}, expected: {1}", cs.CountCards(), expectedCardsCount)); return false; } if(cs.IsIntersectingWith(_dealtCards)) { ShowMessage(string.Format("Some of cards {0} are already dealt", currentDeal)); return false; } _dealtCards |= cs; PokerAction pa = new PokerAction {Kind = Ak.d, Cards = currentDeal}; currentDeal = ""; if (_gameState.Round == -1) { PokerAction oppPrivateDeal = new PokerAction { Kind = Ak.d, Cards = "" }; if (_position == 0) { pa.Position = 0; oppPrivateDeal.Position = 1; _gameRecord.Actions.Add(pa); _gameRecord.Actions.Add(oppPrivateDeal); } else { pa.Position = 1; oppPrivateDeal.Position = 0; _gameRecord.Actions.Add(oppPrivateDeal); _gameState.UpdateByAction(oppPrivateDeal, GameDef); _gameRecord.Actions.Add(pa); } _gameState.UpdateByAction(_gameRecord.Actions[_gameRecord.Actions.Count - 2], GameDef); _gameState.UpdateByAction(_gameRecord.Actions[_gameRecord.Actions.Count - 1], GameDef); } else { pa.Position = -1; _gameRecord.Actions.Add(pa); _gameState.UpdateByAction(pa, GameDef); } return true; }
/// <summary> /// Returns an array containing enumerated combinations. /// </summary> public static CardSet[] Combin(DeckDescriptor deckDescr, int count, CardSet sharedCards, CardSet deadCards) { CardSet unused = deadCards | sharedCards; int combCount = (int)EnumAlgos.CountCombin(deckDescr.Size - unused.CountCards(), count); CombinArrayParams p = new CombinArrayParams(); p.arr = new CardSet[combCount]; Combin(deckDescr, count, sharedCards, deadCards, OnCombinArray, p); return(p.arr); }