// return any witness which hasn't been processed
        private NextWitness FindFirstWitness()
        {
            BoxWitness excluded = null;

            foreach (BoxWitness boxWit in this.boxWitnesses)
            {
                if (!boxWit.IsProcessed())
                {
                    return(new NextWitness(boxWit));
                }
                else if (!boxWit.IsProcessed())
                {
                    excluded = boxWit;
                }
            }
            if (excluded != null)
            {
                return(new NextWitness(excluded));
            }

            return(null);
        }
        // look for the next witness to process
        private NextWitness FindNextWitness(NextWitness prevWitness)
        {
            // flag the last set of details as processed
            prevWitness.GetBoxWitness().SetProcessed(true);

            foreach (Box newBox in prevWitness.GetNewBoxes())
            {
                newBox.SetProcessed(true);
            }

            int        bestTodo    = 99999;
            BoxWitness bestWitness = null;

            // and find a witness which is on the boundary of what has already been processed
            foreach (Box b in this.boxes)
            {
                if (b.IsProcessed())
                {
                    foreach (BoxWitness w in b.GetBoxWitnesses())
                    {
                        if (!w.IsProcessed())
                        {
                            int todo = 0;
                            foreach (Box b1 in w.GetBoxes())
                            {
                                if (!b1.IsProcessed())
                                {
                                    todo++;
                                }
                            }
                            if (todo == 0)      // prioritise the witnesses which have the least boxes left to process
                            {
                                return(new NextWitness(w));
                            }
                            else if (todo < bestTodo)
                            {
                                bestTodo    = todo;
                                bestWitness = w;
                            }
                        }
                    }
                }
            }

            if (bestWitness != null)
            {
                return(new NextWitness(bestWitness));
            }
            else
            {
                information.Write("Ending independent edge");
            }

            //independentGroups++;

            // since we have calculated all the mines in an independent set of witnesses we can crunch them down and store them for later

            // store the details for this edge
            StoreProbabilities();


            // get an unprocessed witness
            NextWitness nw = FindFirstWitness();

            if (nw != null)
            {
                information.Write("Starting a new independent edge");
            }

            // If there is nothing else to process then either do the local clears or calculate the probabilities
            if (nw == null)
            {
                edgeStore.Sort(EdgeStore.SortByLineCount);

                AnalyseAllEdges();

                long start = DateTime.Now.Ticks;
                foreach (EdgeStore edgeDetails in edgeStore)
                {
                    workingProbs = edgeDetails.data;
                    CombineProbabilities();
                }
                information.Write("Combined all edges in " + (DateTime.Now.Ticks - start) + " ticks");
            }

            // return the next witness to process
            return(nw);
        }
        public SolutionCounter(SolverInfo information, List <SolverTile> allWitnesses, List <SolverTile> allWitnessed, int squaresLeft, int minesLeft)
        {
            this.information = information;

            this.witnessed = allWitnessed;

            // constraints in the game
            this.minesLeft     = minesLeft;
            this.tilesLeft     = squaresLeft;
            this.tilesOffEdge  = squaresLeft - allWitnessed.Count;  // squares left off the edge and unrevealed
            this.minTotalMines = minesLeft - this.tilesOffEdge;     //we can't use so few mines that we can't fit the remainder elsewhere on the board
            this.maxTotalMines = minesLeft;

            this.mineCountUpperCutoff = minesLeft;
            this.mineCountLowerCutoff = minTotalMines;

            information.Write("Tiles off edge " + tilesOffEdge);

            //this.boxProb = [];  // the probabilities end up here

            // generate a BoxWitness for each witness tile and also create a list of pruned witnesses for the brute force search
            int pruned = 0;

            foreach (SolverTile wit in allWitnesses)
            {
                BoxWitness boxWit = new BoxWitness(information, wit);

                // if the witness is a duplicate then don't store it
                bool duplicate = false;
                foreach (BoxWitness w in this.boxWitnesses)
                {
                    if (w.Equivalent(boxWit))
                    {
                        //if (boardState.getWitnessValue(w) - boardState.countAdjacentConfirmedFlags(w) != boardState.getWitnessValue(wit) - boardState.countAdjacentConfirmedFlags(wit)) {
                        //    boardState.display(w.display() + " and " + wit.display() + " share unrevealed squares but have different mine totals!");
                        //    validWeb = false;
                        //}
                        duplicate = true;
                        break;
                    }
                }
                if (!duplicate)
                {
                    this.prunedWitnesses.Add(boxWit);
                }
                else
                {
                    pruned++;
                }
                this.boxWitnesses.Add(boxWit);  // all witnesses are needed for the probability engine
            }
            information.Write("Pruned " + pruned + " witnesses as duplicates");
            information.Write("There are " + this.boxWitnesses.Count + " Box witnesses");

            // allocate each of the witnessed squares to a box
            int uid = 0;

            foreach (SolverTile tile in this.witnessed)
            {
                // for each adjacent tile see if it is a witness
                int count = 0;
                //foreach (SolverTile adjTile in information.GetAdjacentTiles(tile)) {
                //    if (information.GetWitnesses().Contains(adjTile)) {
                //        count++;
                //    }
                //}

                // count how many adjacent witnesses the tile has
                foreach (SolverTile tile1 in allWitnesses)
                {
                    if (tile.IsAdjacent(tile1))
                    {
                        count++;
                    }
                }

                // see if the witnessed tile fits any existing boxes
                bool found = false;
                foreach (Box box in this.boxes)
                {
                    if (box.Fits(tile, count))
                    {
                        box.Add(tile);
                        boxLookup.Add(tile, box);   // add this to the lookup
                        found = true;
                        break;
                    }
                }

                // if not found create a new box and store it
                if (!found)
                {
                    Box box = new Box(this.boxWitnesses, tile, uid++);
                    this.boxes.Add(box);
                    boxLookup.Add(tile, box);   // add this to the lookup
                }
            }

            // calculate the min and max mines for each box
            foreach (Box box in this.boxes)
            {
                box.Calculate(this.minesLeft);
                //console.log("Box " + box.tiles[0].asText() + " has min mines = " + box.minMines + " and max mines = " + box.maxMines);
            }

            // Report how many boxes each witness is adjacent to
            foreach (BoxWitness boxWit in this.boxWitnesses)
            {
                information.Write("Witness " + boxWit.GetTile().AsText() + " is adjacent to " + boxWit.GetBoxes().Count + " boxes and has " + boxWit.GetMinesToFind() + " mines to find");
            }
        }