c# A*
Using custom Heap and A* algorithm from https://www.redblobgames.com/pathfinding/a-star/implementation.html#python-astar\n\n\npublic class Solution \n{\n\tpubli
Using custom Heap and A* algorithm from https://www.redblobgames.com/pathfinding/a-star/implementation.html#python-astar\n\n```\npublic class Solution \n{\n\tpublic int MinPushBox(char[][] grid)\n\t{\n\t\tPoint target = new Point();\n\t\tPoint startBox = new Point();\n\t\tPoint startPerson = new Point();\n\t\tfor (int r = 0; r < grid.Length; ++r)\n\t\t{\n\t\t\tfor (int c = 0; c < grid[r].Length; ++c)\n\t\t\t{\n\t\t\t\tif (grid[r][c] == \'T\')\n\t\t\t\t\ttarget = new Point(r, c);\n\t\t\t\telse if (grid[r][c] == \'S\')\n\t\t\t\t\tstartPerson = new Point(r, c);\n\t\t\t\telse if (grid[r][c] == \'B\')\n\t\t\t\t\tstartBox = new Point(r, c);\n\t\t\t}\n\t\t}\n\n\t\tvar heap = new Heap<State>((n1, n2) => n1.Priority.CompareTo(n2.Priority));\n\t\tvar costSoFar = new Dictionary<(Point, Point), int>();\n\n\t\theap.Insert(new State { Priority = this.Heurestic(startBox, target), Box = startBox, Person = startPerson });\n\t\tcostSoFar[(startBox, startPerson)] = 0;\n\n\t\twhile (heap.Count > 0)\n\t\t{\n\t\t\tvar state = heap.RemoveMin();\n\n\t\t\tif (state.Box == target)\n\t\t\t\treturn state.Moves;\n\n\t\t\tfor (int dr = -1; dr <= 1; dr++)\n\t\t\t{\n\t\t\t\tfor (int dc = -1; dc <= 1; dc++)\n\t\t\t\t{\n\t\t\t\t\tif ((dr == 0 && dc == 0) || (dr != 0 && dc != 0))\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tvar newPersonLocation = new Point(state.Person.Row + dr, state.Person.Col + dc);\n\t\t\t\t\tif (!this.CanMove(newPersonLocation, grid))\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tvar currentState = (state.Box, state.Person);\n\n\t\t\t\t\tif (newPersonLocation == state.Box)\n\t\t\t\t\t{\n\t\t\t\t\t\tvar newBoxLocation = new Point(state.Box.Row + dr, state.Box.Col + dc);\n\t\t\t\t\t\tif (!this.CanMove(newBoxLocation, grid))\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tvar nextState = (newBoxLocation, newPersonLocation);\n\t\t\t\t\t\tvar newCost = costSoFar[currentState] + 1;\n\t\t\t\t\t\tif (!costSoFar.ContainsKey(nextState) || newCost < costSoFar[nextState])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcostSoFar[nextState] = newCost;\n\t\t\t\t\t\t\tint priority = newCost + this.Heurestic(newBoxLocation, target);\n\t\t\t\t\t\t\theap.Insert(new State { Box = newBoxLocation, Person = newPersonLocation, Moves = state.Moves + 1, Priority = priority });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tvar nextState = (state.Box, newPersonLocation);\n\t\t\t\t\t\tvar newCost = costSoFar[currentState];\n\t\t\t\t\t\tif (!costSoFar.ContainsKey(nextState) || newCost < costSoFar[nextState])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcostSoFar[nextState] = newCost;\n\t\t\t\t\t\t\tint priority = newCost + this.Heurestic(state.Box, target);\n\t\t\t\t\t\t\theap.Insert(new State { Box = state.Box, Person = newPersonLocation, Moves = state.Moves, Priority = priority });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn -1;\n\t}\n\n\tprivate bool CanMove(Point point, char[][] grid)\n\t{\n\t\tbool invalidLocation =\n\t\t\tpoint.Row < 0 ||\n\t\t\tpoint.Row >= grid.Length ||\n\t\t\tpoint.Col < 0 ||\n\t\t\tpoint.Col >= grid[0].Length ||\n\t\t\tgrid[point.Row][point.Col] == \'#\';\n\n\t\treturn !invalidLocation;\n\t}\n\n\tprivate int Heurestic(Point box, Point target) => Math.Abs(box.Row - target.Row) + Math.Abs(box.Col - target.Col);\n\n\tpublic struct Point : IEquatable<Point>\n\t{\n\t\tpublic Point(int row, int col) => (this.Row, this.Col) = (row, col);\n\n\t\tpublic int Row { get; set; }\n\n\t\tpublic int Col { get; set; }\n\n\t\tpublic static bool operator ==(Point p1, Point p2) => p1.Equals(p2);\n\n\t\tpublic static bool operator !=(Point p1, Point p2) => !p1.Equals(p2);\n\n\t\tpublic bool Equals(Point other) => this.Row == other.Row && this.Col == other.Col;\n\n\t\tpublic override bool Equals(object obj) => base.Equals(obj);\n\n\t\tpublic override int GetHashCode() => HashCode.Combine(Row, Col);\n\t}\n\n\tpublic class State : IComparable<State>\n\t{\n\t\tpublic int Priority { get; set; }\n\t\tpublic int Moves { get; set; }\n\t\tpublic Point Box { get; set; }\n\t\tpublic Point Person { get; set; }\n\n\t\tpublic int CompareTo(State other) => this.Priority.CompareTo(other.Priority);\n\t}\n\t\t\n    public class Heap<T>\n    {\n        private readonly List<T> list = new List<T>();\n\n        private readonly Comparison<T> compare;\n\n        public Heap(Comparison<T> compare) => this.compare = compare;\n\n        public T Min\n        {\n            get => this.list[0];\n        }\n\n        public int Count\n        {\n            get => this.list.Count;\n        }\n\n        public void Insert(T item)\n        {\n            this.list.Add(item);\n            this.FixHeapUp();\n        }\n\n        public void Build(IList<T> items)\n        {\n            this.list.Clear();\n            this.list.AddRange(items);\n\n            int parentIndex = this.GetParentIndex(items.Count - 1);\n            int index;\n            for (index = items.Count - 1; index >= 0; --index)\n            {\n                if (index != parentIndex)\n                    break;\n            }\n\n            for (int i = index; i >= 0; --i)\n                this.FixHeapDown(i);\n        }\n\n        public T RemoveMin()\n        {\n            T min = this.list[0];\n\n            if (this.list.Count == 1)\n            {\n                this.list.Clear();\n            }\n            else\n            {\n                this.list[0] = this.list[this.list.Count - 1];\n                this.list.RemoveAt(this.list.Count - 1);\n                this.FixHeapDown(0);\n            }\n\n            return min;\n        }\n\n        private int GetParentIndex(int index) => (index - 1) / 2;\n\n        private int GetLeftChildIndex(int index)\n        {\n            int leftIndex = 2 * index + 1;\n            if (leftIndex >= this.list.Count)\n                leftIndex = -1;\n            return leftIndex;\n        }\n\n        private int GetRightChildIndex(int index)\n        {\n            int rightIndex = 2 * index + 2;\n            if (rightIndex >= this.list.Count)\n                rightIndex = -1;\n            return rightIndex;\n        }\n\n        private void Swap(int i1, int i2)\n        {\n            T tmp = this.list[i1];\n            this.list[i1] = this.list[i2];\n            this.list[i2] = tmp;\n        }\n\n        private void FixHeapUp()\n        {\n            int i = this.list.Count - 1;\n            int parentIndex = this.GetParentIndex(i);\n\n            while (i != 0 && this.compare(this.list[parentIndex], this.list[i]) > 0)\n            {\n                this.Swap(parentIndex, i);\n                i = this.GetParentIndex(i);\n                parentIndex = this.GetParentIndex(i);\n            }\n        }\n\n        private void FixHeapDown(int rootIndex)\n        {\n            int leftChildIndex = this.GetLeftChildIndex(rootIndex);\n            int rightChildIndex = this.GetRightChildIndex(rootIndex);\n\n            int smallestIndex = rootIndex;\n\n            if (leftChildIndex != -1 && rightChildIndex != -1)\n            {\n                smallestIndex = this.compare(this.list[leftChildIndex], this.list[rightChildIndex]) < 0\n                    ? leftChildIndex\n                    : rightChildIndex;\n            }\n            else if (leftChildIndex != -1)\n                smallestIndex = leftChildIndex;\n            else if (rightChildIndex != -1)\n                smallestIndex = rightChildIndex;\n\n            smallestIndex = this.compare(this.list[smallestIndex], this.list[rootIndex]) < 0\n                ? smallestIndex\n                : rootIndex;\n\n            if (smallestIndex == rootIndex)\n                return;\n\n            this.Swap(smallestIndex, rootIndex);\n            this.FixHeapDown(smallestIndex);\n        }\n    }    \n}\n```
[]