static SiteEx GetNeighbor(Map map, SiteEx from, Direction direction) { var leftCoord = (ushort)(from.X == 0 ? (map.Width - 1) : from.X - 1); var rightCoord = (ushort)(from.X == (map.Width - 1) ? 0 : from.X + 1); var upCoord = (ushort)(from.Y == 0 ? (map.Height - 1) : from.Y - 1); var downCoord = (ushort)(from.Y == (map.Height - 1) ? 0 : from.Y + 1); switch (direction) { case Direction.West: return(new SiteEx(map, leftCoord, from.Y)); case Direction.East: return(new SiteEx(map, rightCoord, from.Y)); case Direction.North: return(new SiteEx(map, from.X, upCoord)); case Direction.South: return(new SiteEx(map, from.X, downCoord)); case Direction.Still: default: return(from); } }
private static Direction GetNearestNonPlayerDirection(Map map, SiteEx activeSite, ushort myID) { var lastTriedByDirection = new Dictionary <Direction, SiteEx>(); lastTriedByDirection.Add(Direction.West, activeSite); lastTriedByDirection.Add(Direction.East, activeSite); lastTriedByDirection.Add(Direction.North, activeSite); lastTriedByDirection.Add(Direction.South, activeSite); for (int tries = 0; tries < map.Width / 2; tries++) { foreach (var kvp in lastTriedByDirection.ToArray()) { if (NeighborInDirectionIsNonPlayer(map, kvp.Value, kvp.Key, myID)) { return(kvp.Key); } else { lastTriedByDirection[kvp.Key] = GetNeighbor(map, lastTriedByDirection[kvp.Key], kvp.Key); } } } return(Direction.Still); }
static SiteEx GetNeighbor(Map map, SiteEx from, Direction direction) { var leftCoord = (ushort)(from.X == 0 ? (map.Width - 1) : from.X - 1); var rightCoord = (ushort)(from.X == (map.Width - 1) ? 0 : from.X + 1); var upCoord = (ushort)(from.Y == 0 ? (map.Height - 1) : from.Y - 1); var downCoord = (ushort)(from.Y == (map.Height - 1) ? 0 : from.Y + 1); switch (direction) { case Direction.West: return(AllSites.First(s => s.X == leftCoord && s.Y == from.Y)); case Direction.East: return(AllSites.First(s => s.X == rightCoord && s.Y == from.Y)); case Direction.North: return(AllSites.First(s => s.X == from.X && s.Y == upCoord)); case Direction.South: return(AllSites.First(s => s.X == from.X && s.Y == downCoord)); case Direction.Still: default: return(from); } }
static List <SiteEx> GetAllNeighbors(Map map, SiteEx from) { var neighbors = new List <SiteEx> { GetNeighbor(map, @from, Direction.West), GetNeighbor(map, @from, Direction.East), GetNeighbor(map, @from, Direction.South), GetNeighbor(map, @from, Direction.North) }; return(neighbors); }
private static Direction GetMoveDirection(Map map, SiteEx startSite, SiteEx destinationSite) { if (destinationSite.X == map.Width - 1 && startSite.X == 0) { return(Direction.West); } if (destinationSite.X == 0 && startSite.X == map.Width - 1) { return(Direction.East); } if (destinationSite.X < startSite.X) { return(Direction.West); } if (destinationSite.X > startSite.X) { return(Direction.East); } if (destinationSite.Y == map.Height - 1 && startSite.Y == 0) { return(Direction.North); } if (destinationSite.Y == 0 && startSite.Y == map.Height - 1) { return(Direction.South); } if (destinationSite.Y < startSite.Y) { return(Direction.North); } if (destinationSite.Y > startSite.Y) { return(Direction.South); } throw new Exception("Your destionation is the same as your start site."); }
public static void Main(string[] args) { Console.SetIn(Console.In); Console.SetOut(Console.Out); ushort myID; var map = Networking.getInit(out myID); const ushort MAX_STRENGTH = 255; const ushort HALF_STRENGTH = 128; /* ------ * Do more prep work, see rules for time limit * ------ */ Networking.SendInit(MyBotName); // Acknoweldge the init and begin the game var random = new Random(); //var logFileName = string.Format(@"C:\Users\dolson\Source\Halite\Halite-C#-Starter-Package\Halite-C#-Starter-Package\log{0}.txt", DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")); var logFileName = string.Format("log{0}.txt", DateTime.Now.Ticks); AppendLog(logFileName, "Starting battle!"); int frameNumber = 0; while (true) { try { Networking.getFrame(ref map); // Update the map to reflect the moves before this turn } catch (Exception) { return; } frameNumber++; AppendLog(logFileName, string.Format("Frame {0}", frameNumber)); //Try to attack in a straight line to achive maximum "overkill" var previousAttackDirectionByLocation = new Dictionary <Location, Direction>(); var moves = new List <Move>(); for (ushort x = 0; x < map.Width; x++) { for (ushort y = 0; y < map.Height; y++) { if (map[x, y].Owner == myID) { var activeSite = new SiteEx(map, x, y); var neighbors = new List <SiteEx>() { GetNeighbor(map, activeSite, Direction.West), GetNeighbor(map, activeSite, Direction.East), GetNeighbor(map, activeSite, Direction.North), GetNeighbor(map, activeSite, Direction.South) }; var friendlySites = neighbors.Where(c => c.Owner == myID); var potentialLunchSites = neighbors.Where(c => c.Strength < activeSite.Strength && c.Owner != myID); var killSites = potentialLunchSites.Where(c => c.Owner != 0); var dangerSites = neighbors.Where(c => c.Strength > activeSite.Strength && c.Owner != myID && c.Owner != 0); //TODO: what to do with danger sites? //1. Continue an attack spearhead from previous turn first if (previousAttackDirectionByLocation.ContainsKey(activeSite.Location)) { var directionToMove = previousAttackDirectionByLocation[activeSite.Location]; previousAttackDirectionByLocation.Remove(activeSite.Location); var neighbor = GetNeighbor(map, activeSite, directionToMove); if (neighbor.Owner != myID && neighbor.Owner != 0) { previousAttackDirectionByLocation.Add(neighbor.Location, directionToMove); } moves.Add(new Move { Location = activeSite.Location, Direction = directionToMove }); } //2. Try to kill anything in sight else if (killSites.Any()) { var killSite = killSites.First(); var directionToMove = GetMoveDirection(map, activeSite, killSite); //AppendLog(logFileName, string.Format("Attack from [{0},{1}] (strength {4}) to [{2},{3}] (strength {5})", // activeSite.X, activeSite.Y, killSite.X, killSite.Y, activeSite.Strength, // killSite.Strength)); previousAttackDirectionByLocation.Add(GetNeighbor(map, activeSite, directionToMove).Location, directionToMove); moves.Add(new Move { Location = activeSite.Location, Direction = directionToMove }); } //3. Try to take over neutral else if (potentialLunchSites.Any()) { var lunchSite = potentialLunchSites.OrderByDescending(s => s.Production).First(); var directionToMove = GetMoveDirection(map, activeSite, lunchSite); //AppendLog(logFileName, string.Format( // "Consume Neutral from [{0},{1}] (strength {4}) to [{2},{3}] (strength {5})", // activeSite.X, activeSite.Y, lunchSite.X, lunchSite.Y, activeSite.Strength, // lunchSite.Strength)); moves.Add(new Move { Location = activeSite.Location, Direction = directionToMove }); } //3. Find a buddy to merge with //else if (friendlySites.Any(c => c.Strength < activeSite.Strength && c.Strength + activeSite.Strength > 25) && activeSite.Strength > 10) //{ // var friendSite = friendlySites.FirstOrDefault(c => c.Strength < activeSite.Strength && c.Strength + activeSite.Strength > 25); // var directionToMove = GetMoveDirection(map, activeSite, friendSite); // moves.Add(new Move // { // Location = activeSite.Location, // Direction = directionToMove // }); //} //4. If all neighbors are friendly, move towards nearest edge. else if (friendlySites.Count() == neighbors.Count && ((activeSite.Strength >= (activeSite.Production * 5)) || activeSite.Strength > HALF_STRENGTH)) { var nearestNonPlayerDirection = GetNearestNonPlayerDirection(map, activeSite, myID); if (nearestNonPlayerDirection != Direction.Still) { //AppendLog(logFileName, string.Format("Move to edge from [{0},{1}] (strength {3}) to {2}", // activeSite.X, activeSite.Y, nearestNonPlayerDirection, activeSite.Strength)); moves.Add(new Move { Location = activeSite.Location, Direction = nearestNonPlayerDirection }); } else //All orthagonal directions are occupied. { //TODO: could have logic here to find enemies or something, or go diagonally. } } ////4. TODO: If large enough, move towards the closest neutral edge. ////5. if all else fails, move randomly. //else if (neighbors.Any(n => n.Strength < activeSite.Strength)) //{ // moves.Add(new Move // { // Location = new Location { X = x, Y = y }, // Direction = (Direction)random.Next(5) // }); //} } } } Networking.SendMoves(moves); // Send moves } }
private static bool NeighborInDirectionIsNonPlayer(Map map, SiteEx site, Direction d, ushort myID) { var neighborSite = GetNeighbor(map, site, d); return(neighborSite.Owner != myID); }
private static Move?GetProductionSeekerBotMove(Map map, ushort x, ushort y) { //Borrows the code from ProductionSeekerBot2 var activeSite = new SiteEx(map, x, y); if ((activeSite.Strength < activeSite.Production * 3) && (activeSite.Strength < MAX_STRENGTH / 12)) { return(null); } var neighbors = new List <SiteEx>() { GetNeighbor(map, activeSite.Location, Direction.West), GetNeighbor(map, activeSite.Location, Direction.East), GetNeighbor(map, activeSite.Location, Direction.North), GetNeighbor(map, activeSite.Location, Direction.South) }; var friendlySites = neighbors.Where(c => c.Owner == _MyID); var friendlySitesWorthVisiting = friendlySites.Where( f => f.Strength > 0 && f.Strength + activeSite.Strength <MAX_STRENGTH && f.Production> (_MaxProductionValue / 4)); var neutralNeighbors = neighbors.Where(c => c.Owner == 0); var weakNeighborSites = neighbors.Where(c => (activeSite.Strength == MAX_STRENGTH || c.Production > 0) && c.Strength < activeSite.Strength && c.Owner == 0); bool shouldCombine = false; if (!weakNeighborSites.Any()) { if (activeSite.X + activeSite.Y % 2 == 1) //Only combine from every other square to prevent dancing. { shouldCombine = true; } } //Combine forces if we are a thin line. if (shouldCombine && friendlySitesWorthVisiting.Any()) { var destination = friendlySitesWorthVisiting.FirstOrDefault(f => f.Production > activeSite.Production); if (destination != null) { var directionToMove = GetMoveDirection(map, activeSite.Location, destination.Location); DarreksLog.AppendLog("Combine Forces!"); return(new Move { Location = activeSite.Location, Direction = directionToMove }); } } //1. Try to grow if (weakNeighborSites.Any()) { SiteEx lunchSiteToAttack = null; //Move Between enemies if possible for maximum damage! foreach (var pls in weakNeighborSites) { var nW = GetNeighbor(map, pls.Location, Direction.West); var nE = GetNeighbor(map, pls.Location, Direction.East); var nS = GetNeighbor(map, pls.Location, Direction.South); var nN = GetNeighbor(map, pls.Location, Direction.North); var enemyNeighborsCount = ((nW.Owner != _MyID && nW.Owner != 0) ? 1 : 0) + ((nE.Owner != _MyID && nE.Owner != 0) ? 1 : 0) + ((nS.Owner != _MyID && nS.Owner != 0) ? 1 : 0) + ((nN.Owner != _MyID && nN.Owner != 0) ? 1 : 0); if (enemyNeighborsCount > 1) { lunchSiteToAttack = pls; } } if (lunchSiteToAttack == null) { lunchSiteToAttack = weakNeighborSites.OrderByDescending(s => s.Production - s.Strength / 10).First(); } var directionToMove = GetMoveDirection(map, activeSite.Location, lunchSiteToAttack.Location); if (lunchSiteToAttack.Strength < activeSite.Strength) { return(new Move { Location = activeSite.Location, Direction = directionToMove }); } } //2. If all neighbors are friendly, move towards nearest edge. else if (activeSite.Strength > 0 && friendlySites.Count() == neighbors.Count && ((activeSite.Strength >= (activeSite.Production * 3)) || activeSite.Strength > HALF_STRENGTH / 2)) { ushort distanceFromEdge; var nearestNonPlayerDirection = GetNearestNonPlayerDirection(map, activeSite, _MyID, out distanceFromEdge); if (nearestNonPlayerDirection != Direction.Still) { return(new Move { Location = activeSite.Location, Direction = nearestNonPlayerDirection }); } else //All orthagonal directions are occupied. { return(new Move { Location = activeSite.Location, Direction = x % 2 == 1 ? Direction.North : Direction.South }); //TODO: could have logic here to find enemies or something, or go diagonally. } } return(null); }
private static Direction GetNearestFreeHighProductionDirection(Map map, SiteEx activeSite) //TODO: This needs to take into account the allowed directions. { //DarrekLog.AppendLog(string.Format("GetNearestFreeHighProductionDirection... Active site is [{0},{1}]", activeSite.X, activeSite.Y)); for (ushort distanceFromOrigin = 1; distanceFromOrigin < map.Width / 2; distanceFromOrigin++) { //DarrekLog.AppendLog("Distance 1..."); //make a square around the origin. for (var x = distanceFromOrigin * -1; x <= distanceFromOrigin; x++) { for (var y = distanceFromOrigin * -1; y <= distanceFromOrigin; y++) { if ((Math.Abs(y) != distanceFromOrigin) && (Math.Abs(x) != distanceFromOrigin)) { continue; // don't need to check this space again } //DarrekLog.AppendLog("Relative: " + x + ", " + y); var mapX = (ushort)((((int)activeSite.X) + x + map.Width) % map.Width); var mapY = (ushort)((((int)activeSite.Y) + y + map.Height) % map.Height); //DarrekLog.AppendLog(string.Format("Checking map[{0},{1}]...", mapX, mapY)); var toCheck = map[mapX, mapY]; if (toCheck.Owner != _MyID)// == 0) { //DarrekLog.AppendLog("Found neutral production area!"); if (toCheck.Production >= _TopProductionValuesGreaterThan) { DarrekLog.AppendLog(string.Format("Found acceptable neutral production area at [{1},{2}], value = {0}", toCheck.Production, mapX, mapY)); if (Math.Abs(x) <= Math.Abs(y)) { //DarrekLog.AppendLog("Moving Horizontally towards high production area"); if (x < 0) { DarrekLog.AppendLog("Heading West to HPA"); return(Direction.West); } else if (x > 0) { DarrekLog.AppendLog("Heading East to HPA"); return(Direction.East); } } else if (Math.Abs(x) > Math.Abs(y)) { //DarrekLog.AppendLog("Moving Vertically towards high production area"); if (y < 0) { DarrekLog.AppendLog("Heading North to HPA"); return(Direction.North); } else if (y > 0) { DarrekLog.AppendLog("Heading South to HPA"); return(Direction.South); } } else { DarrekLog.AppendLog("dammit!"); return(Direction.Still); } } } } } } return(Direction.Still); }
public static void Main(string[] args) { Console.SetIn(Console.In); Console.SetOut(Console.Out); var map = Networking.getInit(out _MyID); DarrekLog.LogFileName = String.Format("log{0}.txt", _MyID); const ushort MAX_STRENGTH = 255; const ushort HALF_STRENGTH = 128; /* ------ * Do more prep work, see rules for time limit * ------ */ Networking.SendInit(MyBotName); // Acknoweldge the init and begin the game var random = new Random(); DarrekLog.AppendLog("Starting battle!"); int frameNumber = 0; var movesTowardHighProductionByDirection = new Dictionary <Direction, ushort>(); movesTowardHighProductionByDirection.Add(Direction.North, 0); movesTowardHighProductionByDirection.Add(Direction.South, 0); movesTowardHighProductionByDirection.Add(Direction.East, 0); movesTowardHighProductionByDirection.Add(Direction.West, 0); while (true) { //try //{ Networking.getFrame(ref map); // Update the map to reflect the moves before this turn //} //catch (Exception) //{ // return; //} #region Check Production if (frameNumber == 0) { var sb = new StringBuilder(); sb.Append("production values:"); //TODO: find nearest high production zone and head there. for (ushort y = 0; y < map.Height; y++) { sb.Append("\r\n"); for (ushort x = 0; x < map.Width; x++) { var prodVal = map[x, y].Production; sb.Append(prodVal + " "); if (_MaxProductionValue < prodVal) { _MaxProductionValue = prodVal; } } } DarrekLog.AppendLog(sb.ToString()); _TopProductionValuesGreaterThan = (ushort)(_MaxProductionValue * .70); DarrekLog.AppendLog(string.Format("Max Production Value Found = {0}", _MaxProductionValue)); DarrekLog.AppendLog(string.Format("Top Production Values >= {0}", _TopProductionValuesGreaterThan)); } #endregion frameNumber++; DarrekLog.AppendLog(string.Format("Frame {0}", frameNumber)); movesTowardHighProductionByDirection[Direction.North] = 0; movesTowardHighProductionByDirection[Direction.South] = 0; movesTowardHighProductionByDirection[Direction.East] = 0; movesTowardHighProductionByDirection[Direction.West] = 0; var moves = new List <Move>(); for (ushort x = 0; x < map.Width; x++) { for (ushort y = 0; y < map.Height; y++) { if (map[x, y].Owner == _MyID) { var activeSite = new SiteEx(map, x, y); if (activeSite.Strength < MAX_STRENGTH / 10) { continue; } var neighbors = new List <SiteEx>() { GetNeighbor(map, activeSite, Direction.West), GetNeighbor(map, activeSite, Direction.East), GetNeighbor(map, activeSite, Direction.North), GetNeighbor(map, activeSite, Direction.South) }; var friendlySites = neighbors.Where(c => c.Owner == _MyID); var neutralNeighbors = neighbors.Where(c => c.Owner == 0); var potentialLunchSites = neighbors.Where(c => c.Strength < activeSite.Strength && c.Owner == 0); //1. Try to grow if (potentialLunchSites.Any()) { if (neutralNeighbors.Count() >= 3 || potentialLunchSites.Count() > 1) { var directionToMove = GetNearestFreeHighProductionDirection(map, activeSite); movesTowardHighProductionByDirection[directionToMove]++; if (GetNeighbor(map, activeSite, directionToMove).Strength < activeSite.Strength) { moves.Add(new Move { Location = activeSite.Location, Direction = directionToMove }); } } else { var lunchSite = potentialLunchSites.OrderByDescending(s => s.Production).First(); var directionToMove = GetMoveDirection(map, activeSite, lunchSite); moves.Add(new Move { Location = activeSite.Location, Direction = directionToMove }); continue; } } //2. If all neighbors are friendly, move where most of the blob is moving (toward high production) if (friendlySites.Count() == neighbors.Count && ((activeSite.Strength >= (activeSite.Production * 5)) || activeSite.Strength > HALF_STRENGTH)) { ushort distanceFromEdge; var nearestNonPlayerDirection = GetNearestNonPlayerDirection(map, activeSite, _MyID, out distanceFromEdge); if (movesTowardHighProductionByDirection.All(m => m.Value == 0) || distanceFromEdge > 3) { if (nearestNonPlayerDirection != Direction.Still) { moves.Add(new Move { Location = activeSite.Location, Direction = nearestNonPlayerDirection }); } else //All orthagonal directions are occupied. { //TODO: could have logic here to find enemies or something, or go diagonally. } } else { var blobMoveDirection = movesTowardHighProductionByDirection.First(m => m.Value == movesTowardHighProductionByDirection.Max(n => n.Value)).Key; DarrekLog.AppendLog(string.Format("Moving with blob to the {0}", blobMoveDirection)); moves.Add(new Move { Location = activeSite.Location, Direction = blobMoveDirection }); } } } } } Networking.SendMoves(moves); // Send moves } }
public static void Main(string[] args) { Console.SetIn(Console.In); Console.SetOut(Console.Out); ushort myID; var map = Networking.getInit(out myID); const ushort MAX_STRENGTH = 255; const ushort HALF_STRENGTH = 128; /* ------ * Do more prep work, see rules for time limit * ------ */ Networking.SendInit(MyBotName); // Acknoweldge the init and begin the game var random = new Random(); //var logFileName = string.Format(@"C:\Users\dolson\Source\Halite\Halite-C#-Starter-Package\Halite-C#-Starter-Package\log{0}.txt", DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")); var logFileName = string.Format("log{0}.txt", DateTime.Now.Ticks); AppendLog(logFileName, "Starting battle!"); int frameNumber = 0; while (true) { try { Networking.getFrame(ref map); // Update the map to reflect the moves before this turn } catch (Exception) { return; } frameNumber++; AppendLog(logFileName, string.Format("Frame {0}", frameNumber)); var moves = new List <Move>(); for (ushort x = 0; x < map.Width; x++) { for (ushort y = 0; y < map.Height; y++) { if (map[x, y].Owner == myID) { var activeSite = new SiteEx(map, x, y); if (activeSite.Strength < MAX_STRENGTH / 10) { continue; } var neighbors = new List <SiteEx>() { GetNeighbor(map, activeSite, Direction.West), GetNeighbor(map, activeSite, Direction.East), GetNeighbor(map, activeSite, Direction.North), GetNeighbor(map, activeSite, Direction.South) }; var friendlySites = neighbors.Where(c => c.Owner == myID); var potentialLunchSites = neighbors.Where(c => c.Strength < activeSite.Strength && c.Owner == 0); //1. Try to grow if (potentialLunchSites.Any()) { var lunchSite = potentialLunchSites.OrderByDescending(s => s.Production).First(); var directionToMove = GetMoveDirection(map, activeSite, lunchSite); moves.Add(new Move { Location = activeSite.Location, Direction = directionToMove }); } //2. If all neighbors are friendly, move towards nearest edge. else if (friendlySites.Count() == neighbors.Count && ((activeSite.Strength >= (activeSite.Production * 5)) || activeSite.Strength > HALF_STRENGTH)) { var nearestNonPlayerDirection = GetNearestNonPlayerDirection(map, activeSite, myID); if (nearestNonPlayerDirection != Direction.Still) { moves.Add(new Move { Location = activeSite.Location, Direction = nearestNonPlayerDirection }); } else //All orthagonal directions are occupied. { //TODO: could have logic here to find enemies or something, or go diagonally. } } } } } Networking.SendMoves(moves); // Send moves } }
public static void Main(string[] args) { Console.SetIn(Console.In); Console.SetOut(Console.Out); var map = Networking.getInit(out _MyID); DarrekLog.LogFileName = String.Format("log{0}.txt", _MyID); const ushort MAX_STRENGTH = 255; const ushort HALF_STRENGTH = 128; /* ------ * Do more prep work, see rules for time limit * ------ */ Networking.SendInit(MyBotName); // Acknoweldge the init and begin the game var random = new Random(); DarrekLog.AppendLog("Starting battle!"); int frameNumber = 0; while (true) { try { Networking.getFrame(ref map); // Update the map to reflect the moves before this turn } catch (Exception) { return; } #region Check Production if (frameNumber == 0) { var sb = new StringBuilder(); sb.Append("production values:"); //TODO: find nearest high production zone and head there. for (ushort y = 0; y < map.Height; y++) { sb.Append("\r\n"); for (ushort x = 0; x < map.Width; x++) { var prodVal = map[x, y].Production; sb.Append(prodVal + " "); if (_MaxProductionValue < prodVal) { _MaxProductionValue = prodVal; } } } DarrekLog.AppendLog(sb.ToString()); _TopProductionValuesGreaterThan = (ushort)(_MaxProductionValue * .70); DarrekLog.AppendLog(string.Format("Max Production Value Found = {0}", _MaxProductionValue)); DarrekLog.AppendLog(string.Format("Top Production Values >= {0}", _TopProductionValuesGreaterThan)); } #endregion frameNumber++; DarrekLog.AppendLog(string.Format("Frame {0}", frameNumber)); var moves = new List <Move>(); for (ushort x = 0; x < map.Width; x++) { for (ushort y = 0; y < map.Height; y++) { if (map[x, y].Owner == _MyID) { var activeSite = new SiteEx(map, x, y); if ((activeSite.Strength < activeSite.Production * 3) && (activeSite.Strength < MAX_STRENGTH / 12)) { continue; } var neighbors = new List <SiteEx>() { GetNeighbor(map, activeSite, Direction.West), GetNeighbor(map, activeSite, Direction.East), GetNeighbor(map, activeSite, Direction.North), GetNeighbor(map, activeSite, Direction.South) }; var friendlySites = neighbors.Where(c => c.Owner == _MyID); var friendlySitesWorthVisiting = friendlySites.Where( f => f.Strength > 0 && f.Strength + activeSite.Strength <MAX_STRENGTH && f.Production> (_MaxProductionValue / 4)); var neutralNeighbors = neighbors.Where(c => c.Owner == 0); var weakNeighborSites = neighbors.Where(c => (activeSite.Strength == MAX_STRENGTH || c.Production > 0) && c.Strength < activeSite.Strength && c.Owner == 0); bool shouldCombine = false; if (!weakNeighborSites.Any()) { if (activeSite.X + activeSite.Y % 2 == 1) //Only combine from every other square to prevent dancing. { shouldCombine = true; } } //Combine forces if we are a thin line. if (shouldCombine && friendlySitesWorthVisiting.Any()) { var destination = friendlySitesWorthVisiting.FirstOrDefault(f => f.Production > activeSite.Production); if (destination != null) { var directionToMove = GetMoveDirection(map, activeSite, destination); DarrekLog.AppendLog("Combine Forces!"); moves.Add(new Move { Location = activeSite.Location, Direction = directionToMove }); continue; } } //1. Try to grow if (weakNeighborSites.Any()) { SiteEx lunchSiteToAttack = null; //Move Between enemies if possible for maximum damage! foreach (var pls in weakNeighborSites) { var nW = GetNeighbor(map, pls, Direction.West); var nE = GetNeighbor(map, pls, Direction.East); var nS = GetNeighbor(map, pls, Direction.South); var nN = GetNeighbor(map, pls, Direction.North); var enemyNeighborsCount = ((nW.Owner != _MyID && nW.Owner != 0) ? 1 : 0) + ((nE.Owner != _MyID && nE.Owner != 0) ? 1 : 0) + ((nS.Owner != _MyID && nS.Owner != 0) ? 1 : 0) + ((nN.Owner != _MyID && nN.Owner != 0) ? 1 : 0); if (enemyNeighborsCount > 1) { lunchSiteToAttack = pls; } } if (lunchSiteToAttack == null) { lunchSiteToAttack = weakNeighborSites.OrderByDescending(s => s.Production - s.Strength / 10).First(); } var directionToMove = GetMoveDirection(map, activeSite, lunchSiteToAttack); if (lunchSiteToAttack.Strength < activeSite.Strength) { moves.Add(new Move { Location = activeSite.Location, Direction = directionToMove }); continue; } } //2. If all neighbors are friendly, move towards nearest edge. else if (activeSite.Strength > 0 && friendlySites.Count() == neighbors.Count && ((activeSite.Strength >= (activeSite.Production * 3)) || activeSite.Strength > HALF_STRENGTH / 2)) { ushort distanceFromEdge; var nearestNonPlayerDirection = GetNearestNonPlayerDirection(map, activeSite, _MyID, out distanceFromEdge); if (nearestNonPlayerDirection != Direction.Still) { moves.Add(new Move { Location = activeSite.Location, Direction = nearestNonPlayerDirection }); } else //All orthagonal directions are occupied. { moves.Add(new Move { Location = activeSite.Location, Direction = x % 2 == 1 ? Direction.North : Direction.South }); //TODO: could have logic here to find enemies or something, or go diagonally. } } } } } Networking.SendMoves(moves); // Send moves } }