/// <summary> /// Shuffles count elements in the given sequnce starting from start. /// The elements below start are untouched. /// </summary> public static void Shuffle(Random rng, int [] sequence, int start, int count) { int end = start + count; for (int i = start; i < end; ++i) { int rndIdx = rng.Next(i, sequence.Length); ShortSequence.Swap(ref sequence[rndIdx], ref sequence[i]); } }
public double Solve(double a, double b, double epsilon, bool verifyFunctionShape) { if (a > b) { ShortSequence.Swap(ref a, ref b); } double x1 = b - (b - a) / GR; double x2 = a + (b - a) / GR; double f1 = F(x1); double f2 = F(x2); double fStart = 0, fEnd = 0; if (verifyFunctionShape) { fStart = F(a); fEnd = F(b); if (!IsShapeCorrect(fStart, fEnd, f1) || !IsShapeCorrect(fStart, fEnd, f2)) { throw new ApplicationException("Wrong function shape"); } } for (;;) { if (b - a <= epsilon) { return((b + a) * 0.5); } if (f1 > f2) { // Replace a a = x1; x1 = x2; f1 = f2; x2 = a + (b - a) / GR; f2 = F(x2); if (verifyFunctionShape) { if (!IsShapeCorrect(fStart, fEnd, f2)) { throw new ApplicationException("Wrong function shape"); } } } else { // Replace b b = x2; x2 = x1; f2 = f1; x1 = b - (b - a) / GR; f1 = F(x1); if (verifyFunctionShape) { if (!IsShapeCorrect(fStart, fEnd, f1)) { throw new ApplicationException("Wrong function shape"); } } } Debug.Assert(FloatingPoint.AreEqual((b - a) / (x2 - a), GR, 1e-10)); Debug.Assert(FloatingPoint.AreEqual((b - a) / (b - x1), GR, 1e-10)); } }
/// <summary> /// Generate an internal chance tree by MC sampling. /// </summary> /// <param name="chanceAbstractions">An array of chance abstractions</param> /// <param name="areAbstractionsEqual">If the absractions are equal, /// one MC sample will update multiple nodes of the chance tree.</param> /// <param name="samplesCount">Number of samples. If equal absractions are used, /// less MC samples will be actually done to reach the specified numbers of updates.</param> /// <param name="rngSeed">RNG seed.</param> /// <param name="feedback">User feedback callback.</param> /// <returns></returns> public static Tree Generate(GameDefinition gd, IChanceAbstraction[] chanceAbstractions, bool areAbstractionsEqual, long samplesCount, int rngSeed, FeedbackDelegate feedback) { if (chanceAbstractions.Length != 2) { throw new ArgumentOutOfRangeException("Only heads up games are supported now"); } McDealer mcDealer = new McDealer(gd, rngSeed); int [][] hands = new int[chanceAbstractions.Length][].Fill(i => new int[mcDealer.HandSize]); int[] handSizes = gd.GetHandSizes(); Tree tree = new Tree { PlayersCount = chanceAbstractions.Length, RoundsCount = gd.RoundsCount, SourceInfo = GetSourceInfo(gd, chanceAbstractions) }; Node root = tree.Root; byte[] abstrCards = new byte[gd.RoundsCount * chanceAbstractions.Length]; uint[] ranks = new uint[chanceAbstractions.Length]; Int64 samplesDone; int updateCount = areAbstractionsEqual ? 2 : 1; for (samplesDone = 0; samplesDone < samplesCount; samplesDone += updateCount) { if (feedback != null && (samplesDone % FEEDBACK_PERIOD == 0)) { if (!feedback(samplesDone)) { break; } } mcDealer.NextDeal(hands); gd.GameRules.Showdown(gd, hands, ranks); int c = 0; for (int r = 0; r < gd.RoundsCount; ++r) { for (int p = 0; p < chanceAbstractions.Length; ++p) { int abstrCard = chanceAbstractions[p].GetAbstractCard(hands[p], handSizes[r]); if (abstrCard < byte.MinValue || abstrCard > byte.MaxValue) { throw new ApplicationException(string.Format("Abstract card {0} out of byte range", abstrCard)); } abstrCards[c++] = (byte)abstrCard; } } for (int u = 0; ;) { LeafT[] leaves = tree.GetLeavesByCards(abstrCards); int lastCard = abstrCards[abstrCards.Length - 1]; leaves[lastCard].Update(ranks); if (++u == updateCount) { break; } // If the abstractions are equal, we can update another node // by permuting cards and results // Note: implemented for 2 players only for (c = 0; c < abstrCards.Length; c += 2) { ShortSequence.Swap(ref abstrCards[c], ref abstrCards[c + 1]); } ShortSequence.Swap(ref ranks[0], ref ranks[1]); } } tree.SamplesCount = (UInt64)samplesDone; tree.UpdateDescription(); return(tree); }