public ApproximationResults Approximate(CardCollection deadCards, params Range[] ranges) { var allApprox = ranges.Select(r => r.SelectedHoleCardBinaries .Where(b => !_cards.ContainsSome(b) && (deadCards == null || !deadCards.ContainsSome(b)))) .CartesianProduct() .Select(s => Approximate(s.ToArray(), deadCards, trials: 100)) .ToList(); var players = new List <float>(new float[ranges.Length]); float splitProb = 0f; foreach (var approx in allApprox) { splitProb += approx.SplitProbability; for (int p = 0; p < ranges.Length; p++) { players[p] += approx[p].Equity; } } players.ForEach(p => p /= allApprox.Count); splitProb /= allApprox.Count; return(new ApproximationResults(players.Select((eq, i) => new ApproximationResults.PlayerResults(i, eq, 3UL)), splitProb)); // Todo: add ranges to result }
/// <summary> /// A collection of all possible hole cards which include one or more cards from a card collection with optional dead cards. /// </summary> /// <param name="card"></param> /// <param name="deadCards">Dead cards. If no dead cards needed leave it null</param> public static IEnumerable <HoleCards> Include(CardCollection includedCards, CardCollection deadCards = null) => Include((ulong)includedCards, (ulong)deadCards);
public bool ContainsSome(CardCollection collection) { return((Binary & collection.Binary) != 0UL); }
public bool Contains(CardCollection collection) { return((Binary & collection.Binary) == collection.Binary); }
public void Exclude(CardCollection collection) { Binary &= ~collection.Binary; }
public void Include(CardCollection collection) { Binary |= collection.Binary; }
public static IEnumerable <CardCollection> Include(int cardAmount, CardCollection includedCards, CardCollection excludedCards = null) { return(Include(cardAmount, includedCards.Binary, excludedCards.Binary).Select(cc => new CardCollection(cc))); //return All(cardAmount, excludedCards).Where(cc => cc.Contains(includedCards)); }
public static IEnumerable <CardCollection> All(int cardAmount, CardCollection excludedCards = null) { return(All(cardAmount, (ulong)excludedCards).Select(cc => new CardCollection(cc))); }
/// <summary> /// Get the notation of a card collection /// </summary> /// <returns>String representation of the card collection, e.g. "Ac Th 6s "</returns> public static string GetNotation(CardCollection collection) { return(GetNotation(collection.Binary)); }
/// <summary> /// Creates a random board. /// </summary> /// <param name="progress">The progression of the board. Specifies how many cards are on the board.</param> /// <param name="deadCards">Dead cards. Specifies all cards that can't be contained on the board such as hole cards or boxed cards.</param> /// <returns>A random board according to the parameters</returns> public static Board Random(Progression progress = Progression.River, CardCollection deadCards = null) { return(new Board(CardCollection.RandomAsUlong((int)progress, deadCards))); }
internal void DealRandomCards(Progression targetState, ulong deadCards = 0UL) { _cards.Include(CardCollection.RandomAsUlong(targetState - Progress, deadCards | _cards.Binary)); }
/// <summary> /// Calculates equity for two or more hole cards on the board by checking all possible outcomes. No splits considered /// </summary> /// <param name="holeCards">The list of hole cards to evaluate the equity for</param> /// <returns>A list of player approximation results</returns> public ApproximationResults ApproximateExact(CardCollection deadCards, params HoleCards[] holeCards) => ApproximateExact(deadCards, Array.ConvertAll(holeCards, hc => (ulong)hc));
public void ApproximateLive(Action <IEnumerable <float>, float> updateLiveResults, CardCollection deadCards, CancellationToken?cancellationToken, params Range[] ranges) { var rnd = new Random(); var nativeRanges = ranges.Select(r => r.SelectedHoleCardBinaries.Where(b => !_cards.ContainsSome(b) && (!deadCards?.ContainsSome(b) ?? true)).ToList()).ToList(); cancellationToken?.ThrowIfCancellationRequested(); ulong[]? localHoleCards = new ulong[nativeRanges.Count]; ulong allLocalHoleCards; float[]? totalEquity = new float[nativeRanges.Count]; float splitEquity = 0f; int firstSelectedPlayer = 0; int skippedSituations = 0; bool skipSituation = false; for (int i = 0; i < Int32.MaxValue; i++) { // Stop if requested cancellationToken?.ThrowIfCancellationRequested(); allLocalHoleCards = 0; // Select random hole cards from each player to test // Do not select from the same player first every time, // the equities can be affected by this (e.g. AA-KK vs AA-KK vs AA-KK) int j = firstSelectedPlayer; do { var validHoleCards = nativeRanges[j].Where(hc => (hc & allLocalHoleCards) == 0).ToList(); if (!validHoleCards.Any()) { if (skippedSituations > (i < 1000 ? 950 : i * 0.95f)) { throw new NashException("Ranges are too narrow. Please adjust."); } skipSituation = true; break; } localHoleCards[j] = validHoleCards[rnd.Next(validHoleCards.Count)]; allLocalHoleCards |= localHoleCards[j]; // if the last player is reached wrap around to the first one if (++j >= nativeRanges.Count) { j = 0; } } while (j != firstSelectedPlayer); // skip this situation if not all hole cards were chosen // try with same first player to not influence the results if (skipSituation) { skippedSituations++; skipSituation = false; continue; } // update first player for next run if (++firstSelectedPlayer >= nativeRanges.Count) { firstSelectedPlayer = 0; } // Add to total equity var results = Approximate(localHoleCards, deadCards, trials: 1000); for (int k = 0; k < nativeRanges.Count; k++) { totalEquity[k] += results[k].Equity; } splitEquity += results.SplitProbability; // Update live results if (i % 10 == 0) { int simulationCount = (i - skippedSituations + 1); updateLiveResults?.Invoke(totalEquity.Select(eq => Math.Min(eq / simulationCount, 1f)), Math.Min(splitEquity / simulationCount, 1f)); } } }
public Board() { _cards = new CardCollection(); }
/// <summary> /// Get all possible boards on a specific street and specific included cards /// </summary> /// <param name="progress">The street of the board</param> /// <param name="includedCards">Every board must contain all of these cards</param> /// <param name="deadCards">All boards containing one or more cards from this parameter will be excluded</param> /// <returns>A list of boards according to the parameters</returns> public static IEnumerable <Board> Include(Progression progress, CardCollection includedCards, CardCollection deadCards = null) { #if DEBUG if (includedCards.Count > (int)progress) { throw new ArgumentException("There can't be more cards included than are dealt on the current progression of the board.", nameof(includedCards)); } #endif return(Include((int)progress, includedCards, deadCards).Select(cc => new Board(cc))); }
public static IEnumerable <Board> All(Progression progress, CardCollection deadCards = null) => All((int)progress, deadCards).Select(cc => new Board(cc));