Ejemplo n.º 1
0
        public static Map Parse(string description, string boosterPack)
        {
            var tokens     = description.Split("#");
            var allPoints  = new AllPoints();
            var edges      = ParseContours(tokens[0], allPoints, false);
            var startPoint = Point.Parse(tokens[1]);
            var obstacles  = ParseContours(tokens[2], allPoints, true);

            var cells = new Map.Cell[allPoints.MaxX + 1, allPoints.MaxY + 1];

            foreach (var e in edges)
            {
                cells[e.X, e.Y] = Map.Cell.Edge;
            }

            foreach (var o in obstacles)
            {
                cells[o.X, o.Y] = Map.Cell.Obstacle;
            }

            ParseBoosters(tokens[3], cells);

            var initialManipulatorCount = 0;
            var initialCloneCount       = 0;

            foreach (var ch in boosterPack)
            {
                switch (ch)
                {
                case 'B':
                    ++initialManipulatorCount;
                    break;

                case 'C':
                    ++initialCloneCount;
                    break;

                default:
                    break;
                }
            }

            return(new Map(startPoint.X, startPoint.Y, cells, initialManipulatorCount, initialCloneCount));
        }
Ejemplo n.º 2
0
        public string SaveToMap()
        {
            string FmtPoint(Point p) => $"({p.X},{p.Y})";

            var contourPointsStr = string.Join(',', this.contourPoints.Select(FmtPoint));

            var selectedPoints   = new HashSet <Point>();
            var contourAllPoints = new AllPoints();

            foreach (var p in this.contourPoints)
            {
                contourAllPoints.Update(p);
            }

            var startPos = this.SelectRandomPoint(selectedPoints, contourAllPoints.MaxX, contourAllPoints.MaxY);

            var boosters = new StringBuilder();

            void SelectBoosters(char sym, int count)
            {
                for (var i = 0; i < count; ++i)
                {
                    if (boosters.Length > 0)
                    {
                        boosters.Append(';');
                    }

                    var boosterPoint = this.SelectRandomPoint(selectedPoints, contourAllPoints.MaxX, contourAllPoints.MaxY);
                    boosters.Append($"{sym}{FmtPoint(boosterPoint)}");
                }
            }

            SelectBoosters('B', this.mNum);
            SelectBoosters('F', this.fNum);
            SelectBoosters('L', this.dNum);
            SelectBoosters('R', this.rNum);
            SelectBoosters('C', this.cNum);
            SelectBoosters('X', this.xNum);

            return($"{contourPointsStr}#{FmtPoint(startPos)}##{boosters}");
        }
Ejemplo n.º 3
0
        private static List <Point> ParseContours(string description, AllPoints allPoints, bool inside)
        {
            var contours        = description.Split(';', StringSplitOptions.RemoveEmptyEntries);
            var pointsByContour = contours.Select(x => x.Split("),").Select(Point.Parse).ToArray()).ToArray();
            var directions      = new[]
            {
                new Point {
                    X = 1, Y = 0
                },
                new Point {
                    X = 0, Y = -1
                },
                new Point {
                    X = -1, Y = 0
                },
                new Point {
                    X = 0, Y = 1
                },
            };
            var insideDirections = new[]
            {
                new Point {
                    X = 0, Y = 0
                },
                new Point {
                    X = 0, Y = -1
                },
                new Point {
                    X = -1, Y = -1
                },
                new Point {
                    X = -1, Y = 0
                },
            };
            var outsideDirections = new[]
            {
                new Point {
                    X = 0, Y = -1
                },
                new Point {
                    X = -1, Y = -1
                },
                new Point {
                    X = -1, Y = 0
                },
                new Point {
                    X = 0, Y = 0
                },
            };
            var edgeDirections = inside ? insideDirections : outsideDirections;
            var result         = new List <Point>();

            foreach (var contour in pointsByContour)
            {
                for (var i = 0; i < contour.Length; ++i)
                {
                    var(pCur, pNext) = (contour[i], contour[(i + 1) % contour.Length]);
                    var dPoint = new Point {
                        X = Math.Sign(pNext.X - pCur.X), Y = Math.Sign(pNext.Y - pCur.Y)
                    };
                    var directionIndex = Array.IndexOf(directions, dPoint);
                    Trace.Assert(directionIndex >= 0);

                    var dEdge       = edgeDirections[directionIndex];
                    var curX        = pCur.X;
                    var curY        = pCur.Y;
                    var nextReached = false;
                    while (!nextReached)
                    {
                        var edgePoint = new Point {
                            X = curX + dEdge.X, Y = curY + dEdge.Y
                        };
                        if (allPoints.Update(edgePoint))
                        {
                            result.Add(edgePoint);
                        }

                        curX       += dPoint.X;
                        curY       += dPoint.Y;
                        nextReached = curX == pNext.X && curY == pNext.Y;
                    }
                }
            }

            return(result);
        }
