Exemple #1
0
        private static int CountLightsOnAfter(SparseMap <bool> lights, int rounds, bool cornersAreStuck)
        {
            var corners = lights.Corners().ToList();

            // A light which is on stays on when 2 or 3 neighbors are on, and turns off otherwise.
            // A light which is off turns on if exactly 3 neighbors are on, and stays off otherwise.
            for (var i = 0; i < rounds; i++)
            {
                var nextlights = new SparseMap <bool>();
                foreach (var(p, on) in lights.All())
                {
                    if (cornersAreStuck && corners.Any(corner => p == corner))
                    {
                        nextlights[p] = true;
                    }
                    else
                    {
                        var n = p.LookDiagonallyAround().Count(x => lights[x]);
                        nextlights[p] = on && (n == 2 || n == 3) || !on && (n == 3);
                    }
                }
                lights = nextlights;
            }
            var lightsOn = lights.AllPoints(c => c).Count();

            return(lightsOn);
        }
Exemple #2
0
        private SparseMap <char> GenerateMap(IntCodeMachine icm)
        {
            var map = new SparseMap <char>(true);

            (int x, int y)cur = (0, 0);


            while (icm.Step())
            {
                while (icm.Output.CanRead)
                {
                    var tile = icm.Output.Read();
                    //Console.Write((char)tile);
                    if (tile == 10)
                    {
                        cur.x = 0;
                        cur.y++;
                    }
                    else
                    {
                        map.Set(cur, (char)tile);
                        cur.x++;
                    }
                }
                if (icm.WantInput)
                {
                }
            }
            return(map);
        }
Exemple #3
0
        private int FindIntersections(SparseMap <char> map)
        {
            var alignment = 0;

            for (int y = map.Ymin; y < map.Ymax; y++)
            {
                for (int x = map.Xmin; x < map.Xmax; x++)
                {
                    var c     = map.Get((x, y));
                    var neigh = 0;
                    if (c == '#')
                    {
                        neigh += map.Get((x - 1, y)) == c ? 1 : 0;
                        neigh += map.Get((x + 1, y)) == c ? 1 : 0;
                        neigh += map.Get((x, y - 1)) == c ? 1 : 0;
                        neigh += map.Get((x, y + 1)) == c ? 1 : 0;
                    }
                    if (neigh > 2)
                    {
                        map.Set((x, y), 'O');
                        alignment += x * y;
                    }
                }
            }
            return(alignment);
        }
Exemple #4
0
        protected override int Part2(string[] input)
        {
            var map = new SparseMap <int>();

            var overlap = 0;

            foreach (var s in input)
            {
                var(x1, y1, x2, y2) = s.RxMatch("%d,%d -> %d,%d").Get <int, int, int, int>();

                var dx = x2 == x1 ? 0 : x2 > x1 ? 1 : -1;
                var dy = y2 == y1 ? 0 : y2 > y1 ? 1 : -1;
                var D  = Math.Max(Math.Abs(x2 - x1), Math.Abs(y2 - y1));

                for (var d = 0; d <= D; d++)
                {
                    var x = x1 + d * dx;
                    var y = y1 + d * dy;
                    if (map[x][y] == 1)
                    {
                        //Console.WriteLine($"{x}, {y1}");
                        overlap++;
                    }
                    map[x][y]++;
                }
            }

            return(overlap);
        }
Exemple #5
0
            static Cluster MoveLeft(SparseMap <int> distField, Cluster c)
            {
                // Keep track of the paths examined in a stack, starting with
                // the Goal-point. MoveTo the Left will find the next cluster,
                // ie the one that took the fewest moves.
                var path = new Stack <Point>();

                path.Push(c.Goal);
                Cluster nextCluster = null;

                MoveTo(path, c.Goal.Left);
                return(nextCluster);

                void MoveTo(Stack <Point> path, Point moveto)
                {
                    // The path is all the discs that will have to be moved
                    var movefrom = path.Peek();
                    var moves    = path.Count();

                    // If can't do any better than the moves found for the best next
                    // cluster then don't examine this path any further
                    if (moves + (distField?[movefrom] ?? 0) >= nextCluster?.Moves)
                    {
                        return;
                    }

                    // If we can move the content then we know it will be the sortest
                    // path found so far (see above) so move the entire centipede of
                    // disc contents all the way back to the original goal+destination.
                    if (c.CanMoveContentTo(movefrom, moveto))
                    {
                        // yes we can
                        nextCluster = c.Copy();
                        foreach (var p in path)
                        {
                            nextCluster.MoveContent(p, moveto);
                            moveto = p;
                        }
                        return;
                    }

                    // No room on this disc. Examine all neighbors that has a disc that
                    // would fit the data if it was empty. If there's a distance-field
                    // (only for the first move) then visit the closest ones first; if
                    // this optimization isn't done then it'll take forever.
                    var sizeNeeded = c.Disks[movefrom].Used;
                    var neighborsWithEnoughSize = moveto
                                                  .LookAround()
                                                  .Where(p => !path.Contains(p) && c.Disks?[p]?.Size >= sizeNeeded)
                                                  .ToArray();

                    path.Push(moveto);
                    foreach (var n in neighborsWithEnoughSize.OrderBy(n => distField?[n] ?? 0))
                    {
                        MoveTo(path, n);
                    }
                    path.Pop();
                }
            }
