public MultiPlayerServer(IGameplayEngine player1, IGameplayEngine player2, bool runUntilFullyConquered, bool runUntilWin) { _gameState = new GameState(); _timeout = 2000; _player1 = player1; _player2 = player2; _runUntilFullyConquered = runUntilFullyConquered; _runUntilWin = runUntilWin; }
/// <summary> /// Parses the "pick_starting_regions" line parts and issues the GetPreferredStartingRegions() method on the bot. /// </summary> /// <param name="bot"></param> /// <param name="parts"></param> /// <returns></returns> private static string PickStartingRegions(IGameplayEngine bot, string[] parts) { var pickable = GetPickableStartingRegions(bot.State.FullMap, parts); int timeout = int.Parse(parts[1]); var preferredStartingRegions = bot.GetPreferredStartingRegions(pickable, timeout); return string.Join(" ", preferredStartingRegions.Select(r => r.ID.ToString()).ToArray()); }
private static void ProcessSettings(IGameplayEngine bot, string[] parts) { if (parts[1] == "your_bot") { bot.Name = parts[2]; } bot.State.UpdateSettings(parts[1], parts[2]); }
public static string Parse(string line, IGameplayEngine bot) { string result = null; if (line == null) { // null indicates exit return null; } line = line.Trim(); if (line.Length == 0) { return ""; } String[] parts = InputParser.Split(line); if (parts[0].Equals("pick_starting_regions")) { result = PickStartingRegions(bot, parts); } else if (parts.Length == 3 && parts[0].Equals("go")) { result = Go(bot, parts); } else if (parts.Length == 3 && parts[0].Equals("settings")) { ProcessSettings(bot, parts); } else if (parts[0].Equals("setup_map")) { bot.State.SetupMap(parts); } else if (parts[0].Equals("update_map")) { //all visible regions are given bot.State.UpdateMap(parts); } else if (parts[0].Equals("opponent_moves")) { //all visible opponent moves are given bot.ProcessOpponentMoves(MoveParser.ParseMoves(bot.State.FullMap, line)); } else { Console.Error.WriteLine("Unable to parse line '{0}'", line); } return result; }
protected virtual List<Region> GetAndPrintStartingRegions(IGameplayEngine forPlayer, List<Region> startingRegions, int _timeout) { var regions = forPlayer.GetPreferredStartingRegions(startingRegions, _timeout); if (regions == null || !regions.Any()) { ConsoleExtensions.WriteColoredLine(ConsoleColor.Red, "Player `{0}` didn't pick any starting regions!", forPlayer.Name); } else { string selected = string.Join(" ", regions.Select(r => r.ID.ToString()).ToArray()); ConsoleExtensions.WriteColoredLine(ConsoleColor.Green, "Player `{0}` picked starting regions: {1}", forPlayer.Name, selected); } return regions; }
protected virtual void SendMapUpdateAndOutputMap(IGameplayEngine forPlayer) { forPlayer.State.UpdateMap(GetMapUpdate(forPlayer.Name)); ConsoleExtensions.WriteColoredLine(ConsoleColor.White, "Player `{0}` map: {1}", forPlayer.Name, forPlayer.State.FullMap.GetMapString()); }
protected virtual void Move(IGameplayEngine actingPlayer, AttackTransferMove move) { var fromRegion = _gameState.FullMap.GetRegionByID(move.FromRegion.ID); var toRegion = _gameState.FullMap.GetRegionByID(move.ToRegion.ID); if (move.Armies < 1) { ConsoleExtensions.WriteColoredLine(ConsoleColor.Red, "Player '{0}' tried to move {1} armies from region {2} to {3}, which is a bit silly. Move discarded.", move.PlayerName, move.Armies, fromRegion.ID, toRegion.ID, fromRegion.Armies); return; } if (fromRegion.PlayerName != move.PlayerName) { ConsoleExtensions.WriteColoredLine(ConsoleColor.Red, "Player '{0}' tried to move {1} armies from region {2} to {3}, but region {2} is not theirs. Move discarded.", move.PlayerName, move.Armies, fromRegion.ID, toRegion.ID); return; } if (move.Armies > fromRegion.ArmiesAvailable) { ConsoleExtensions.WriteColoredLine(ConsoleColor.Red, "Player '{0}' tried to move {1} armies from region {2} to {3}, but only {4} armies were remaining. Move discarded.", move.PlayerName, move.Armies, fromRegion.ID, toRegion.ID, fromRegion.Armies); return; } if (!fromRegion.Neighbors.Contains(toRegion)) { ConsoleExtensions.WriteColoredLine(ConsoleColor.Red, "Player '{0}' tried to move {1} armies from region {2} to {3}, but the regions are no neighbors. Move discarded.", move.PlayerName, move.Armies, fromRegion.ID, toRegion.ID); return; } if (move.PlayerName == toRegion.PlayerName) { MoveArmies(move.PlayerName, fromRegion, toRegion, move.Armies, move.MoveReason); } else { AttackHandler.HandleAttack(move, _gameState); } ConsoleExtensions.WriteColoredLine(ConsoleColor.Magenta, "Region {0} ('{1}'): {2} armies, Region {3} ('{4}'): {5} armies", fromRegion.ID, fromRegion.PlayerName, fromRegion.Armies, toRegion.ID, toRegion.PlayerName, toRegion.Armies); }
protected virtual int Place(IGameplayEngine actingPlayer, PlaceArmiesMove move, int armiesLeft) { Region region = _gameState.FullMap.GetRegionByID(move.Region.ID); if (region == null) { ConsoleExtensions.WriteColoredLine(ConsoleColor.Red, "Player '{0}' tried to place {1} armies on region {2}, which does not exist. Move discarded.", move.PlayerName, move.Armies, move.Region.ID, move.Region.PlayerName); return 0; } if (move.PlayerName != region.PlayerName) { ConsoleExtensions.WriteColoredLine(ConsoleColor.Red, "Player '{0}' tried to place {1} armies on region {2}, which is owned by '{3}' instead. Move discarded.", move.PlayerName, move.Armies, move.Region.ID, move.Region.PlayerName); return 0; } if (move.Armies < 1) { ConsoleExtensions.WriteColoredLine(ConsoleColor.Red, "Player '{0}' tried to place {1} armies on region {2}, which is a bit silly. Move discarded.", move.PlayerName, move.Armies, move.Region.ID); return 0; } if (move.Armies > armiesLeft) { ConsoleExtensions.WriteColoredLine(ConsoleColor.Red, "Player '{0}' places {1} armies on region {2}, but only {3} armies were remaining. Move discarded.", move.PlayerName, move.Armies, move.Region.ID, armiesLeft); return 0; } ConsoleExtensions.WriteColoredLine(ConsoleColor.DarkGreen, "Player '{0}' places {1} armies on region {2}.", move.PlayerName, move.Armies, move.Region.ID); region.Armies += move.Armies; region.ArmiesAvailable += move.Armies; ConsoleExtensions.WriteColoredLine(ConsoleColor.Magenta, "Region {0} ('{1}'): {2} armies", region.ID, region.PlayerName, region.Armies); return move.Armies; }
protected virtual void ApplyMovesToState(List<Move> moves, IGameplayEngine actingPlayer) { GameState.ResetRegions(_gameState.FullMap.Regions, resetOwnerAndArmies: false); int startingArmies = _gameState.GetStartingArmies(actingPlayer.Name); int armiesPlaced = 0; foreach (var move in moves) { if (move is AttackTransferMove) { Move(actingPlayer, move as AttackTransferMove); } else { int armiesPlacing = Place(actingPlayer, move as PlaceArmiesMove, startingArmies - armiesPlaced); armiesPlaced += armiesPlacing; } } }
protected virtual void ProcessPlayerMoves(IGameplayEngine actingPlayer, IGameplayEngine opponent, List<Move> moves) { if (!moves.Any()) { ConsoleExtensions.WriteColoredLine(ConsoleColor.Red, "Player '{0}' made no moves!", actingPlayer.Name); } ApplyMovesToState(moves, actingPlayer); opponent.ProcessOpponentMoves(moves); }
protected virtual bool HandleAttackTransferMoves(IGameplayEngine firstPlayer, IGameplayEngine secondPlayer) { var moves = firstPlayer.GetAttackTransferMoves(_timeout); ; ProcessPlayerMoves(firstPlayer, secondPlayer, moves.Cast<Move>().ToList()); if (DetectGameEnd()) { return true; } moves = secondPlayer.GetAttackTransferMoves(_timeout); ProcessPlayerMoves(secondPlayer, firstPlayer, moves.Cast<Move>().ToList()); if (DetectGameEnd()) { return true; } firstPlayer.State.UpdateMap(GetMapUpdate(firstPlayer.Name)); secondPlayer.State.UpdateMap(GetMapUpdate(secondPlayer.Name)); return false; }
/// <summary> /// Called when the bot needs to make a place_armies or attack/transfer move. /// </summary> /// <param name="bot"></param> /// <param name="parts"></param> /// <returns></returns> private static string Go(IGameplayEngine bot, string[] parts) { IEnumerable<Move> moves = null; int timeout = int.Parse(parts[2]); if (parts[1].Equals("place_armies")) { moves = bot.GetPlaceArmiesMoves(timeout).Cast<Move>(); } else if (parts[1].Equals("attack/transfer")) { moves = bot.GetAttackTransferMoves(timeout).Cast<Move>(); } else { throw new Exception(string.Format("Unkown go command '{0}'.", parts[1])); } if (moves == null || !moves.Any()) { return "No moves"; } else { string output = string.Join(",", moves.Select(m => m.GetCommandString()).ToArray()); return output; } }
public ConsoleServer(IGameplayEngine bot) { _bot = bot; }
/// <summary> /// /// </summary> /// <param name="mapFilename">Map file name.</param> /// <param name="stateFile">State file name, pass null for no state.</param> /// <param name="player1">Instance of bot for player1.</param> /// <param name="player2">Instance of bot for player2.</param> /// <param name="runUntilFullyConquered">If false and either bot loses its last region, the game ends. If true, then one player must conquer the entire map.</param> /// <param name="runUntilWin">When a draw occurs after _maxTurns turns (default: 100) and this parameter is set to false, the game ends. If set to true, the server will restart the game until either bot wins.</param> public TextFileMapServer(string mapFilename, string stateFile, IGameplayEngine player1, IGameplayEngine player2, bool runUntilFullyConquered, bool runUntilWin) : base(player1, player2, runUntilFullyConquered, runUntilWin) { _mapFilename = mapFilename; _stateFilename = stateFile; }