</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
<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
--- /dev/null
+[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
-; 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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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