Exemple #6
0
        private static SparseMap <bool> GetLights(string[] input)
        {
            var map    = CharMap.FromArray(input);
            var lights = new SparseMap <bool>();

            foreach (var p in map.AllPoints())
            {
                lights[p] = map[p] == '#';
            }
            return(lights);
        }
Exemple #7
0
        public override void First()
        {
            var icm = new IntCodeMachine();

            icm.Init("Day15/repairdroid.ic");
            map = CreateMap(icm);
            int val = ShortestPath(map);

            Echo($"Shortest path from (0,0) to oxygen tank in {val} steps");
            ValidateAnswer(val, 218);
        }
Exemple #8
0
        public override void Second()
        {
            var icm = new IntCodeMachine();

            icm.Init("Day17/cameras.ic");
            icm.mem[0] = 2; // Override movement control
            var map = new SparseMap <char>(true);
            var y0  = Console.CursorTop;

            (int x, int y)cur = (0, 0);
            int cmd = 0, cIdx = 0;
            var dust = 0L;

            while (icm.Step())
            {
                while (icm.Output.CanRead)
                {
                    var tile = icm.Output.Read();
                    if (tile == 10)
                    {
                        cur.x = 0;
                        cur.y++;
                    }
                    else if (tile < 256)
                    {
                        map.Set(cur, (char)tile);
                        cur.x++;
                    }
                    else
                    {
                        dust = tile;
                    }
                }
                if (icm.WantInput)
                {
                    if (cmd < movements.Length && cIdx < movements[cmd].Length)
                    {
                        icm.Input.Write((long)movements[cmd][cIdx]);
                        cIdx++;
                    }
                    else
                    {
                        cmd++;
                        cIdx = 0;
                    }
                }
            }
            map.Render();
            Echo($"Dust collected: {dust}");
            ValidateAnswer(dust, 742673);
        }
Exemple #9
0
        protected override int Part2(string[] input)
        {
            var key = input[0];

            // Geenrate al hashes and transform them into a sparsemap, which is
            // really easy (and fast) to walk around
            var hashes = Enumerable.Range(0, 128)
                         .Select(i => Common.KnotHash.Hash($"{key}-{i}"))
                         .ToArray();
            var map = new SparseMap <bool>();

            for (var y = 0; y < hashes.Length; y++)
            {
                var hash = hashes[y];
                for (var x = 0; x < hash.Length; x++)
                {
                    for (var b = 0; b < 8; b++)
                    {
                        if ((hash[x] & 1U << (7 - b)) != 0)
                        {
                            map[x * 8 + b][y] = true;
                        }
                    }
                }
            }

            // Find the next set bit, clear the entire region, and count it
            // until all set bits has been cleared
            var n = 0;

            while (true)
            {
                var set = map.FirstOrDefault(b => b);
                if (set == null)
                {
                    break;
                }
                ClearRegion(set);
                n++;
            }
            return(n);

            void ClearRegion(Point pos)
            {
                map[pos] = false;
                foreach (var p in pos.LookAround().Where(p => map[p]))
                {
                    ClearRegion(p);
                }
            }
        }
