// this is used to recursively place the missing Mines into the available boxes for the probability line private List <ProbabilityLine> DistributeMissingMines(ProbabilityLine pl, NextWitness nw, int missingMines, int index) { //console.log("Distributing " + missingMines + " missing mines to box " + nw.newBoxes[index].uid); this.recursions++; if (this.recursions % 100000 == 0) { information.Write("Solution Counter recursision = " + recursions); } List <ProbabilityLine> result = new List <ProbabilityLine>(); // if there is only one box left to put the missing mines we have reach the end of this branch of recursion if (nw.GetNewBoxes().Count - index == 1) { // if there are too many for this box then the probability can't be valid if (nw.GetNewBoxes()[index].GetMaxMines() < missingMines) { //console.log("Abandon (1)"); return(result); } // if there are too few for this box then the probability can't be valid if (nw.GetNewBoxes()[index].GetMinMines() > missingMines) { //console.log("Abandon (2)"); return(result); } // if there are too many for this game then the probability can't be valid if (pl.GetMineCount() + missingMines > this.maxTotalMines) { //console.log("Abandon (3)"); return(result); } // otherwise place the mines in the probability line pl.SetMineBoxCount(nw.GetNewBoxes()[index].GetUID(), new BigInteger(missingMines)); pl.SetMineCount(pl.GetMineCount() + missingMines); result.Add(pl); //console.log("Distribute missing mines line after " + pl.mineBoxCount); return(result); } // this is the recursion int maxToPlace = Math.Min(nw.GetNewBoxes()[index].GetMaxMines(), missingMines); for (int i = nw.GetNewBoxes()[index].GetMinMines(); i <= maxToPlace; i++) { ProbabilityLine npl = ExtendProbabilityLine(pl, nw.GetNewBoxes()[index], i); List <ProbabilityLine> r1 = DistributeMissingMines(npl, nw, missingMines - i, index + 1); result.AddRange(r1); } return(result); }
// create a new probability line by taking the old and adding the mines to the new Box private ProbabilityLine ExtendProbabilityLine(ProbabilityLine pl, Box newBox, int mines) { //console.log("Extended probability line: Adding " + mines + " mines to box " + newBox.uid); //console.log("Extended probability line before" + pl.mineBoxCount); ProbabilityLine result = new ProbabilityLine(this.boxes.Count); result.SetMineCount(pl.GetMineCount() + mines); result.CopyMineBoxCount(pl); result.SetMineBoxCount(newBox.GetUID(), new BigInteger(mines)); //console.log("Extended probability line after " + result.mineBoxCount); return(result); }
// calculate how many ways this solution can be generated and roll them into one private void MergeLineProbabilities(ProbabilityLine npl, ProbabilityLine pl) { BigInteger solutions = 1; for (int i = 0; i < this.boxes.Count; i++) { solutions = solutions * (BigInteger)SMALL_COMBINATIONS[this.boxes[i].GetTiles().Count][(int)pl.GetMineBoxCount(i)]; } npl.SetSolutionCount(npl.GetSolutionCount() + solutions); for (int i = 0; i < this.boxes.Count; i++) { if (this.mask[i]) // if this box has been involved in this solution - if we don't do this the hash gets corrupted by boxes = 0 mines because they weren't part of this edge { npl.SetMineBoxCount(i, npl.GetMineBoxCount(i) + pl.GetMineBoxCount(i) * solutions); } } }
// this combines newly generated probabilities with ones we have already stored from other independent sets of witnesses private void CombineProbabilities() { List <ProbabilityLine> result = new List <ProbabilityLine>(); if (this.workingProbs.Count == 0) { information.Write("working probabilites list is empty!!"); return; } // see if we can find a common divisor BigInteger hcd = workingProbs[0].GetSolutionCount(); foreach (ProbabilityLine pl in workingProbs) { hcd = BigInteger.GreatestCommonDivisor(hcd, pl.GetSolutionCount()); } foreach (ProbabilityLine pl in heldProbs) { hcd = BigInteger.GreatestCommonDivisor(hcd, pl.GetSolutionCount()); } information.Write("Greatest Common Divisor is " + hcd); solutionCountMultiplier = solutionCountMultiplier * hcd; int mineCountMin = workingProbs[0].GetMineCount() + heldProbs[0].GetMineCount(); // shrink the window edgeMinesMinLeft = edgeMinesMinLeft - workingProbs[0].GetMineCount(); edgeMinesMaxLeft = edgeMinesMaxLeft - workingProbs[workingProbs.Count - 1].GetMineCount(); foreach (ProbabilityLine pl in workingProbs) { BigInteger plSolCount = pl.GetSolutionCount() / hcd; foreach (ProbabilityLine epl in heldProbs) { // if the mine count can never reach the lower cuttoff then ignore it if (pl.GetMineCount() + epl.GetMineCount() + edgeMinesMaxLeft < this.mineCountLowerCutoff) { continue; } // if the mine count will always be pushed beyonf the upper cuttoff then ignore it if (pl.GetMineCount() + epl.GetMineCount() + edgeMinesMinLeft > this.mineCountUpperCutoff) { continue; } ProbabilityLine newpl = new ProbabilityLine(this.boxes.Count); newpl.SetMineCount(pl.GetMineCount() + epl.GetMineCount()); BigInteger eplSolCount = epl.GetSolutionCount() / hcd; newpl.SetSolutionCount(pl.GetSolutionCount() * eplSolCount); for (int k = 0; k < this.boxes.Count; k++) { BigInteger w1 = pl.GetMineBoxCount(k) * eplSolCount; BigInteger w2 = epl.GetMineBoxCount(k) * plSolCount; newpl.SetMineBoxCount(k, w1 + w2); } result.Add(newpl); } } //Console.WriteLine("Solution multiplier is " + solutionCountMultiplier); this.heldProbs.Clear(); // if result is empty this is an impossible position if (result.Count == 0) { Console.WriteLine("Impossible position encountered"); return; } if (result.Count == 1) { heldProbs.AddRange(result); return; } // sort into mine order result.Sort(); // and combine them into a single probability line for each mine count int mc = result[0].GetMineCount(); ProbabilityLine npl = new ProbabilityLine(this.boxes.Count); npl.SetMineCount(mc); int startMC = mc; foreach (ProbabilityLine pl in result) { if (pl.GetMineCount() != mc) { this.heldProbs.Add(npl); mc = pl.GetMineCount(); npl = new ProbabilityLine(this.boxes.Count); npl.SetMineCount(mc); } npl.SetSolutionCount(npl.GetSolutionCount() + pl.GetSolutionCount()); for (int j = 0; j < this.boxes.Count; j++) { npl.SetMineBoxCount(j, npl.GetMineBoxCount(j) + pl.GetMineBoxCount(j)); } } this.heldProbs.Add(npl); }