Пример #1
0
        private IList<Molecule> getCombinationsOfTwo(IList<Tile> potentialReactionTiles, Tile userClickedTile)
        {
            IList<Molecule> toReturn = new List<Molecule>();
            Molecule combo;

            for (int i = 0; i < potentialReactionTiles.Count; i++)
            {
                for (int j = i + 1; j < potentialReactionTiles.Count; j++)
                {
                    combo = new Molecule();
                    combo.AtomTiles.Add(potentialReactionTiles[i]);
                    combo.AtomTiles.Add(potentialReactionTiles[j]);

                    // Bug-fix and optimization: only molecules with the user-clicked tile are legit.
                    if (combo.AtomTiles.Contains(userClickedTile))
                    {
                        toReturn.Add(combo);
                    }
                }
            }

            return toReturn;
        }
Пример #2
0
        private IList<Molecule> getIncrementalCombinations(IList<Tile> potentialReactionTiles, IList<Molecule> previousSet)
        {
            IList<Molecule> toReturn = new List<Molecule>();

            // This thread needs to be more sleepy. To prevent lag.
            int throttleCount = 0;
            const int THROTTLE_AFTER_COUNT = 10;

            // Trick: if we are generating combos of five, and we just did twos, we have:
            // AB, AC, AD, BC, BD, BE, CD, CE
            // We now take each of these, and add whatever's after the last one
            // eg. for AB, we look at: C, D, E to make ABC, ABD, ABE!
            // BRILLIANT, I tell you!!
            foreach (Molecule m in previousSet)
            {
                Tile lastTile = m.AtomTiles[m.AtomTiles.Count - 1];
                IList<Tile> validTiles = new List<Tile>();

                for (int i = potentialReactionTiles.IndexOf(lastTile) + 1; i < potentialReactionTiles.Count; i++)
                {
                    validTiles.Add(potentialReactionTiles[i]);
                }

                foreach (Tile t in validTiles)
                {
                    Molecule newbie = new Molecule();

                    foreach (Tile at in m.AtomTiles)
                    {
                        newbie.AtomTiles.Add(at);
                    }

                    newbie.AtomTiles.Add(t);
                    toReturn.Add(newbie);
                    throttleCount++;
                    throttleCount %= THROTTLE_AFTER_COUNT;
                    if (throttleCount == THROTTLE_AFTER_COUNT - 1)
                    {
                        Thread.Sleep(10);
                    }
                }
            }

            return toReturn;
        }
Пример #3
0
        // It's complicated. We use two collections: one that looks at ALL the atoms we see, ever,
        // and one that looks at only the atoms we've seen so far -- the latter back-pedals when
        // we run out of adjacencies, and the former perseveres. This covers all kinds of cases,
        // like (* indicates last atom placed):
        // B Fl
        // B Fl
        //   Fl*
        // ... which is covered by back-pedalling only, and like:
        // B Cl* Cl Cl
        // ... which is covered by looking at the total only.
        private IList<Molecule> calculateReactionsUsingBestFirstSearch(IList<Tile> potentialReactionTiles, Tile centerTile, IList<Tile> foundSoFarInPath, IList<Tile>foundSoFarInTotal)
        {
            // These IFs cover a tricky case where we search exhaustively and don't find
            // a molecule, then when backtracking, backtrack into something we've seen
            // already. We shouldn't add a tile twice, and this fixes the bug that does that
            // (visible in puzzle one -- it adds the bottom-most Fl twice (6, 3).)
            if (!foundSoFarInPath.Contains(centerTile))
            {
                foundSoFarInPath.Add(centerTile);
            }

            if (!foundSoFarInTotal.Contains(centerTile))
            {
                foundSoFarInTotal.Add(centerTile);
            }

            Molecule m1 = new Molecule();
            foreach (Tile t in foundSoFarInPath)
            {
                m1.AtomTiles.Add(t);
            }

            if (m1.NetCharge == 0)
            {
                // Base case: we're net zero!
                List<Molecule> toReturn = new List<Molecule>();
                toReturn.Add(m1);
                return toReturn;
            }

            Molecule m2 = new Molecule();
            foreach (Tile t in foundSoFarInTotal)
            {
                m2.AtomTiles.Add(t);
            }

            if (m2.NetCharge == 0)
            {
                // Base case: we're net zero!
                List<Molecule> toReturn = new List<Molecule>();
                toReturn.Add(m2);
                return toReturn;
            }

            // Recursive case: keep looking.
            // Find adjacent molecules
            IList<Tile> adjacents = potentialReactionTiles.Where(t => TowerUtils.DistanceBetweenPoints(t.X, t.Y, centerTile.X, centerTile.Y) == 1).ToList();

            // Exclude tiles we already saw. Use current path, for back-pedalling.
            adjacents = adjacents.Where(t => !foundSoFarInPath.Contains(t) && !foundSoFarInTotal.Contains(t)).ToList();

            // Sort by |my valence + their valence|;
            adjacents = adjacents.OrderBy(t => t, new OrderTilesByElectronegativityWithAtomComparer(centerTile.Atom)).ToList();

            // Base case: no adjacents.
            if (adjacents.Count == 0)
            {
                return new List<Molecule>();
            }
            else
            {
                // Take the best, and move on
                foreach (Tile adj in adjacents)
                {
                    // Copy foundSoFar so we can return up the stack and keep looking on
                    // a different path. Without screwing up our "found so far" data.
                    IList<Tile> foundDupe = new List<Tile>();
                    foreach (Tile t in foundSoFarInPath)
                    {
                        foundDupe.Add(t);
                    }

                    IList<Molecule> toReturn = this.calculateReactionsUsingBestFirstSearch(potentialReactionTiles, adj, foundDupe, foundSoFarInTotal);
                    if (toReturn.Count > 0)
                    {
                        return toReturn;
                    }
                }

                // Found nothing.
                return new List<Molecule>();
            }
        }