]> Dogcows Code - chaz/carfire/commitdiff
New test map: maze.cfmap
authorCharles <Charles@92bb83a3-7c8f-8a45-bc97-515c4e399668>
Mon, 19 Apr 2010 05:09:51 +0000 (05:09 +0000)
committerCharles <Charles@92bb83a3-7c8f-8a45-bc97-515c4e399668>
Mon, 19 Apr 2010 05:09:51 +0000 (05:09 +0000)
New classes:
- Timer is a basic event scheduler.
- IPriorityQueue, BinaryHeap is a basic heap... not sure why .Net doesn't provide one.
- PathFinder lets your search the map for paths.
- Script is a WIP.

git-svn-id: https://bd85.net/svn/cs3505_group@107 92bb83a3-7c8f-8a45-bc97-515c4e399668

CarFire/CarFire/CarFire/CarFire.csproj
CarFire/CarFire/CarFire/Content/Content.contentproj
CarFire/CarFire/CarFire/Content/Maps/maze.cfmap [new file with mode: 0644]
CarFire/CarFire/CarFire/Content/Maps/stable.cfmap
CarFire/CarFire/CarFire/PathFinder.cs [new file with mode: 0644]
CarFire/CarFire/CarFire/PriorityQueue.cs [new file with mode: 0644]
CarFire/CarFire/CarFire/Script.cs [new file with mode: 0644]
CarFire/CarFire/CarFire/Timer.cs [new file with mode: 0644]

index fd92b88a774d0313b185841f194a565812a1b17b..2edc12d8b23734b901b1a2fa1eeaaa842f0c96a5 100644 (file)
@@ -84,6 +84,7 @@
     </Reference>\r
   </ItemGroup>\r
   <ItemGroup>\r
+    <Compile Include="PathFinder.cs" />\r
     <Compile Include="ChatInfo.cs" />\r
     <Compile Include="Display.cs" />\r
     <Compile Include="Game.cs" />\r
     <Compile Include="MapReader.cs" />\r
     <Compile Include="NetworkManager.cs" />\r
     <Compile Include="Parse.cs" />\r
+    <Compile Include="PriorityQueue.cs" />\r
     <Compile Include="Projectile.cs" />\r
     <Compile Include="Properties\AssemblyInfo.cs" />\r
     <Compile Include="Program.cs" />\r
+    <Compile Include="Script.cs" />\r
+    <Compile Include="Timer.cs" />\r
     <Compile Include="XnaGame.cs" />\r
     <Compile Include="ScreenManager.cs" />\r
   </ItemGroup>\r
index e53208fd94954349d60d11839b6931cecc31d4cc..818dbddd70cdf783952e66a4316c7df87090d0ca 100644 (file)
       <Processor>TextureProcessor</Processor>\r
     </Compile>\r
   </ItemGroup>\r
+  <ItemGroup>\r
+    <Compile Include="Maps\maze.cfmap">\r
+      <Name>maze</Name>\r
+      <Importer>MapImporter</Importer>\r
+      <Processor>PassThroughProcessor</Processor>\r
+    </Compile>\r
+  </ItemGroup>\r
   <Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\v3.0\Microsoft.Xna.GameStudio.ContentPipeline.targets" />\r
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \r
        Other similar extension points exist, see Microsoft.Common.targets.\r
diff --git a/CarFire/CarFire/CarFire/Content/Maps/maze.cfmap b/CarFire/CarFire/CarFire/Content/Maps/maze.cfmap
new file mode 100644 (file)
index 0000000..a7d220d
--- /dev/null
@@ -0,0 +1,33 @@
+[metadata]\r
+       author = Chaz McGarvey\r
+       levelname = Maze\r
+       type = Campaign\r
+       dimensions = [80,21]\r
+       tileset = FuturisticBuilding\r
+       numplayers = 1\r
+\r
+; okay, so it's more like a spiral...\r
+[maptable]\r
++------------------------------------------------------------------------------+\r
+|   +                                                                          |\r
+| 1 +                     +                                                    |\r
+|   +                     +                                                    |\r
+|   +   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++   |\r
+|   +   +                                         +                        +   |\r
+|   +   +                                         +                        +   |\r
+|   +   +                                                                  +   |\r
+|   +   +   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++   +   |\r
+|   +   +        +           +             +                           +   +   |\r
+|   +   +        +           +             +                ++++++++   +   +   |\r
+|   +   +              +         +    +        +++++++        +++      +   +   |\r
+|   +   +              +         +    +              +                 +   +   |\r
+|   +   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++   +   |\r
+|   +                                                                      +   |\r
+|   +                                                                      +   |\r
+|   +                                                                      +   |\r
+|   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++   |\r
+|                                                                              |\r
+|                                                                 +            |\r
++------------------------------------------------------------------------------+\r
+\r
+; vi:ft=dosini\r
index fc7f2c35c1c6798b5132ecb3992a4307bc2b34f7..fe5a7e29c1ed669ba83afdd72398f87355a02868 100644 (file)
@@ -1,7 +1,4 @@
-; Comments can be made with a semicolon as the first character of a line.\r
-; Blank lines are also ignored.\r
-; This is my sandbox level I will use to test against while building the\r
-; level-loading code.\r
+; This map should load and function just fine.\r
 \r
 [metadata]\r
        author = Chaz McGarvey\r
 |                  |------------------------------------------                 |\r
 | 4                |                                       |                   |\r
 |                  |                                       |                   |\r
