Esempio n. 1
0
        public void Work(int id, Random rnd,
                         XElement puzzledb,
                         string filepath,
                         List <BoardData> records,
                         List <PatternData> patterns,
                         List <RejectData> rejects,
                         int maxNoMove,
                         int minMove,
                         int maxMove,
                         int minScore,
                         int idleFold,
                         int maxSolutionSeconds)
        {
            List <ElementDetails> newdna  = new List <ElementDetails>();
            PatternData           pattern = patterns.ElementAt(rnd.Next(patterns.Count()));

            char[] chrs = pattern.DNA.ToCharArray();
            for (int i = 0; i < chrs.Length; i++)
            {
                char c = chrs[i];
                newdna.Add(Element.CharToElementDetails(c));
            }
            ElementDetails[] dna = newdna.ToArray();

            Board board = new Board((byte)rnd.Next(pattern.MinWidth, pattern.MaxWidth), (byte)rnd.Next(pattern.MinHeight, pattern.MaxHeight));

            board.Randomize(rnd, pattern, dna);
            Board     original = new Board(board);
            ulong     hash     = original.FNV1aHash();
            BoardData existing = records.Where(x => x.Hash == hash).FirstOrDefault();

            if (existing != null)
            {
                //Console.WriteLine($"(Task {id}) Board already exists (hash: {hash}).");
                return;
            }
            RejectData rejected = rejects.Where(x => x.Hash == hash).FirstOrDefault();

            if (rejected != null)
            {
                //Console.WriteLine($"(Task {id}) Board already rejected (hash: {hash}).");
                return;
            }

            for (int i = 0; i < idleFold; i++)
            {
                board.Fold();
            }
            board.Place(new Element(Element.Player), board.StartY, board.StartX);

            //Console.WriteLine($"(Task {id}) Origin:");
            //original.Dump();
            //Console.WriteLine($"\n(Task {id}) Idle folded:");
            //board.Dump();
            Solution s = Solver.Solve(id, board, new TimeSpan(0, 0, maxSolutionSeconds), maxMove, 1f);

            if (s != null && s.Bound < minMove)
            {
                //Console.WriteLine($"(Task {id}) Move under the minimum ({minMove}), discarding.");
                puzzledb.Element("Rejects").Add(
                    new XElement("Reject",
                                 new XElement("Hash", hash),
                                 new XElement("Reason", "MinMove")
                                 ));
                lock (puzzledb) {
                    puzzledb.Save(filepath);
                }
                lock (rejects) {
                    rejects.Add(new RejectData {
                        Hash = hash
                    });
                }
                s = null;
            }
            else
            if (s == null && Solver.LastSearchResult == Solver.TIMEDOUT)
            {
                //Console.WriteLine($"(Task {id}) Timeout, couldn't verify board. Discarding.");
                puzzledb.Element("Rejects").Add(
                    new XElement("Reject",
                                 new XElement("Hash", hash),
                                 new XElement("Reason", "Timeout with no solution"),
                                 new XElement("Data", original.ToString())
                                 ));
                lock (puzzledb) {
                    puzzledb.Save(filepath);
                }
                lock (rejects) {
                    rejects.Add(new RejectData {
                        Hash = hash
                    });
                }
                s = null;
            }
            else
            if (s == null)
            {
                //Console.WriteLine($"(Task {id}) No Solution found. Discarding.");
                puzzledb.Element("Rejects").Add(
                    new XElement("Reject",
                                 new XElement("Hash", hash),
                                 new XElement("Reason", "Unsolveable")
                                 ));
                lock (puzzledb) {
                    puzzledb.Save(filepath);
                }
                lock (rejects) {
                    rejects.Add(new RejectData {
                        Hash = hash
                    });
                }
            }

            if (s != null)
            {
                //Console.WriteLine($"(Task {id}) Trying to find better solutions.");
                float first = s.Bound;
                do
                {
                    Solver.Tries++;
                    Solution better = Solver.Solve(id, board, new TimeSpan(0, 0, maxSolutionSeconds), s.Bound, (s.Bound - 1) / first);
                    if (better != null && better.Bound < s.Bound)
                    {
                        //Console.WriteLine($"(Task {id}) Better solution found: {better.Bound}");
                        s = better;
                        if (s.Bound < minMove)
                        {
                            //Console.WriteLine($"(Task {id}) Move under the minimum ({minMove}), discarding.");
                            s = null;
                            break;
                        }
                    }
                    else
                    if (better == null && Solver.LastSearchResult == Solver.TIMEDOUT)
                    {
                        //Console.WriteLine($"(Task {id}) Timeout, couldn't verify board. Discarding.");
                        puzzledb.Element("Rejects").Add(
                            new XElement("Reject",
                                         new XElement("Hash", hash),
                                         new XElement("Width", original.ColCount),
                                         new XElement("Height", original.RowCount),
                                         new XElement("StartX", original.StartX),
                                         new XElement("StartY", original.StartY),
                                         new XElement("ExitX", original.ExitX),
                                         new XElement("ExitY", original.ExitY),
                                         new XElement("Reason", "Timeout while looking for a better solution"),
                                         new XElement("Idle", idleFold),
                                         new XElement("Data", original.ToString())
                                         ));
                        lock (puzzledb) {
                            puzzledb.Save(filepath);
                        }
                        lock (rejects) {
                            rejects.Add(new RejectData {
                                Hash = hash
                            });
                        }
                        s = null;
                        break;
                    }
                    else
                    {
                        //Console.WriteLine($"(Task {id}) No better solution, bailing.");
                        break;
                    }
                } while (true);
                if (s != null)
                {
                    XElement solution     = new XElement("Solution");
                    int      steps        = 0;
                    Board    prev         = null;
                    int      len          = s.Path[0].Data.Length;
                    int      diffTotal    = 0;
                    int      goalTotal    = 0;
                    int      mobBefore    = 0;
                    int      mobAfter     = 0;
                    int      fallingDelta = 0;
                    int      proximity    = 0;
                    foreach (Board b in s.Path)
                    {
                        var foldStr = b.ToString();
                        var fold    = new XElement("Fold", foldStr);
                        fold.SetAttributeValue("Move", b.NameMove());
                        int goals = b.Data.Where(x => x != null && x.Details == Element.Diamond).Count();
                        //fold.SetAttributeValue("Goals", goals);
                        goalTotal += goals;
                        var diffs = 0;
                        if (prev != null)
                        {
                            for (int i = 0; i < len; i++)
                            {
                                if (prev.Data[i].Details != b.Data[i].Details)
                                {
                                    diffs++;
                                }
                            }
                            fallingDelta += prev.Data.Count(x => x.Falling) - b.Data.Count(x => x.Falling);
                        }
                        diffTotal += diffs;
                        //fold.SetAttributeValue("Diffs", diffs);
                        //var ff = b.Data.Count(x => x.Falling);
                        //if (ff > 0)
                        //    fold.SetAttributeValue("Falling", ff);
                        //fold.SetAttributeValue("Space", b.Data.Count(x => x == null || x.Details == Element.Space));
                        var     moveOrder = new StringBuilder();
                        Boolean before    = true;
                        for (int i = 0; i < len; i++)
                        {
                            var details = b.Data[i].Details;
                            if (details.Mob)
                            {
                                if (i > 0 && b.Data[i - 1].Details == Element.Player)
                                {
                                    proximity++;
                                }
                                if (i < len - 1 && b.Data[i + 1].Details == Element.Player)
                                {
                                    proximity++;
                                }
                                if (i > b.ColCount && b.Data[i - b.ColCount].Details == Element.Player)
                                {
                                    proximity++;
                                }
                                if (i < b.ColCount - 1 && b.Data[i + b.ColCount].Details == Element.Player)
                                {
                                    proximity++;
                                }
                            }
                            if (details.Mob || details == Element.Boulder || details == Element.Diamond || details == Element.Player)
                            {
                                moveOrder.Append(details.Symbols[details.StartFacing]);
                                if (details != Element.Player)
                                {
                                    if (details.Mob)
                                    {
                                        if (before)
                                        {
                                            mobBefore++;
                                        }
                                        else
                                        {
                                            mobAfter++;
                                        }
                                    }
                                }
                                else
                                {
                                    before = false;
                                }
                            }
                        }
                        //if (proximity > 0)
                        //    fold.SetAttributeValue("Proximity", proximity);
                        //fold.SetAttributeValue("MoveOrder", moveOrder.ToString());

                        prev = b;
                        solution.Add(fold);
                        steps++;
                    }
                    fallingDelta = Math.Max(-10, fallingDelta * -1);
                    int score = ((int)Math.Ceiling((double)diffTotal / (s.Path.Count - 1)) * 10) + ((mobBefore / s.Path.Count) * 5) + ((mobAfter / s.Path.Count) * 2) + (fallingDelta * 5) + len + ((goalTotal / s.Path.Count) * 3) + (proximity * 12);
                    solution.SetAttributeValue("AvgDiff", (int)Math.Ceiling((double)diffTotal / (s.Path.Count - 1)));
                    solution.SetAttributeValue("AvgGoals", goalTotal / s.Path.Count);
                    solution.SetAttributeValue("AvgBefore", (mobBefore / s.Path.Count));
                    solution.SetAttributeValue("AvgAfter", (mobAfter / s.Path.Count));
                    solution.SetAttributeValue("FallingDelta", fallingDelta);
                    solution.SetAttributeValue("Proximity", proximity);
                    solution.SetAttributeValue("Score", score);
                    if (score >= minScore)
                    {
                        puzzledb.Element("Boards").Add(new XElement("Board",
                                                                    new XElement("Hash", original.FNV1aHash()),
                                                                    new XElement("Width", original.ColCount),
                                                                    new XElement("Height", original.RowCount),
                                                                    new XElement("Par", steps),
                                                                    new XElement("StartX", original.StartX),
                                                                    new XElement("StartY", original.StartY),
                                                                    new XElement("ExitX", original.ExitX),
                                                                    new XElement("ExitY", original.ExitY),
                                                                    new XElement("Idle", idleFold),
                                                                    new XElement("Data", original.ToString()),
                                                                    solution
                                                                    ));
                        lock (puzzledb)
                        {
                            puzzledb.Save(filepath);
                        }
                        lock (records)
                        {
                            records.Add(new BoardData
                            {
                                Hash = hash
                            });
                        }
                    }
                    else
                    {
                        puzzledb.Element("Rejects").Add(
                            new XElement("Reject",
                                         new XElement("Hash", hash),
                                         new XElement("Width", original.ColCount),
                                         new XElement("Height", original.RowCount),
                                         new XElement("StartX", original.StartX),
                                         new XElement("StartY", original.StartY),
                                         new XElement("ExitX", original.ExitX),
                                         new XElement("ExitY", original.ExitY),
                                         new XElement("Reason", "Min score"),
                                         new XElement("Idle", idleFold),
                                         new XElement("Data", original.ToString()),
                                         solution
                                         ));
                        lock (puzzledb)
                        {
                            puzzledb.Save(filepath);
                        }
                        lock (rejects)
                        {
                            rejects.Add(new RejectData
                            {
                                Hash = hash
                            });
                        }
                    }
                    // Console.WriteLine($"(Task {id}) Puzzle added to DB");
                }
            }
        }