Ejemplo n.º 4
0
        public void EnsureMapIsValid(string mapFile)
        {
            // Some invariants are easier to check on the raw map
            var tokens = File.ReadAllText(mapFile).Split('#');

            Ensure(tokens[2] == string.Empty, "The puzzle-solving task may have no obstacles", 2);

            var rawContour = tokens[0].Split("),").Select(Point.Parse).Select(CorrectPoint).ToArray();
            var vCount     = rawContour.Length;

            Ensure(
                vCount >= this.vMin && vCount <= this.vMax,
                $"Expected to have at least {this.vMin} and at most {this.vMax} vertices, got {vCount}",
                7);

            var rawContourPoints = new AllPoints();

            foreach (var p in rawContour)
            {
                rawContourPoints.Update(p);
            }

            var minSize = this.tSize - Math.Floor(0.1 * this.tSize);

            Ensure(rawContourPoints.MaxX >= minSize, $"Map max X should be no less than {minSize}", 5);
            Ensure(rawContourPoints.MaxY >= minSize, $"Map max Y should be no less than {minSize}", 5);
            Ensure(rawContourPoints.MaxX <= this.tSize, $"Map max X should be at most {this.tSize}", 4);
            Ensure(rawContourPoints.MaxY <= this.tSize, $"Map max Y should be at most {this.tSize}", 4);

            var totalArea = 0.0;

            for (var idx = 0; idx < rawContour.Length; ++idx)
            {
                var p1 = rawContour[idx];
                var p2 = rawContour[(idx + 1) % rawContour.Length];
                totalArea += p1.X * p2.Y;
                totalArea -= p1.Y * p2.X;
            }

            totalArea /= 2;
            var minArea = Math.Ceiling(0.2 * this.tSize * this.tSize);

            Ensure(totalArea >= minArea, $"Map area should be at least {minArea}", 6);

            for (var idx = 0; idx < rawContour.Length; ++idx)
            {
                var p1 = rawContour[idx];
                var p2 = rawContour[(idx + 1) % rawContour.Length];
                var p3 = rawContour[(idx + 2) % rawContour.Length];

                Ensure(p1 != p2, $"Identical points: {p1} an {p2}", 1);
                Ensure(!(p1.X == p2.X && p2.X == p3.X), $"Collinear points: {p1}, {p2}, {p3}", 1);
                Ensure(!(p1.Y == p2.Y && p2.Y == p3.Y), $"Collinear points: {p1}, {p2}, {p3}", 1);
            }

            // We can now load a proper map
            var map         = MapParser.Parse(File.ReadAllText(mapFile), string.Empty);
            var mapInterior = map.CellsToVisit
                              .Select(p => CorrectPoint(new Point {
                X = p.Item1, Y = p.Item2
            }))
                              .ToArray();

            foreach (var inSq in this.insidePoints)
            {
                Ensure(mapInterior.Contains(inSq), $"Inside point {inSq} is not inside", 9);
            }

            foreach (var outSq in this.outsidePoints)
            {
                Ensure(!mapInterior.Contains(outSq), $"Outside point {outSq} is inside", 10);
            }

            var startPoint = CorrectPoint(new Point {
                X = map.StartX, Y = map.StartY
            });

            Ensure(mapInterior.Contains(startPoint), "The initial position is outside", 3);

            var mNumValid = 0;
            var fNumValid = 0;
            var dNumValid = 0;
            var rNumValid = 0;
            var cNumValid = 0;
            var xNumValid = 0;

            foreach (var p in mapInterior)
            {
                switch (map[p.X + 1, p.Y + 1])
                {
                case Map.Cell.ManipulatorExtension:
                    ++mNumValid;
                    break;

                case Map.Cell.FastWheels:
                    ++fNumValid;
                    break;

                case Map.Cell.Drill:
                    ++dNumValid;
                    break;

                case Map.Cell.Teleport:
                    ++rNumValid;
                    break;

                case Map.Cell.Clone:
                    ++cNumValid;
                    break;

                case Map.Cell.SpawnPoint:
                    ++xNumValid;
                    break;
                }
            }

            Ensure(mNumValid == this.mNum, $"Expected {this.mNum} valid manipulator extensions, got {mNumValid}", 8);
            Ensure(fNumValid == this.fNum, $"Expected {this.fNum} valid fast wheels, got {fNumValid}", 8);
            Ensure(dNumValid == this.dNum, $"Expected {this.dNum} valid drills, got {dNumValid}", 8);
            Ensure(rNumValid == this.rNum, $"Expected {this.rNum} valid teleports, got {rNumValid}", 8);
            Ensure(cNumValid == this.cNum, $"Expected {this.cNum} valid clones, got {cNumValid}", 8);
            Ensure(xNumValid == this.xNum, $"Expected {this.xNum} valid spawn points, got {xNumValid}", 8);

            void Ensure(bool condition, string message, int ruleNumber)
            {
                if (!condition)
                {
                    throw new Exception($"{message} (violated rule {ruleNumber})");
                }
            }
        }