-+-------------+----+                                       |                   |\r
-|             |                                            |                   |\r
-|             |                                            |                   |\r
-|             |                                            |                   |\r
-|             |          \ @ # $ % ^ & * ( )               |                   |\r
-|     +-------+                                            |                   |\r
-|                                                          |                   |\r
-|                                                                              |\r
-|                                                                              |\r
++-------------+----+                                       |      \       /    |\r
+|             |                                            |       \     /     |\r
+|             |                                            |        \   /      |\r
+|             |                                            |         \ /       |\r
+|             |          \ @ # $ % ^ & * ( )               |          |        |\r
+|     +-------+                                            |         / \       |\r
+|                                                          |        /   \      |\r
+|                                                                  /     \     |\r
+|                                                                 /       \    |\r
 |                                                                              |\r
 +------------------------------------------------------------------------------+\r
 \r
diff --git a/CarFire/CarFire/CarFire/PathFinder.cs b/CarFire/CarFire/CarFire/PathFinder.cs
new file mode 100644 (file)
index 0000000..8b627ac
--- /dev/null
@@ -0,0 +1,277 @@
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Diagnostics;\r
+using Microsoft.Xna.Framework;\r
+\r
+namespace CarFire\r
+{\r
+    /// <summary>\r
+    /// A class to navigate from here to there through a grid of\r
+    /// open and closed cells.\r
+    /// </summary>\r
+    public class PathFinder\r
+    {\r
+        #region Public Types\r
+\r
+        /// <summary>\r
+        /// The heuristic function should return some value representing\r
+        /// the distance between two points.  A common approach is to\r
+        /// return the manhattan distance.\r
+        /// </summary>\r
+        /// <param name="a">A point.</param>\r
+        /// <param name="b">The endpoint.</param>\r
+        /// <returns>The heuristic.</returns>\r
+        public delegate int Heuristic(Point a, Point b);\r
+\r
+        /// <summary>\r
+        /// The cost function should take two points representing two\r
+        /// adjacent cells and return a cost measure of how expensive it\r
+        /// is to move from one cell to the other.\r
+        /// </summary>\r
+        /// <param name="a">A point.</param>\r
+        /// <param name="b">Another point.</param>\r
+        /// <returns>The cost.</returns>\r
+        public delegate int CostFunction(Point a, Point b);\r
+\r
+        #endregion\r
+\r
+\r
+        #region Public Methods\r
+\r
+        /// <summary>\r
+        /// Construct a path finder with a grid.  The grid is a matrix\r
+        /// of boolean values, true meaning the cell is walkable and false\r
+        /// meaning the cell is closed.\r
+        /// </summary>\r
+        /// <param name="grid">The grid to find paths on.</param>\r
+        public PathFinder(bool[,] grid)\r
+        {\r
+            Debug.Assert(grid != null);\r
+\r
+            mGrid = grid;\r
+            mGridWidth = mGrid.GetUpperBound(0) + 1;\r
+            mGridHeight = mGrid.GetUpperBound(1) + 1;\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// The A* algorithm for finding the best path through a grid of cells.\r
+        /// The manhattan distance heuristic and a simple distance-based cost\r
+        /// function will be used.\r
+        /// </summary>\r
+        /// <param name="start">The cell to start at.</param>\r
+        /// <param name="finish">The desired destination.</param>\r
+        /// <returns>A list of points representing the path through the grid,\r
+        /// ends points not included, or null if no path could be found.</return>\r
+        public List<Point> GetPath(Point start, Point finish)\r
+        {\r
+            return GetPath(start, finish, GetManhattanDistance, GetCost);\r
+        }\r
+\r
+        /// <summary>\r
+        /// The A* algorithm for finding the best path through a grid of cells.\r
+        /// A simple distance-based cost function will be used.\r
+        /// </summary>\r
+        /// <param name="start">The cell to start at.</param>\r
+        /// <param name="finish">The desired destination.</param>\r
+        /// <param name="heuristic">The heuristic function.</param>\r
+        /// <returns>A list of points representing the path through the grid,\r
+        /// ends points not included, or null if no path could be found.</return>\r
+        public List<Point> GetPath(Point start, Point finish, Heuristic heuristic)\r
+        {\r
+            return GetPath(start, finish, heuristic, GetCost);\r
+        }\r
+\r
+        /// <summary>\r
+        /// The A* algorithm for finding the best path through a grid of cells.\r
+        /// The manhattan distance heuristic will be used.\r
+        /// </summary>\r
+        /// <param name="start">The cell to start at.</param>\r
+        /// <param name="finish">The desired destination.</param>\r
+        /// <param name="costFunction">The cost function</param>\r
+        /// <returns>A list of points representing the path through the grid,\r
+        /// ends points not included, or null if no path could be found.</return>\r
+        public List<Point> GetPath(Point start, Point finish, CostFunction costFunction)\r
+        {\r
+            return GetPath(start, finish, GetManhattanDistance, costFunction);\r
+        }\r
+\r
+        /// <summary>\r
+        /// The A* algorithm for finding the best path through a grid of cells.\r
+        /// </summary>\r
+        /// <param name="start">The cell to start at.</param>\r
+        /// <param name="finish">The desired destination.</param>\r
+        /// <param name="heuristic">The heuristic function.</param>\r
+        /// <param name="costFunction">The cost function.</param>\r
+        /// <returns>A list of points representing the path through the grid,\r
+        /// ends points not included, or null if no path could be found.</return>\r
+        public List<Point> GetPath(Point start, Point finish, Heuristic heuristic, CostFunction costFunction)\r
+        {\r
+            mFringe = new BinaryHeap<Cell>();\r
+            mCells = new Cell[mGridWidth, mGridHeight];\r
+\r
+            Cell startCell = new Cell(start, 0, GetManhattanDistance(start, finish));\r
+            mFringe.Add(startCell);\r
+            mCells[start.X, start.Y] = startCell;\r
+            while (mFringe.Count > 0)\r
+            {\r
+                Cell cell = mFringe.GetNext();\r
+                cell.IsOpen = false;\r
+\r
+                if (cell.Point == finish)\r
+                {\r
+                    List<Point> list = new List<Point>();\r
+\r
+                    cell = cell.Parent;\r
+                    while (cell.Point != start)\r
+                    {\r
+                        list.Add(cell.Point);\r
+                        cell = cell.Parent;\r
+                    }\r
+\r
+                    list.Reverse();\r
+                    return list;\r
+                }\r
+\r
+                List<Point> neighbors = new List<Point>(8);\r
+                neighbors.Add(new Point(cell.Point.X - 1, cell.Point.Y - 1));\r
+                neighbors.Add(new Point(cell.Point.X + 0, cell.Point.Y - 1));\r
+                neighbors.Add(new Point(cell.Point.X + 1, cell.Point.Y - 1));\r
+                neighbors.Add(new Point(cell.Point.X - 1, cell.Point.Y + 0));\r
+                neighbors.Add(new Point(cell.Point.X + 1, cell.Point.Y + 0));\r
+                neighbors.Add(new Point(cell.Point.X - 1, cell.Point.Y + 1));\r
+                neighbors.Add(new Point(cell.Point.X + 0, cell.Point.Y + 1));\r
+                neighbors.Add(new Point(cell.Point.X + 1, cell.Point.Y + 1));\r
+                foreach (Point point in neighbors)\r
+                {\r
+                    Cell inQueue = mCells[point.X, point.Y];\r
+\r
+                    if (0 <= point.X && point.X < mGridWidth && 0 <= point.Y && point.Y < mGridHeight &&\r
+                        mGrid[point.X, point.Y])\r
+                    {\r
+                        int cost = cell.G + GetCost(cell.Point, point);\r
+\r
+                        if (inQueue == null)\r
+                        {\r
+                            Cell neighbor = new Cell(point, cost, GetManhattanDistance(point, finish), cell);\r
+                            mFringe.Add(neighbor);\r
+                            mCells[point.X, point.Y] = neighbor;\r
+                        }\r
+                        else if (inQueue.IsOpen && cost < inQueue.G)\r
+                        {\r
+                            inQueue.G = cost;\r
+                            inQueue.Parent = cell;\r
+                            mFringe.Promote(inQueue);\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+\r
+            return null;\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Get the manhattan distance between two points.  This is a simple but\r
+        /// effective and commonly-used heuristic.\r
+        /// </summary>\r
+        /// <param name="a">A point.</param>\r
+        /// <param name="b">Another point.</param>\r
+        /// <returns>The manhattan distance.</returns>\r
+        public static int GetManhattanDistance(Point a, Point b)\r
+        {\r
+            int w = b.X - a.X;\r
+            int h = b.Y - a.Y;\r
+            if (w < 0) w = -w;\r
+            if (h < 0) h = -h;\r
+            return w + h;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Get the cost to travel from one point to another.  This is a simple\r
+        /// cost function based purely on distance.  On a square grid, diagonal\r
+        /// cells are further away than adjacent cells; therefore, adjacent moves\r
+        /// are favored.\r
+        /// </summary>\r
+        /// <param name="a">A point.</param>\r
+        /// <param name="b">Another point.</param>\r
+        /// <returns>The cost.</returns>\r
+        public static int GetCost(Point a, Point b)\r
+        {\r
+            if (a.X != b.X && a.Y != b.Y) return 14;\r
+            return 10;\r
+        }\r
+\r
+        #endregion\r
+\r
+\r
+        #region Private Types\r
+\r
+        class Cell : IComparable<Cell>\r
+        {\r
+            public Point Point;\r
+            public Cell Parent;\r
+            public bool IsOpen;\r
+\r
+            public int G\r
+            {\r
+                get { return mG; }\r
+                set { mG = value; mF = mG + mH; }\r
+            }\r
+\r
+            public int H\r
+            {\r
+                get { return mH; }\r
+                set { mH = value; mF = mG + mH; }\r
+            }\r
+\r
+            public int F { get { return mF; } }\r
+\r
+\r
+            public Cell(Point point, int g, int h)\r
+            {\r
+                Point = point;\r
+                IsOpen = true;\r
+                mG = g;\r
+                mH = h;\r
+                mF = g + h;\r
+            }\r
+\r
+            public Cell(Point point, int g, int h, Cell parent)\r
+            {\r
+                Point = point;\r
+                Parent = parent;\r
+                IsOpen = true;\r
+                mG = g;\r
+                mH = h;\r
+                mF = g + h;\r
+            }\r
+\r
+            public int CompareTo(Cell other)\r
+            {\r
+                return F - other.F;\r
+            }\r
+\r
+\r
+            int mG;\r
+            int mH;\r
+            int mF;\r
+        }\r
+\r
+        #endregion\r
+\r
+\r
+        #region Private Variables\r
+\r
+        bool[,] mGrid;\r
+        int mGridWidth;\r
+        int mGridHeight;\r
+\r
+        IPriorityQueue<Cell> mFringe;\r
+        Cell[,] mCells;\r
+\r
+        #endregion\r
+    }\r
+}\r
diff --git a/CarFire/CarFire/CarFire/PriorityQueue.cs b/CarFire/CarFire/CarFire/PriorityQueue.cs
new file mode 100644 (file)
index 0000000..df60ec0
--- /dev/null
@@ -0,0 +1,455 @@
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Diagnostics;\r
+\r
+namespace CarFire\r
+{\r
+    /// <summary>\r
+    /// Why .NET doesn't already provide such a basic data structure\r
+    /// as a priority queue is anybody's best guess.  This is an interface\r
+    /// for a queue class which treats the items themselves as keys,\r
+    /// the relative priorities being determined by a comparison between\r
+    /// them.\r
+    /// </summary>\r
+    /// <typeparam name="T">The type of item to queue.  This must be a\r
+    /// comparable class.</typeparam>\r
+    public interface IPriorityQueue<T> where T : IComparable<T>\r
+    {\r
+        /// <summary>\r
+        /// Add a new item to the priority queue.\r
+        /// </summary>\r
+        /// <param name="item">The item to add.</param>\r
+        void Add(T item);\r
+\r
+        /// <summary>\r
+        /// Get the item with the highest priority, removing it\r
+        /// from the priority queue.\r
+        /// </summary>\r
+        /// <returns>The highest priority item.</returns>\r
+        T GetNext();\r
+\r
+        /// <summary>\r
+        /// Get the item with the highest priority, but keep it in\r
+        /// the priority queue.\r
+        /// </summary>\r
+        /// <returns>The highest priority item.</returns>\r
+        T Peek();\r
+\r
+        /// <summary>\r
+        /// Notify the priority queue that the priority of a certain item\r
+        /// has improved.  If the items is not in the queue, it is added.\r
+        /// Do not use this to demote items.  The internal structures will\r
+        /// be reconfigured in order to ensure correct priority queueing.\r
+        /// </summary>\r
+        /// <param name="item">The item that improved.</param>\r
+        void Promote(T item);\r
+\r
+        /// <summary>\r
+        /// Remove all the items from the priority queue.\r
+        /// </summary>\r
+        void Clear();\r
+\r
+        /// <summary>\r
+        /// Get the number of items in the priority queue.\r
+        /// </summary>\r
+        int Count { get; }\r
+    }\r
+\r
+\r
+    /// <summary>\r
+    /// A minimum binary heap implementing a priority queue.\r
+    /// </summary>\r
+    /// <typeparam name="T">The type of items to load in the heap.</typeparam>\r
+    public class BinaryHeap<T> : IPriorityQueue<T> where T : IComparable<T>\r
+    {\r
+        #region Public Properties\r
+\r
+        /// <summary>\r
+        /// Get the number of items in the binary heap.\r
+        /// </summary>\r
+        public int Count { get { return mSize; } }\r
+\r
+        #endregion\r
+\r
+\r
+        #region Public Methods\r
+\r
+        /// <summary>\r
+        /// Construct a binary heap.\r
+        /// </summary>\r
+        public BinaryHeap()\r
+        {\r
+            mList.Add(default(T));\r
+        }\r
+\r
+        /// <summary>\r
+        /// Construct a binary heap with a predetermined capacity.\r
+        /// The heap is dynamically-sized, but it will be more\r
+        /// efficient if you set the capacity to the number of items\r
+        /// you plan to add.\r
+        /// </summary>\r
+        /// <param name="capacity">The capacity of the heap.</param>\r
+        public BinaryHeap(int capacity)\r
+        {\r
+            mList.Capacity = capacity;\r
+            mList.Add(default(T));\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Add a new item to the heap.\r
+        /// </summary>\r
+        /// <param name="item">The item to add.</param>\r
+        public void Add(T item)\r
+        {\r
+            mList.Add(item);\r
+            mSize++;\r
+            PercolateUp(mSize);\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Get the item with the lowest value, removing it from the heap.\r
+        /// </summary>\r
+        /// <returns>The highest priority item.</returns>\r
+        public T GetNext()\r
+        {\r
+            Debug.Assert(mSize > 0);\r
+\r
+            T next = mList[1];\r
+\r
+            mList[1] = mList[mSize];\r
+            PercolateDown(1);\r
+            mList.RemoveAt(mSize);\r
+            mSize--;\r
+\r
+            return next;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Get the item with the lowest value, but keep it in the heap.\r
+        /// </summary>\r
+        /// <returns>The highest priority item.</returns>\r
+        public T Peek()\r
+        {\r
+            Debug.Assert(mSize > 0);\r
+\r
+            return mList[1];\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Decrease the value of one of the items in the heap.  If the\r
+        /// item is not already in the heap, it is added.\r
+        /// </summary>\r
+        /// <param name="item">The item to change.</param>\r
+        public void Promote(T item)\r
+        {\r
+            for (int i = 1; i < mList.Count; i++)\r
+            {\r
+                if (item.Equals(mList[i]))\r
+                {\r
+                    mList[i] = item;\r
+                    if (PercolateUp(i) == i) PercolateDown(i);\r
+                    return;\r
+                }\r
+            }\r
+\r
+            Add(item);\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Remove all the items from the heap.\r
+        /// </summary>\r
+        public void Clear()\r
+        {\r
+            mList.Clear();\r
+            mSize = 0;\r
+        }\r
+\r
+        #endregion\r
+\r
+\r
+        #region Private Methods\r
+\r
+        int PercolateUp(int index)\r
+        {\r
+            T temp = mList[index];\r
+\r
+            for (int parent; index > 1; index = parent)\r
+            {\r
+                parent = index / 2;\r
+                if (temp.CompareTo(mList[parent]) < 0) mList[index] = mList[parent];\r
+                else break;\r
+            }\r
+\r
+            mList[index] = temp;\r
+            return index;\r
+        }\r
+\r
+        int PercolateDown(int index)\r
+        {\r
+            T temp = mList[index];\r
+\r
+            for (int child; index * 2 <= mSize; index = child)\r
+            {\r
+                child = index * 2;\r
+                if (child != mSize && mList[child].CompareTo(mList[child + 1]) > 0) child++;\r
+                if (temp.CompareTo(mList[child]) > 0) mList[index] = mList[child];\r
+                else break;\r
+            }\r
+\r
+            mList[index] = temp;\r
+            return index;\r
+        }\r
+\r
+        #endregion\r
+\r
+\r
+        #region Private Variables\r
+\r
+        List<T> mList = new List<T>();\r
+        int mSize = 0;\r
+\r
+        #endregion\r
+    }\r
+\r
+\r
+    /// <summary>\r
+    /// The binary heap might be too slow for shortest path algorithms,\r
+    /// so here is a fibonacci heap which should perform better.\r
+    /// </summary>\r
+    /// <typeparam name="T">The type of items to load in the heap.</typeparam>\r
+    public class FibonacciHeap<T> : IPriorityQueue<T> where T : IComparable<T>\r
+    {\r
+        #region Public Properties\r
+\r
+        /// <summary>\r
+        /// Get the number of items in the fibonacci heap.\r
+        /// </summary>\r
+        public int Count { get { return mCount; } }\r
+\r
+        #endregion\r
+\r
+\r
+        #region Public Methods\r
+\r
+        /// <summary>\r
+        /// Construct an empty fibonacci heap.\r
+        /// </summary>\r
+        public FibonacciHeap()\r
+        {\r
+            mList = new LinkedList<NodeInfo>();\r
+            mLookup = new Dictionary<T, LinkedListNode<NodeInfo>>();\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Add a new item to the heap.\r
+        /// </summary>\r
+        /// <param name="item">The item to add.</param>\r
+        public void Add(T item)\r
+        {\r
+            LinkedListNode<NodeInfo> node = mList.AddLast(new NodeInfo(item));\r
+            if (mMin == null || item.CompareTo(mMin.Value.Item) < 0) mMin = node;\r
+\r
+            mLookup[item] = node;\r
+            mCount++;\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Get the item with the lowest value, removing it from the heap.\r
+        /// </summary>\r
+        /// <returns>The highest priority item.</returns>\r
+        public T GetNext()\r
+        {\r
+            LinkedListNode<NodeInfo> temp = mMin;\r
+            mList.Remove(mMin);\r
+            mMin = null;\r
+\r
+            LinkedListNode<NodeInfo> node = temp.Value.Children.First;\r
+            while (node != null)\r
+            {\r
+                Cut(node);\r
+                node = temp.Value.Children.First;\r
+            }\r
+            Consolidate();\r
+\r
+            mLookup.Remove(temp.Value.Item);\r
+            mCount--;\r
+            return temp.Value.Item;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Get the item with the lowest value, but keep it in the heap.\r
+        /// </summary>\r
+        /// <returns>The highest priority item.</returns>\r
+        public T Peek()\r
+        {\r
+            return mMin.Value.Item;\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Decrease the value of one of the items in the heap.  If the\r
+        /// item is not already in the heap, it is added.\r
+        /// </summary>\r
+        /// <param name="item">The item to change.</param>\r
+        public void Promote(T item)\r
+        {\r
+            LinkedListNode<NodeInfo> node;\r
+            if (mLookup.TryGetValue(item, out node))\r
+            {\r
+                LinkedListNode<NodeInfo> parent = node.Value.Parent;\r
+                if (parent != null)\r
+                {\r
+                    if (node.Value.Item.CompareTo(parent.Value.Item) < 0)\r
+                    {\r
+                        Cut(node);\r
+                        CascadingCut(parent);\r
+                        if (node.Value.Item.CompareTo(mMin.Value.Item) < 0) mMin = node;\r
+                    }\r
+                }\r
+                else if (node.Value.Item.CompareTo(mMin.Value.Item) < 0) mMin = node;\r
+            }\r
+            else\r
+            {\r
+                Add(item);\r
+            }\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Remove all the items from the heap.\r
+        /// </summary>\r
+        public void Clear()\r
+        {\r
+            mList.Clear();\r
+            mMin = null;\r
+            mCount = 0;\r
+            mLookup.Clear();\r
+        }\r
+\r
+        #endregion\r
+\r
+\r
+        #region Private Methods\r
+\r
+        // Builds up the binomial trees.  More importantly, it sets the min\r
+        // pointeer and ensures that no root binomial tree has the same degree.\r
+        void Consolidate()\r
+        {\r
+            LinkedListNode<NodeInfo>[] degree = new LinkedListNode<NodeInfo>[64];\r
+\r
+            for (LinkedListNode<NodeInfo> node = mList.First; node != null;)\r
+            {\r
+                LinkedListNode<NodeInfo> match = degree[node.Value.Degree];\r
+                if (match == null)\r
+                {\r
+                    if (mMin == null || node.Value.Item.CompareTo(mMin.Value.Item) <= 0) mMin = node;\r
+                    degree[node.Value.Degree] = node;\r
+                    \r
+                    node = node.Next;\r
+                }\r
+                else\r
+                {\r
+                    degree[node.Value.Degree] = null;\r
+\r
+                    if (node.Value.Item.CompareTo(match.Value.Item) < 0)\r
+                    {\r
+                        Link(match, node);\r
+                    }\r
+                    else\r
+                    {\r
+                        mList.Remove(match);\r
+                        mList.AddAfter(node, match);\r
+                        Link(node, match);\r
+                        node = match;\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        // Removes child from whatever list it is in and makes it a child\r
+        // of parent.  This is for building up the binomial trees.\r
+        void Link(LinkedListNode<NodeInfo> child, LinkedListNode<NodeInfo> parent)\r
+        {\r
+            child.List.Remove(child);\r
+            parent.Value.Children.AddLast(child);\r
+            child.Value.Parent = parent;\r
+            child.Value.IsMarked = false;\r
+        }\r
+\r
+        // Removes node from whatever list it is in and makes it a root binomial\r
+        // tree.\r
+        void Cut(LinkedListNode<NodeInfo> node)\r
+        {\r
+            node.List.Remove(node);\r
+            mList.AddLast(node);\r
+            node.Value.Parent = null;\r
+            node.Value.IsMarked = false;\r
+        }\r
+\r
+        // Cuts each node that is marked, following the ancestry until it finds\r
+        // an unmarked ancestor (in which case it marks it) or a root node.\r
+        void CascadingCut(LinkedListNode<NodeInfo> node)\r
+        {\r
+            while (node.Value.Parent != null)\r
+            {\r
+                if (node.Value.IsMarked)\r
+                {\r
+                    Cut(node);\r
+                    node = node.Value.Parent;\r
+                }\r
+                else\r
+                {\r
+                    node.Value.IsMarked = true;\r
+                    break;\r
+                }\r
+            }\r
+        }\r
+\r
+        #endregion\r
+\r
+\r
+        #region Private Types\r
+\r
+        // This container class has the information we need to form\r
+        // a tree out of linked lists.\r
+        class NodeInfo\r
+        {\r
+            public LinkedListNode<NodeInfo> Parent;\r
+            public LinkedList<NodeInfo> Children = new LinkedList<NodeInfo>();\r
+            public bool IsMarked = false;\r
+\r
+            public int Degree { get { return Children.Count; } }\r
+\r
+            public T Item { get { return mItem; } }\r
+\r
+            public NodeInfo(T item)\r
+            {\r
+                mItem = item;\r
+            }\r
+\r
+            T mItem;\r
+        }\r
+\r
+        #endregion\r
+\r
+\r
+        #region Private Variables\r
+\r
+        LinkedList<NodeInfo> mList;\r
+        LinkedListNode<NodeInfo> mMin;\r
+        int mCount;\r
+\r
+        // To speed up promotions, we need a fast lookup for nodes.\r
+        Dictionary<T, LinkedListNode<NodeInfo>> mLookup;\r
+\r
+        #endregion\r
+    }\r
+}\r
diff --git a/CarFire/CarFire/CarFire/Script.cs b/CarFire/CarFire/CarFire/Script.cs
new file mode 100644 (file)
index 0000000..5ae6908
--- /dev/null
@@ -0,0 +1,50 @@
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+\r
+namespace CarFire\r
+{\r
+    public class Script\r
+    {\r
+        #region Public Types\r
+\r
+        public enum Status\r
+        {\r
+            Waiting,\r
+            Done,\r
+        }\r
+\r
+        public enum Function\r
+        {\r
+            Create,\r
+            Has,\r
+            Play,\r
+            Remove,\r
+            UseUp,\r
+            Wait,\r
+        }\r
+\r
+        #endregion\r
+\r
+\r
+        #region Public Methods\r
+\r
+        public Script(string code)\r
+        {\r
+        }\r
+\r
+        public Status Run()\r
+        {\r
+            return Status.Done;\r
+        }\r
+\r
+        public Status Evaluate(out bool value)\r
+        {\r
+            value = true;\r
+            return Status.Done;\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}\r
diff --git a/CarFire/CarFire/CarFire/Timer.cs b/CarFire/CarFire/CarFire/Timer.cs
new file mode 100644 (file)
index 0000000..01dfd77
--- /dev/null
@@ -0,0 +1,183 @@
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+\r
+namespace CarFire\r
+{\r
+    /// <summary>\r
+    /// A simple timer class.  I'm not sure why .NET or at least\r
+    /// XNA doesn't already have one of these.\r
+    /// </summary>\r
+    public class Timer<T> : IComparable<Timer<T>> where T : IComparable<T>\r
+    {\r
+        #region Public Properties\r
+\r
+        /// <summary>\r
+        /// Get and set the expiration time.  If the time is already set\r
+        /// and the timer is registered, you cannot push the expiration time\r
+        /// further back, but you can decrease it.\r
+        /// </summary>\r
+        public T Time\r
+        {\r
+            get\r
+            {\r
+                return mTime;\r
+            }\r
+            set\r
+            {\r
+                if (mTime.CompareTo(value) > 0)\r
+                {\r
+                    mTime = value;\r
+                    gTimers.Promote(this);\r
+                }\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Get the current absolute time, accurate up until\r
+        /// the last time Timer.FireAll was called.\r
+        /// </summary>\r
+        public static T Now { get { return gNow; } }\r
+\r
+        /// <summary>\r
+        /// Get and set the events that will be called when the\r
+        /// timer expires.\r
+        /// </summary>\r
+        public event ExpiredEventHandler Expired;\r
+\r
+        /// <summary>\r
+        /// Get and set a user contextual object.\r
+        /// </summary>\r
+        public object Context;\r
+\r
+        #endregion\r
+\r
+\r
+        #region Public Types\r
+\r
+        /// <summary>\r
+        /// The type for an event handler for timers that expire.\r
+        /// </summary>\r
+        /// <param name="timer">The timer that expired.</param>\r
+        public delegate void ExpiredEventHandler(Timer<T> timer);\r
+\r
+        #endregion\r
+\r
+\r
+        #region Public Methods\r
+\r
+        /// <summary>\r
+        /// Construct a timer with an absolute time (in seconds)\r
+        /// when the timer should expire.\r
+        /// </summary>\r
+        /// <param name="time">Absolute time, in seconds.</param>\r
+        public Timer(T time)\r
+        {\r
+            mTime = time;\r
+            gTimers.Add(this);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Construct a timer with an absolute time (in seconds)\r
+        /// when the timer should expire, and an event handler.\r
+        /// </summary>\r
+        /// <param name="time">Absolute time, in seconds.</param>\r
+        /// <param name="expired">An event handler.</param>\r
+        public Timer(T time, ExpiredEventHandler expired)\r
+        {\r
+            mTime = time;\r
+            Expired += expired;\r
+            gTimers.Add(this);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Construct a timer with an absolute time (in seconds)\r
+        /// when the timer should expire, and a contextual object.\r
+        /// </summary>\r
+        /// <param name="time">Absolute time, in seconds.</param>\r
+        /// <param name="context">A user contextual object.</param>\r
+        public Timer(T time, object context)\r
+        {\r
+            mTime = time;\r
+            Context = context;\r
+            gTimers.Add(this);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Construct a timer with an absolute time (in seconds)\r
+        /// when the timer should expire, an event handler, and a\r
+        /// contextual object.\r
+        /// </summary>\r
+        /// <param name="time">Absolute time, in seconds.</param>\r
+        /// <param name="expired">An event handler.</param>\r
+        /// <param name="context">A user contextual object.</param>\r
+        public Timer(T time, ExpiredEventHandler expired, object context)\r
+        {\r
+            mTime = time;\r
+            Expired += expired;\r
+            Context = context;\r
+            gTimers.Add(this);\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Fire all outstanding timers which should be expired\r
+        /// before a certain time.\r
+        /// </summary>\r
+        /// <param name="time">Absolute time, in seconds.</param>\r
+        public static void FireExpired(T time)\r
+        {\r
+            gNow = time;\r
+\r
+            while (gTimers.Count > 0)\r
+            {\r
+                Timer<T> timer = gTimers.Peek();\r
+                if (timer.Time.CompareTo(Now) <= 0)\r
+                {\r
+                    if (timer.Expired != null) timer.Expired(timer);\r
+                    if (timer.Time.CompareTo(Now) <= 0) gTimers.GetNext();\r
+                }\r
+                else\r
+                {\r
+                    break;\r
+                }\r
+            }\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Unregister all registered timers without firing any events.\r
+        /// </summary>\r
+        public static void Clear()\r
+        {\r
+            gTimers.Clear();\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Compare a timer with another, based on the expiration\r
+        /// times of both timers.\r
+        /// </summary>\r
+        /// <param name="other">The timer to compare against.</param>\r
+        /// <returns>A negative value if this timer is less than the\r
+        /// other, a positive value if this timer is greater than the\r
+        /// other, or zero if they are the same.</returns>\r
+        public int CompareTo(Timer<T> other)\r
+        {\r
+            return Time.CompareTo(other.Time);\r
+        }\r
+\r
+        #endregion\r
+\r
+\r
+        #region Private Variables\r
+\r
+        T mTime;\r
+\r
+        static IPriorityQueue<Timer<T>> gTimers = new BinaryHeap<Timer<T>>(10);\r
+        static T gNow;\r
+\r
+        #endregion\r
+    }\r
+}\r
This page took 0.056732 seconds and 4 git commands to generate.