Esempio n. 2
0
        public void Randomize(Random rnd, PatternData pattern, ElementDetails[] dna)
        {
            ElementDetails[] nonMobs = Array.FindAll(dna, x => !x.Mob);
            for (int i = 0; i < RowCount; i++)
            {
                for (int j = 0; j < ColCount; j++)
                {
                    int     pick    = rnd.Next(nonMobs.Length);
                    Element element = new Element(nonMobs[pick]);
                    Data[(i * ColCount) + j] = element;
                }
            }
            ElementDetails[] mobs = Array.FindAll(dna, x => x.Mob);
            int mobCount          = (int)Math.Round((RowCount * ColCount) * pattern.MobRatio);

            for (int i = 0; i < mobCount; i++)
            {
                int mx, my;
                do
                {
                    mx = rnd.Next(ColCount);
                    my = rnd.Next(RowCount);
                    Element under = GetElementAt(my, mx);
                    if (under != null && !under.Details.Mob)
                    {
                        break;
                    }
                } while (true);
                int     pick  = rnd.Next(mobs.Length);
                Element spawn = new Element(mobs[pick]);
                Place(spawn, my, mx);
            }
            foreach (PatternCommmand command in pattern.Commands)
            {
                int fx = (int)Math.Round(command.From.X * ColCount);
                int fy = (int)Math.Round(command.From.Y * RowCount);
                int tx = (int)Math.Round(command.To.X * ColCount);
                int ty = (int)Math.Round(command.To.Y * RowCount);

                if (command.Type.ToLower() == "line")
                {
                    if (ty - fy < tx - fx)
                    {
                        float slopex = (ty - fy != 0) ? 1f / (float)(ty - fy) : 0f;
                        float row    = (float)fy;
                        for (int i = fx; i < tx; i++)
                        {
                            Place(new Element(command.Element), (int)Math.Round(row), i);
                            row += slopex;
                        }
                    }
                    else
                    {
                        float slopey = (tx - fx != 0) ? 1f / (float)(tx - fx) : 0f;
                        float col    = (float)fx;
                        for (int i = fy; i < ty; i++)
                        {
                            Place(new Element(command.Element), i, (int)Math.Round(col));
                            col += slopey;
                        }
                    }
                }
                else
                {
                    if (command.Type.ToLower() == "rectangle")
                    {
                        for (int i = fx; i < tx; i++)
                        {
                            Place(new Element(command.Element), fy, i);
                            Place(new Element(command.Element), ty, i);
                        }
                        for (int i = fy + 1; i < ty - 1; i++)
                        {
                            Place(new Element(command.Element), i, fx);
                            Place(new Element(command.Element), i, tx);
                        }
                    }
                }
            }

            int px = rnd.Next(ColCount);
            int py = rnd.Next(RowCount);

            if (pattern.Start != null)
            {
                px = (int)Math.Round(pattern.Start.X * ColCount);
                py = (int)Math.Round(pattern.Start.Y * RowCount);
            }
            StartX = px;
            StartY = py;
            Place(new Element(Element.Steel), py, px);

            do
            {
                px = rnd.Next(ColCount);
                py = rnd.Next(RowCount);
                if (pattern.Exit != null)
                {
                    px = (int)Math.Round(pattern.Exit.X * ColCount);
                    py = (int)Math.Round(pattern.Exit.Y * RowCount);
                }
                Element under = GetElementAt(py, px);
                if (under.Details != null && under.Details == Element.Player)
                {
                    continue;
                }
                if (px == StartX && py == StartY)
                {
                    continue;
                }
                ExitX = px;
                ExitY = py;
                Place(new Element(Element.Steel), py, px);
                break;
            } while (true);
        }