Example #1
0
        private static void WriteMazeInManual(HexamazeInfo maze)
        {
            const double hexWidth = 72;

            foreach (var path in new[] { @"D:\c\KTANE\HTML\Hexamaze.html", @"D:\c\KTANE\Hexamaze\Manual\Hexamaze.html" })
            {
                // Create the color chart (top-left of the manual page)
                File.WriteAllText(path, Regex.Replace(File.ReadAllText(path), @"(?<=<!--%%-->).*(?=<!--%%%-->)", options: RegexOptions.Singleline, replacement: $@"
                <svg class='legend' viewBox='-325 -375 650 750'>
                    {"red,yellow,green,cyan,blue,pink".Split(',').Select((color, i) => $"<g class='label' transform='rotate({330 + 60 * i})'><text text-anchor='middle' y='-280'>{color}</text><path d='M-124.7-150v-200M124.7-150v-200' /></g>").JoinString()}
                    <polygon class='outline' points='{Hex.LargeHexagonOutline(4, hexWidth).Select(p => $"{p.X},{p.Y}").JoinString(" ")}' />
                    {Hex.LargeHexagon(4).Select(h => h.GetCenter(hexWidth)).Select(p => $"<circle class='dot' cx='{p.X}' cy='{p.Y}' r='{hexWidth / 12}' />").JoinString()}
                </svg>"));

                // Create the main maze in the manual page
                File.WriteAllText(path, Regex.Replace(File.ReadAllText(path), @"(?<=<!--##-->).*(?=<!--###-->)", maze.CreateSvg(), RegexOptions.Singleline));
            }
        }
Example #2
0
        private static bool areMarkingsUnique(HexamazeInfo maze, bool saveFiles = false)
        {
            var ambig     = 1;
            var size      = maze.Size;
            var smallSize = maze.SubmazeSize;
            var unique    = new Dictionary <string, List <Tuple <Hex, int> > >();

            foreach (var centerHex in Hex.LargeHexagon(size - smallSize + 1))
            {
                for (int rotation = 0; rotation < 6; rotation++)
                {
                    var markingsStr = Hex.LargeHexagon(smallSize).Select(h => h.Rotate(rotation) + centerHex).Select(h => maze.Markings.Get(h, Marking.None).Rotate(-rotation)).ToMarkingString();
                    List <Tuple <Hex, int> > uniqs;
                    if (unique.TryGetValue(markingsStr, out uniqs) && uniqs.Count > 0)
                    {
                        if (saveFiles)
                        {
                            var fills1 = Tuple.Create(Hex.LargeHexagon(smallSize).Select(h => h.Rotate(uniqs[0].Item2) + uniqs[0].Item1), "fed");
                            var fills2 = Tuple.Create(Hex.LargeHexagon(smallSize).Select(h => h.Rotate(rotation) + centerHex), "def");
                            ambig++;
                            File.WriteAllText($@"D:\c\KTANE\HTML\Hexamaze{ambig}.html", Regex.Replace(File.ReadAllText(@"D:\c\KTANE\HTML\Hexamaze.html"), @"\A(.*<!--##-->\s*).*?(?=\s*<!--###-->)", options: RegexOptions.Singleline, evaluator: m => m.Groups[1].Value + maze.CreateSvg(new[] { fills1, fills2 })));
                        }
                        else
                        {
                            return(false);
                        }
                    }
                    unique.AddSafe(markingsStr, Tuple.Create(centerHex, rotation));
                }
            }

            if (!saveFiles)
            {
                return(true);
            }

            foreach (var nonUnique in unique.Where(k => k.Value.Count > 1))
            {
                Console.WriteLine($"{nonUnique.Key} = {nonUnique.Value.Select(tup => $"{tup.Item1}/{(6 - tup.Item2) % 6}").JoinString(", ")}");
            }
            return(unique.All(kvp => kvp.Value.Count <= 1));
        }
Example #3
0
        public static HexamazeInfo GenerateMarkings(HexamazeInfo origMaze)
        {
            var          obj            = new object();
            var          lowestMarkings = int.MaxValue;
            HexamazeInfo bestMaze       = null;

            var seed = 146;     // 19 markings with initial hexagon in the center
            //Enumerable.Range(0, 300).ParallelForEach(4, seed =>
            //{
            var rnd = new Random(seed);

            var maze      = origMaze.Clone();
            var size      = maze.Size;
            var smallSize = maze.SubmazeSize;

            maze.Markings = new Dictionary <Hex, Marking>();
            // List Circle and Hexagon twice so that triangles don’t completely dominate the distribution
            var allowedMarkings = new[] { Marking.Circle, Marking.Circle, Marking.Hexagon, Marking.Hexagon, Marking.TriangleDown, Marking.TriangleLeft, Marking.TriangleRight, Marking.TriangleUp };

            // Put a hexagon in the center
            maze.Markings.Add(new Hex(0, 0), Marking.Hexagon);

            // Step 1: Put random markings in until there are no more ambiguities
            while (!areMarkingsUnique(maze))
            {
                var availableHexes = Hex.LargeHexagon(size).Where(h => !maze.Markings.ContainsKey(h) && !h.Neighbors.SelectMany(n => n.Neighbors).Any(maze.Markings.ContainsKey)).ToArray();
                if (availableHexes.Length == 0)
                {
                    goto impossiburu;
                }
                var randomHex = availableHexes[rnd.Next(availableHexes.Length)];
                maze.Markings[randomHex] = allowedMarkings.PickRandom(rnd);
            }

            // Step 2: Find markings to remove again
            var removableMarkings = maze.Markings.ToList();

            while (removableMarkings.Count > 0)
            {
                var tryRemoveIndex = rnd.Next(removableMarkings.Count);
                var tryRemove      = removableMarkings[tryRemoveIndex];
                removableMarkings.RemoveAt(tryRemoveIndex);
                maze.Markings.Remove(tryRemove.Key);
                if (!areMarkingsUnique(maze))
                {
                    // No longer unique — put it back in
                    maze.Markings.Add(tryRemove.Key, tryRemove.Value);
                }
            }

            lock (obj)
            {
                var msg = "{0/White} = {1/Green}{2/Magenta}".Color(null).Fmt(seed, maze.Markings.Count, maze.Markings.Count < lowestMarkings ? " — NEW BEST" : maze.Markings.Count == lowestMarkings ? " — TIED" : "");
                if (maze.Markings.Count <= lowestMarkings)
                {
                    lowestMarkings = maze.Markings.Count;
                    bestMaze       = maze;
                    WriteMazeInManual(bestMaze);
                }
                ConsoleUtil.WriteLine(msg);
            }

            impossiburu :;
            //});
            return(bestMaze);
        }