Exemple #10
0
        protected override int Part2(string[] input)
        {
            var cluster = new Cluster(input);

            // For moving the first point (and only for that, it seems) we need to
            // know the preferred direction for moving data around. There is 1 empty
            // disc and it's the only one we can move anything onto, and there are
            // a number of big blocks that can't be moved at all. With that in mind
            // we create a distance-field with shortest distance from (== to) the
            // empty spot, working around the big blocks. When examining the routes
            // this will tell us which discs are closest to the empty disc.
            var distField = new SparseMap <int>();
            var distq     = new Queue <Point>();
            var bigblocks = new HashSet <Point>(cluster.Disks.All(d => d.Used > 100).Select(x => x.Item1));
            var empty     = cluster.Disks.All(d => d.Used == 0).Single().Item1;

            distq.Enqueue(empty);
            while (distq.Any())
            {
                var p         = distq.Dequeue();
                var dist      = distField[p];
                var neighbors = p.LookAround().Where(n => distField[n] == 0 && cluster.Disks[n] != null && !bigblocks.Contains(n));
                foreach (var n in neighbors)
                {
                    distField[n] = dist + 1;
                    distq.Enqueue(n);
                }
            }

            // The stragegy:
            // Move the Goal to the left, one spot at a time. (That seems to produce the
            // shortest path overall). Do so by examining which of the neighbors has room
            // to spare can can move their data away, either directly or by pushing data
            // data away from their neighbors, recursively.
            // We only need the distance-field for the first move. It's costly to calculate
            // for the remaining moves and doesn't seem to make a difference so just set
            // it to null after the first move.
            var moves = 0;

            while (cluster.Goal != Point.Origin)
            {
                cluster   = MoveLeft(distField, cluster);
                moves    += cluster.Moves;
                distField = null;
                //cluster.WriteToConsole();
            }
            return(moves);
Exemple #11
0
        protected override int Part1(string[] input)
        {
            var raw = input[0];
            var map = new SparseMap <int>();

            var pos = Point.From(0, 0);

            map[pos]++;
            foreach (var ch in raw)
            {
                pos = pos.Move(ch);
                map[pos]++;
            }

            var visited = map.AllPoints().Count();

            return(visited);
        }
Exemple #12
0
        protected override int Part2(string[] input)
        {
            var n   = int.Parse(input[0]);
            var map = new SparseMap <int>(0);

            // Seed the map at (0,0) with 1
            // Then spiral out (skip 0,0) while building up map-values
            map[Point.Origin] = 1;
            foreach (var pos in Point.Origin.SpiralFrom().Skip(1))
            {
                var v = map[pos] = pos.LookDiagonallyAround().Sum(p => map[p]);
                if (v > n)
                {
                    return(v);
                }
            }
            throw new Exception("Not found");
        }
Exemple #13
0
 public Cluster(string[] input)
 {
     Disks = new SparseMap <Disk>();
     foreach (var line in input.SkipWhile(x => !x.StartsWith("/dev")))
     {
         // root@ebhq-gridcenter# df -h
         // Filesystem              Size  Used  Avail  Use%
         // /dev/grid/node-x0-y2     90T   70T    20T   77%
         var(x, y, size, used) = line
                                 .RxMatch("/dev/grid/node-x%d-y%d %DT %DT")
                                 .Get <int, int, int, int>();
         Disks[x][y] = new Disk
         {
             Size = size,
             Used = used
         };
     }
     Goal = Point.From(Disks.MinMax().Item2.X, 0);
 }
Exemple #14
0
        protected override int Part1(string[] input)
        {
            var map = new SparseMap <int>();

            var overlap = 0;

            foreach (var s in input)
            {
                var(x1, y1, x2, y2) = s.RxMatch("%d,%d -> %d,%d").Get <int, int, int, int>();
                if (x1 == x2)
                {
                    var yy1 = Math.Min(y1, y2);
                    var yy2 = Math.Max(y1, y2);
                    for (var y = yy1; y <= yy2; y++)
                    {
                        if (map[x1][y] == 1)
                        {
                            //Console.WriteLine($"{x1}, {y}");
                            overlap++;
                        }
                        map[x1][y]++;
                    }
                }
                if (y1 == y2)
                {
                    var xx1 = Math.Min(x1, x2);
                    var xx2 = Math.Max(x1, x2);
                    for (var x = xx1; x <= xx2; x++)
                    {
                        if (map[x][y1] == 1)
                        {
                            //Console.WriteLine($"{x}, {y1}");
                            overlap++;
                        }
                        map[x][y1]++;
                    }
                }
            }


            return(overlap);
        }
Exemple #15
0
        protected override int Part2(string[] input)
        {
            var raw = input[0];
            var map = new SparseMap <int>();

            var deliveries = new Point[] { Point.From(0, 0), Point.From(0, 0) };

            foreach (var d in deliveries)
            {
                map[d]++;
            }
            for (var i = 0; i < raw.Length; i++)
            {
                var turn = i % deliveries.Length;
                deliveries[turn] = deliveries[turn].Move(raw[i]);
                map[deliveries[turn]]++;
            }

            var visited = map.AllPoints().Count();

            return(visited);
        }
Exemple #16
0
        private static PortalGraph BuildSimpleGraph(PortalMaze maze)
        {
            var walked = new SparseMap <PortalGraph.Vertex>();
            var graph  = new PortalGraph();

            graph.AddVertex(maze.Entry);
            BuildSimpleGraph(graph.Root);

            return(graph);

            void BuildSimpleGraph(PortalGraph.Vertex node)
            {
                while (walked[node.Pos] == null)
                {
                    walked[node.Pos] = node;
                    var positions = node.Pos
                                    .LookAround()
                                    .Select(p => new { Pos = p, Dest = maze.Transform(p) })
                                    .Where(x => maze.Map[x.Dest] == '.')
                                    .Where(x => walked[x.Dest] == null || !walked[x.Dest].Edges.ContainsKey(node))
                                    .ToList();

                    foreach (var p in positions.Where(x => walked[x.Dest] != null).ToList())
                    {
                        var existing    = walked[p.Dest];
                        var portal      = maze.Portals[p.Pos];
                        var portalValue = portal == null ? 0 : portal.IsDownward ? -1 : 1;
                        var portalName  = portal == null ? null : portal.Name;
                        node.Value           = portal;
                        existing.Value       = portal;
                        node.Edges[existing] = portalValue;
                        existing.Edges[node] = -portalValue;
                        positions.Remove(p);
                    }

                    switch (positions.Count())
                    {
                    case 0:
                        return;

                    case 1:
                        var p    = positions.First();
                        var next = graph.AddVertex(p.Dest);
                        //graph.Vertices.Add(next);
                        var portal      = maze.Portals[p.Pos];
                        var portalValue = portal == null ? 0 : portal.IsDownward ? -1 : 1;
                        node.Value       = portal;
                        next.Value       = portal;
                        node.Edges[next] = portalValue;
                        next.Edges[node] = -portalValue;
                        node             = next;
                        break;

                    default:
                        var forks = positions.Select(x => graph.AddVertex(x.Dest)).ToList();
                        foreach (var fork in forks)
                        {
                            BuildSimpleGraph(fork);
                        }
                        return;
                    }
                }
            }
        }
Exemple #17
0
        /// <summary>Sample invocation of path-finding code in <see cref="EMonk.Pathfinding.PathMap"/>.</summary>
        static void PathfinderSample()
        {
            Console.Clear();
            Console.WriteLine("Pathfinding Sample");
            Console.WriteLine("==================");

            // create a simple set of map nodes
            Console.Write("Generating sample map tiles");
            SparseMap <MapPosition, MapNode> map = new SparseMap <MapPosition, MapNode>();

            // add strip of high-cost tiles
            for (int i = 20; i <= 30; ++i)
            {
                map[new MapPosition(i, 15)] = new MapNode(true, 15);
            }

            // create a lower cost hole through strip
            map[new MapPosition(22, 15)] = new MapNode(true, 2);

            // add a medium-cost block in the way of the normal path
            map[new MapPosition(23, 14)] = new MapNode(true, 4);
            map[new MapPosition(22, 14)] = new MapNode(true, 4);
            Console.WriteLine();

            // generate path map for this
            MapPosition origin  = new MapPosition(25, 25);
            double      maxCost = 50;

            Console.Write("Generating PathMap for Origin={0}, MaxCost={1}", origin, maxCost);
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Start();
            PathMap <MapNode> m = PathMap <MapNode> .Generate(map, origin, maxCost);

            sw.Stop();
            if (m == null)
            {
                Console.WriteLine(" failed!");
                Console.WriteLine();
                ShowError("Error occurred while calculating PathMap.");
                return;
            }
            Console.WriteLine(" [{0:0.00}ms]", sw.Elapsed.TotalMilliseconds);
            Console.WriteLine("Statistics:");
            Console.WriteLine("\tInput Nodes     \t{0}", map.Count);
            Console.WriteLine("\tOutput Positions\t{0}", m.Count);
            Console.WriteLine("\tScan Iterations \t{0}", m.Iterations);
            Console.WriteLine();

            // find path to end-point
            MapPosition target = new MapPosition(25, 14);

            Console.Write("Finding path to target position {0}", target);

            if (null == m[target])
            {
                Console.WriteLine(" failed.");
                Console.WriteLine();
                ShowError("Target was not present in PathMap's potential move set.");
                return;
            }

            double pcost;

            sw.Restart();
            MapPosition[] path = m.GetPath(new MapPosition(25, 14), out pcost);
            sw.Stop();
            if (path == null)
            {
                Console.WriteLine(" failed!");
                Console.WriteLine();
                ShowError("Error occurred while calculating path.");
                return;
            }
            Console.WriteLine(" [{0:0.00}ms]", sw.Elapsed.TotalMilliseconds);
            Console.WriteLine();

            // Display generated path
            Console.WriteLine("Generated path from {0}:", path.First());
            Console.WriteLine("\tDirection\tNew Position\tCost\tTotal Cost");
            MapPosition prev = null;

            foreach (var curr in path)
            {
                if (prev != null)
                {
                    Console.WriteLine("\t{0,-10}\t{1,-9}\t{2}\t{3}", prev.DirectionTo(curr).ToString(), curr, (m[curr].TotalCost - m[prev].TotalCost), m[curr].TotalCost);
                }
                prev = curr;
            }

            Console.WriteLine();
            Console.WriteLine("Press any key to continue");
            Console.ReadKey();
        }
Exemple #18
0
        public PortalMaze(CharMap map)
            : base(map)
        {
            var portalinfo    = Map.AllPoints(char.IsUpper).OrderBy(p => p.Y).ThenBy(p => p.X);
            var portalsByName = new Dictionary <string, List <Tuple <Point, Point> > >();

            // Map all entry-portals
            foreach (var p in portalinfo)
            {
                if (Map[p.Down] == '.')
                {
                    //       X
                    // p ->  Y  <- exit
                    //       .  <- arrival
                    AddPortal(p.Up, p, p, p.Down);
                }
                else if (Map[p.Up] == '.')
                {
                    //       .  <- arrival
                    // p ->  X  <- exit
                    //       Y
                    AddPortal(p, p.Down, p, p.Up);
                }
                //};

                //// Next find the portal exits and match with their entry
                //foreach (var p in portalinfo)
                //{
                else if (Map[p.Right] == '.')
                {
                    // exit vv arrival
                    //     XY.
                    //      ^ p
                    AddPortal(p.Left, p, p, p.Right);
                }
                else if (Map[p.Left] == '.')
                {
                    // arrival vv exit
                    //         .XY
                    //          ^ p
                    AddPortal(p, p.Right, p, p.Left);
                }
            }
            ;

            // Link up portals
            Entry = portalsByName["AA"].First().Item2;
            Exit  = portalsByName["ZZ"].First().Item2;
            Map[portalsByName["AA"].First().Item1] = '#';
            Map[portalsByName["ZZ"].First().Item1] = '#';
            ExternalMapPoints = new Point[] { Exit };

            Portals = new SparseMap <Portal>();
            var area = Map.MinMax();

            foreach (var pair in portalsByName.Where(p => p.Key != "AA" && p.Key != "ZZ"))
            {
                var p1 = pair.Value[0];
                var p2 = pair.Value[1];
                Portals[p1.Item1] = new Portal
                {
                    Name       = pair.Key,
                    Pos        = p2.Item2,
                    IsDownward = !IsOuterPortal(p1.Item1)
                };
                Portals[p2.Item1] = new Portal
                {
                    Name       = pair.Key,
                    Pos        = p1.Item2,
                    IsDownward = !IsOuterPortal(p2.Item1)
                };
            }

            bool IsOuterPortal(Point p) => p.X <4 || p.X> area.Item2.X - 4 || p.Y <4 || p.Y> area.Item2.Y - 4;

            void AddPortal(Point pos1, Point pos2, Point departure, Point arrival)
            {
                var name = new string(new char[] { Map[pos1], Map[pos2] });

                if (!portalsByName.TryGetValue(name, out var pn))
                {
                    portalsByName[name] = new List <Tuple <Point, Point> >();
                }
                portalsByName[name].Add(new Tuple <Point, Point>(departure, arrival));
            }
        }