diff --git a/Games/Stumped/AI.cs b/Games/Stumped/AI.cs index c723e15..424f771 100644 --- a/Games/Stumped/AI.cs +++ b/Games/Stumped/AI.cs @@ -101,6 +101,72 @@ public bool RunTurn() // <<-- /Creer-Merge: runTurn -->> } + /// + /// A very basic path finding algorithm (Breadth First Search) that when given a starting Tile, will return a valid path to the goal Tile. + /// + /// + /// This is NOT an optimal pathfinding algorithm. It is intended as a stepping stone if you want to improve it. + /// + /// the starting Tile + /// the goal Tile + /// A List of Tiles representing the path, the the first element being a valid adjacent Tile to the start, and the last element being the goal. Or an empty list if no path found. + List FindPath(Tile start, Tile goal) + { + // no need to make a path to here... + if (start == goal) + { + return new List(); + } + + // the tiles that will have their neighbors searched for 'goal' + Queue fringe = new Queue(); + + // How we got to each tile that went into the fringe. + Dictionary cameFrom = new Dictionary(); + + // Enqueue start as the first tile to have its neighbors searched. + fringe.Enqueue(start); + + // keep exploring neighbors of neighbors... until there are no more. + while (fringe.Count > 0) + { + // the tile we are currently exploring. + Tile inspect = fringe.Dequeue(); + + // cycle through the tile's neighbors. + foreach (Tile neighbor in inspect.GetNeighbors()) + { + if (neighbor == goal) + { + // Follow the path backward starting at the goal and return it. + List path = new List(); + path.Add(goal); + + // Starting at the tile we are currently at, insert them retracing our steps till we get to the starting tile + for (Tile step = inspect; step != start; step = cameFrom[step]) + { + path.Insert(0, step); + } + + return path; + } + + // if the tile exists, has not been explored or added to the fringe yet, and it is pathable + if (neighbor != null && !cameFrom.ContainsKey(neighbor) && neighbor.IsPathable()) + { + // add it to the tiles to be explored and add where it came from. + fringe.Enqueue(neighbor); + cameFrom.Add(neighbor, inspect); + } + + } // foreach(neighbor) + + } // while(fringe not empty) + + // if you're here, that means that there was not a path to get to where you want to go. + // in that case, we'll just return an empty path. + return new List(); + } // <<-- Creer-Merge: methods -->> - Code you add between this comment and the end comment will be preserved between Creer re-runs. // you can add additional methods here for your AI to call diff --git a/Games/Stumped/Beaver.cs b/Games/Stumped/Beaver.cs index 5056ca4..946036c 100644 --- a/Games/Stumped/Beaver.cs +++ b/Games/Stumped/Beaver.cs @@ -21,37 +21,37 @@ class Beaver : Stumped.GameObject { #region Properties /// - /// The number of actions remaining for the beaver this turn. + /// The number of actions remaining for the Beaver this turn. /// public int Actions { get; protected set; } /// - /// The number of branches this beaver is holding. + /// The amount of branches this Beaver is holding. /// public int Branches { get; protected set; } /// - /// The number of fish this beaver is holding. + /// The amount of food this Beaver is holding. /// - public int Fish { get; protected set; } + public int Food { get; protected set; } /// - /// How much health this beaver has left. + /// How much health this Beaver has left. /// public int Health { get; protected set; } /// - /// The Job this beaver was recruited to do. + /// The Job this Beaver was recruited to do. /// public Stumped.Job Job { get; protected set; } /// - /// How many moves this beaver has left this turn. + /// How many moves this Beaver has left this turn. /// public int Moves { get; protected set; } /// - /// The Player that owns and can control this beaver. + /// The Player that owns and can control this Beaver. /// public Stumped.Player Owner { get; protected set; } @@ -61,12 +61,12 @@ class Beaver : Stumped.GameObject public bool Recruited { get; protected set; } /// - /// The tile this beaver is on. + /// The Tile this Beaver is on. /// public Stumped.Tile Tile { get; protected set; } /// - /// Number of turns this beaver is distracted for (0 means not distracted). + /// Number of turns this Beaver is distracted for (0 means not distracted). /// public int TurnsDistracted { get; protected set; } @@ -88,7 +88,7 @@ protected Beaver() : base() /// /// Attacks another adjacent beaver. /// - /// The beaver to attack. Must be on an adjacent tile. + /// The Beaver to attack. Must be on an adjacent Tile. /// True if successfully attacked, false otherwise. public bool Attack(Stumped.Beaver beaver) { @@ -98,7 +98,7 @@ public bool Attack(Stumped.Beaver beaver) } /// - /// Builds a lodge on the Beavers current tile. + /// Builds a lodge on the Beavers current Tile. /// /// True if successfully built a lodge, false otherwise. public bool BuildLodge() @@ -108,11 +108,11 @@ public bool BuildLodge() } /// - /// Drops some of the given resource on the beaver's tile. Fish dropped in water disappear instantly, and fish dropped on land die one per tile per turn. + /// Drops some of the given resource on the beaver's Tile. /// - /// The Tile to drop branches/fish on. Must be the same Tile that the Beaver is on, or an adjacent one. - /// The type of resource to drop ('branch' or 'fish'). - /// The amount of the resource to drop, numbers <= 0 will drop all the resource type. + /// The Tile to drop branches/food on. Must be the same Tile that the Beaver is on, or an adjacent one. + /// The type of resource to drop ('branch' or 'food'). + /// The amount of the resource to drop, numbers <= 0 will drop all the resource type. /// True if successfully dropped the resource, false otherwise. public bool Drop(Stumped.Tile tile, string resource, int amount=0) { @@ -124,9 +124,9 @@ public bool Drop(Stumped.Tile tile, string resource, int amount=0) } /// - /// Harvests the branches or fish from a Spawner on an adjacent tile. + /// Harvests the branches or food from a Spawner on an adjacent Tile. /// - /// The Spawner you want to harvest. Must be on an adjacent tile. + /// The Spawner you want to harvest. Must be on an adjacent Tile. /// True if successfully harvested, false otherwise. public bool Harvest(Stumped.Spawner spawner) { @@ -136,9 +136,9 @@ public bool Harvest(Stumped.Spawner spawner) } /// - /// Moves this beaver from its current tile to an adjacent tile. + /// Moves this Beaver from its current Tile to an adjacent Tile. /// - /// The tile this beaver should move to. + /// The Tile this Beaver should move to. /// True if the move worked, false otherwise. public bool Move(Stumped.Tile tile) { @@ -148,11 +148,11 @@ public bool Move(Stumped.Tile tile) } /// - /// Picks up some branches or fish on the beaver's tile. + /// Picks up some branches or food on the beaver's tile. /// - /// The Tile to pickup branches/fish from. Must be the same Tile that the Beaver is on, or an adjacent one. - /// The type of resource to pickup ('branch' or 'fish'). - /// The amount of the resource to drop, numbers <= 0 will pickup all of the resource type. + /// The Tile to pickup branches/food from. Must be the same Tile that the Beaver is on, or an adjacent one. + /// The type of resource to pickup ('branch' or 'food'). + /// The amount of the resource to drop, numbers <= 0 will pickup all of the resource type. /// True if successfully picked up a resource, false otherwise. public bool Pickup(Stumped.Tile tile, string resource, int amount=0) { @@ -164,6 +164,7 @@ public bool Pickup(Stumped.Tile tile, string resource, int amount=0) } + // <<-- Creer-Merge: methods -->> - Code you add between this comment and the end comment will be preserved between Creer re-runs. // you can add additional method(s) here. // <<-- /Creer-Merge: methods -->> diff --git a/Games/Stumped/Game.cs b/Games/Stumped/Game.cs index 9994a04..0a114ea 100644 --- a/Games/Stumped/Game.cs +++ b/Games/Stumped/Game.cs @@ -25,11 +25,6 @@ class Game : BaseGame /// public IList Beavers { get; protected set; } - /// - /// How many branches a lodge must have to be considered complete. - /// - public int BranchesToCompleteLodge { get; protected set; } - /// /// The player whose turn it is currently. That player can send commands. Other players cannot. /// @@ -41,7 +36,7 @@ class Game : BaseGame public int CurrentTurn { get; protected set; } /// - /// When a Player has less Beavers than this number, recruiting other Beavers is free. + /// When a Player has less Beavers than this number, then recruiting other Beavers is free. /// public int FreeBeaversCount { get; protected set; } @@ -56,9 +51,9 @@ class Game : BaseGame public double LodgeCostConstant { get; protected set; } /// - /// How many lodges must be complete at once to win the game. + /// How many lodges must be owned by a Player at once to win the game. /// - public int LodgesCompleteToWin { get; protected set; } + public int LodgesToWin { get; protected set; } /// /// The number of Tiles in the map along the y (vertical) axis. @@ -91,12 +86,12 @@ class Game : BaseGame public IList Spawner { get; protected set; } /// - /// Constant number used to calculate how many breanches/fish Beavers harvest from spawners. + /// Constant number used to calculate how many branches/food Beavers harvest from Spawners. /// public double SpawnerHarvestConstant { get; protected set; } /// - /// All the types of spawners in the game. + /// All the types of Spawners in the game. /// public IList SpawnerTypes { get; protected set; } @@ -129,6 +124,23 @@ protected Game() : base() } + /// + /// Gets the Tile at a specified (x, y) position + /// + /// integer between 0 and the MapWidth + /// integer between 0 and the MapHeight + /// the Tile at (x, y) or null if out of bounds + public Tile GetTileAt(int x, int y) + { + if (x < 0 || y < 0 || x >= this.MapWidth || y >= this.MapHeight) + { + // out of bounds + return null; + } + + return this.Tiles[x + y * this.MapWidth]; + } + // <<-- Creer-Merge: methods -->> - Code you add between this comment and the end comment will be preserved between Creer re-runs. // you can add additional method(s) here. // <<-- /Creer-Merge: methods -->> diff --git a/Games/Stumped/GameObject.cs b/Games/Stumped/GameObject.cs index 2e60061..891fffd 100644 --- a/Games/Stumped/GameObject.cs +++ b/Games/Stumped/GameObject.cs @@ -58,6 +58,7 @@ public void Log(string message) } + // <<-- Creer-Merge: methods -->> - Code you add between this comment and the end comment will be preserved between Creer re-runs. // you can add additional method(s) here. // <<-- /Creer-Merge: methods -->> diff --git a/Games/Stumped/Job.cs b/Games/Stumped/Job.cs index 83cbf53..d433cf6 100644 --- a/Games/Stumped/Job.cs +++ b/Games/Stumped/Job.cs @@ -21,52 +21,52 @@ class Job : Stumped.GameObject { #region Properties /// - /// The number of actions this job can make per turn. + /// The number of actions this Job can make per turn. /// public int Actions { get; protected set; } /// - /// How many resources a beaver with this job can hold at once. + /// How many combined resources a beaver with this Job can hold at once. /// public int CarryLimit { get; protected set; } /// - /// Scalar for how many branches this job harvests at once. + /// Scalar for how many branches this Job harvests at once. /// public int Chopping { get; protected set; } /// - /// How many fish this Job costs to recruit. + /// How much food this Job costs to recruit. /// public int Cost { get; protected set; } /// - /// The amount of damage this job does per attack. + /// The amount of damage this Job does per attack. /// public int Damage { get; protected set; } /// - /// How many turns a beaver attacked by this job is distracted by. + /// How many turns a beaver attacked by this Job is distracted by. /// public int DistractionPower { get; protected set; } /// - /// Scalar for how many fish this job harvests at once. + /// The amount of starting health this Job has. /// - public int Fishing { get; protected set; } + public int Health { get; protected set; } /// - /// The amount of starting health this job has. + /// The number of moves this Job can make per turn. /// - public int Health { get; protected set; } + public int Moves { get; protected set; } /// - /// The number of moves this job can make per turn. + /// Scalar for how much food this Job harvests at once. /// - public int Moves { get; protected set; } + public int Munching { get; protected set; } /// - /// The job title ('builder', 'fisher', etc). + /// The Job title. /// public string Title { get; protected set; } @@ -98,6 +98,7 @@ public Stumped.Beaver Recruit(Stumped.Tile tile) } + // <<-- Creer-Merge: methods -->> - Code you add between this comment and the end comment will be preserved between Creer re-runs. // you can add additional method(s) here. // <<-- /Creer-Merge: methods -->> diff --git a/Games/Stumped/Player.cs b/Games/Stumped/Player.cs index 069c581..6a969bb 100644 --- a/Games/Stumped/Player.cs +++ b/Games/Stumped/Player.cs @@ -26,7 +26,7 @@ class Player : Stumped.GameObject public IList Beavers { get; protected set; } /// - /// How many branches are required to build a lodge for this player. + /// How many branches are required to build a lodge for this Player. /// public int BranchesToBuildLodge { get; protected set; } @@ -36,7 +36,7 @@ class Player : Stumped.GameObject public string ClientType { get; protected set; } /// - /// A list of tiles that contain lodges owned by this player. + /// A list of Tiles that contain lodges owned by this player. /// public IList Lodges { get; protected set; } @@ -93,6 +93,7 @@ protected Player() : base() } + // <<-- Creer-Merge: methods -->> - Code you add between this comment and the end comment will be preserved between Creer re-runs. // you can add additional method(s) here. // <<-- /Creer-Merge: methods -->> diff --git a/Games/Stumped/Spawner.cs b/Games/Stumped/Spawner.cs index 5582e06..fca67d6 100644 --- a/Games/Stumped/Spawner.cs +++ b/Games/Stumped/Spawner.cs @@ -1,4 +1,4 @@ -// A resource spawner that generates branches or fish. +// A resource spawner that generates branches or food. // DO NOT MODIFY THIS FILE // Never try to directly create an instance of this class, or modify its member variables. @@ -15,7 +15,7 @@ namespace Joueur.cs.Games.Stumped { /// - /// A resource spawner that generates branches or fish. + /// A resource spawner that generates branches or food. /// class Spawner : Stumped.GameObject { @@ -26,17 +26,17 @@ class Spawner : Stumped.GameObject public bool HasBeenHarvested { get; protected set; } /// - /// How much health this spawner has, which is used to calculate how much of its resource can be harvested. + /// How much health this Spawner has, which is used to calculate how much of its resource can be harvested. /// public int Health { get; protected set; } /// - /// The tile this Spawner is on. + /// The Tile this Spawner is on. /// public Stumped.Tile Tile { get; protected set; } /// - /// What type of resource this is ('Fish' or 'Branch'). + /// What type of resource this is ('food' or 'branches'). /// public string Type { get; protected set; } @@ -56,6 +56,7 @@ protected Spawner() : base() } + // <<-- Creer-Merge: methods -->> - Code you add between this comment and the end comment will be preserved between Creer re-runs. // you can add additional method(s) here. // <<-- /Creer-Merge: methods -->> diff --git a/Games/Stumped/Tile.cs b/Games/Stumped/Tile.cs index 82b5eaa..a0b56dc 100644 --- a/Games/Stumped/Tile.cs +++ b/Games/Stumped/Tile.cs @@ -21,32 +21,32 @@ class Tile : Stumped.GameObject { #region Properties /// - /// The beaver on this tile if present, otherwise null. + /// The Beaver on this Tile if present, otherwise null. /// public Stumped.Beaver Beaver { get; protected set; } /// - /// The number of branches dropped on this tile. + /// The number of branches dropped on this Tile. /// public int Branches { get; protected set; } /// - /// The number of fish dropped on this tile. + /// The cardinal direction water is flowing on this Tile ('North', 'East', 'South', 'West'). /// - public int Fish { get; protected set; } + public string FlowDirection { get; protected set; } /// - /// The cardinal direction water is flowing on this tile ('North', 'East', 'South', 'West'). + /// The number of food dropped on this Tile. /// - public string FlowDirection { get; protected set; } + public int Food { get; protected set; } /// - /// The owner of the beaver lodge on this tile, if present, otherwise null. + /// The owner of the Beaver lodge on this Tile, if present, otherwise null. /// public Stumped.Player LodgeOwner { get; protected set; } /// - /// The resource spawner on this tile if present, otherwise null. + /// The resource Spawner on this Tile if present, otherwise null. /// public Stumped.Spawner Spawner { get; protected set; } @@ -101,6 +101,63 @@ protected Tile() : base() } + /// + /// Gets the neighbors of this Tile + /// + /// The neighboring (adjacent) Tiles to this tile + public List GetNeighbors() + { + var list = new List(); + + if (this.TileNorth != null) + { + list.Add(this.TileNorth); + } + + if (this.TileEast != null) + { + list.Add(this.TileEast); + } + + if (this.TileSouth != null) + { + list.Add(this.TileSouth); + } + + if (this.TileWest != null) + { + list.Add(this.TileWest); + } + + return list; + } + + /// + /// Checks if a Tile is pathable to units + /// + /// True if pathable, false otherwise + public bool IsPathable() + { + // <<-- Creer-Merge: is_pathable_builtin -->> - Code you add between this comment and the end comment will be preserved between Creer re-runs. + return false; // DEVELOPER ADD LOGIC HERE + // <<-- /Creer-Merge: is_pathable_builtin -->> + } + + /// + /// Checks if this Tile has a specific neighboring Tile + /// + /// Tile to check against + /// true if the tile is a neighbor of this Tile, false otherwise + public bool HasNeighbor(Tile tile) + { + if (tile == null) + { + return false; + } + + return (this.TileNorth == tile || this.TileEast == tile || this.TileSouth == tile || this.TileEast == tile); + } + // <<-- Creer-Merge: methods -->> - Code you add between this comment and the end comment will be preserved between Creer re-runs. // you can add additional method(s) here. // <<-- /Creer-Merge: methods -->> diff --git a/_creer/Games/${game_name}/${obj_key}.cs b/_creer/Games/${game_name}/${obj_key}.cs index f43587e..46718d5 100644 --- a/_creer/Games/${game_name}/${obj_key}.cs +++ b/_creer/Games/${game_name}/${obj_key}.cs @@ -26,7 +26,7 @@ namespace Joueur.cs.Games.${game_name} { /// - /// ${obj['description']} + /// ${shared['c#']['escape'](obj['description'])} /// class ${obj_key} : ${inherit_str} { @@ -36,7 +36,7 @@ class ${obj_key} : ${inherit_str} if (obj_key == "Game" and (attr_name == "gameObjects" or attr_name == "name")) or attr_name == "id": continue %> /// - /// ${attr_parms['description']} + /// ${shared['c#']['escape'](attr_parms['description'])} /// public ${shared['c#']['type'](attr_parms['type'])} ${upcase_first(attr_name)} { get; protected set; } @@ -70,16 +70,16 @@ class ${obj_key} : ${inherit_str} arg_strings = [] return_type = None %> /// - /// ${function_parms['description']} + /// ${shared['c#']['escape'](function_parms['description'])} /// % if 'arguments' in function_parms: % for arg_parms in function_parms['arguments']: - /// ${arg_parms['description']} + /// ${shared['c#']['escape'](arg_parms['description'])} % endfor % endif % if function_parms['returns']: <% return_type = shared['c#']['type'](function_parms['returns']['type']) -%> /// ${function_parms['returns']['description']} +%> /// ${shared['c#']['escape'](function_parms['returns']['description'])} % endif public ${return_type or 'void'} ${upcase_first(function_name)}(${shared['c#']['args'](function_parms['arguments'])}) { @@ -92,6 +92,84 @@ class ${obj_key} : ${inherit_str} % endfor +% if 'Tile' in game_objs: +% if 'TiledGame' in game['serverParentClasses']: #// then we need to add some client side utility functions +% if obj_key == 'Game': + /// + /// Gets the Tile at a specified (x, y) position + /// + /// integer between 0 and the MapWidth + /// integer between 0 and the MapHeight + /// the Tile at (x, y) or null if out of bounds + public Tile GetTileAt(int x, int y) + { + if (x < 0 || y < 0 || x >= this.MapWidth || y >= this.MapHeight) + { + // out of bounds + return null; + } + + return this.Tiles[x + y * this.MapWidth]; + } +% elif obj_key == 'Tile': + /// + /// Gets the neighbors of this Tile + /// + /// The neighboring (adjacent) Tiles to this tile + public List GetNeighbors() + { + var list = new List(); + + if (this.TileNorth != null) + { + list.Add(this.TileNorth); + } + + if (this.TileEast != null) + { + list.Add(this.TileEast); + } + + if (this.TileSouth != null) + { + list.Add(this.TileSouth); + } + + if (this.TileWest != null) + { + list.Add(this.TileWest); + } + + return list; + } + + /// + /// Checks if a Tile is pathable to units + /// + /// True if pathable, false otherwise + public bool IsPathable() + { +${merge(" // ", "is_pathable_builtin", " return false; // DEVELOPER ADD LOGIC HERE")} + } + + /// + /// Checks if this Tile has a specific neighboring Tile + /// + /// Tile to check against + /// true if the tile is a neighbor of this Tile, false otherwise + public bool HasNeighbor(Tile tile) + { + if (tile == null) + { + return false; + } + + return (this.TileNorth == tile || this.TileEast == tile || this.TileSouth == tile || this.TileEast == tile); + } +% endif +% endif + +% endif ${merge(" // ", "methods", " // you can add additional method(s) here.", optional=True)} #endregion } diff --git a/_creer/Games/${game_name}/AI.cs b/_creer/Games/${game_name}/AI.cs index 586db85..daff790 100644 --- a/_creer/Games/${game_name}/AI.cs +++ b/_creer/Games/${game_name}/AI.cs @@ -102,7 +102,75 @@ public override void Ended(bool won, string reason) } % endfor +% if 'TiledGame' in game['serverParentClasses']: #// then we need to add some client side utility functions + /// + /// A very basic path finding algorithm (Breadth First Search) that when given a starting Tile, will return a valid path to the goal Tile. + /// + /// + /// This is NOT an optimal pathfinding algorithm. It is intended as a stepping stone if you want to improve it. + /// + /// the starting Tile + /// the goal Tile + /// A List of Tiles representing the path, the the first element being a valid adjacent Tile to the start, and the last element being the goal. Or an empty list if no path found. + List FindPath(Tile start, Tile goal) + { + // no need to make a path to here... + if (start == goal) + { + return new List(); + } + + // the tiles that will have their neighbors searched for 'goal' + Queue fringe = new Queue(); + + // How we got to each tile that went into the fringe. + Dictionary cameFrom = new Dictionary(); + + // Enqueue start as the first tile to have its neighbors searched. + fringe.Enqueue(start); + + // keep exploring neighbors of neighbors... until there are no more. + while (fringe.Count > 0) + { + // the tile we are currently exploring. + Tile inspect = fringe.Dequeue(); + // cycle through the tile's neighbors. + foreach (Tile neighbor in inspect.GetNeighbors()) + { + if (neighbor == goal) + { + // Follow the path backward starting at the goal and return it. + List path = new List(); + path.Add(goal); + + // Starting at the tile we are currently at, insert them retracing our steps till we get to the starting tile + for (Tile step = inspect; step != start; step = cameFrom[step]) + { + path.Insert(0, step); + } + + return path; + } + + // if the tile exists, has not been explored or added to the fringe yet, and it is pathable + if (neighbor != null && !cameFrom.ContainsKey(neighbor) && neighbor.IsPathable()) + { + // add it to the tiles to be explored and add where it came from. + fringe.Enqueue(neighbor); + cameFrom.Add(neighbor, inspect); + } + + } // foreach(neighbor) + + } // while(fringe not empty) + + // if you're here, that means that there was not a path to get to where you want to go. + // in that case, we'll just return an empty path. + return new List(); + } + +% endif ${merge(" // ", "methods", ' // you can add additional methods here for your AI to call', optional=True)} #endregion } diff --git a/_creer/Games/${game_name}/functions.noCreer b/_creer/Games/${game_name}/functions.noCreer index 53a234a..b04201b 100644 --- a/_creer/Games/${game_name}/functions.noCreer +++ b/_creer/Games/${game_name}/functions.noCreer @@ -2,6 +2,20 @@ if not 'c#' in shared: shared['c#'] = {} + def cs_escape(s): + """ + Returns the ASCII decoded version of the given HTML string. This does + NOT remove normal HTML tags like

. + """ + htmlCodes = ( + ('>', '>'), + ('<', '<') + ) + for code in htmlCodes: + s = s.replace(code[0], code[1]) + return s + shared['c#']['escape'] = cs_escape + def cs_default(type_obj, default=None): base_type = type_obj['name'] if default == None: