public static void Main(string[] args) { // For Debug bool readFromFile = false; BoardStaticData.Load(readFromFile); var manager = new StrategyManager(); // game loop while (true) { var board = new Board(); board.LoadTurn(readFromFile); if (manager.GameTurn == 0) { BoardStaticData.Init(board); // Init my start position etc... } List <IAction> actions = manager.ComputeActions(board); Console.WriteLine(string.Join(" ; ", actions.Select(a => a.GetActionString()).ToArray())); ++manager.GameTurn; } }
public static void Init(Board board) { BoardStaticData.MiddleId = 0; BoardStaticData.MyStartId = board.Factories.First(f => f.Owner == 1).Id; BoardStaticData.EnnemyStartId = board.Factories.First(f => f.Owner == -1).Id; BoardStaticData.MySideIds = new List <int>() { BoardStaticData.MyStartId }; BoardStaticData.MySideIds.AddRange( board.Factories .Where(f => f.Id != BoardStaticData.MyStartId && f.Id != BoardStaticData.MiddleId && (f.Id % 2) == (BoardStaticData.MyStartId % 2)) // my side .OrderBy(f => BoardStaticData.GetDistance(f.Id, BoardStaticData.MyStartId)) // order by distance .Select(f => f.Id) ); }
public List <IAction> ComputeActions(Board board) { List <IAction> todoList = new List <IAction>(); // Actual score : var myProduction = board.MyFactories.Sum(f => f.Production); var ennemyProduction = board.Factories.Where(f => f.Owner == -1).Sum(t => t.Production); todoList.Add(new MessageAction() { Message = $"{myProduction} vs {ennemyProduction}" }); var mySideFactories = new List <Factory>(); BoardStaticData.MySideIds.ForEach(id => mySideFactories.Add(board.GetFactory(id))); // 1) Defend board.MyFactories.ForEach(f => { // Check for negative var dangers = new List <Tuple <int, int> >(); // turn, number var availability = f.CountAvailableCyborgs(board); for (int i = 0; i < availability.Count; ++i) { if (availability[i] < 0) { dangers.Add(new Tuple <int, int>(i, -availability[i])); } } int added = 0; dangers.ForEach(d => { int needed = d.Item2 - added; if (needed > 0) { Console.Error.WriteLine($"Has to defend {f.Id} from {needed} cyborgs at turn {d.Item1}."); added += this.SendClosestCyborgs(board, todoList, f, needed, d.Item1); } }); }); // 2) Upgrade board.MyFactories.ForEach(mf => { var myFactoryAvailabilities = mf.CountAvailableCyborgs(board); var available = myFactoryAvailabilities.Min(); // 1) If prod not maxed, wait or send to up it. if (mf.Production < 3 && mf.CyborgsNumber >= 10) { // Simulate with 10 less Cyborgs var copy = mf.Copy(); copy.CyborgsNumber -= 10; // Send var dangers = new List <Tuple <int, int> >(); // turn, number var simulatedAvailabilities = copy.CountAvailableCyborgs(board); for (int j = 0; j < simulatedAvailabilities.Count; ++j) { if (simulatedAvailabilities[j] < 0) { dangers.Add(new Tuple <int, int>(j, -simulatedAvailabilities[j])); } } int added = 0; dangers.ForEach(d => { int needed = d.Item2 - added; if (needed > 0) { Console.Error.WriteLine($"Has to help real increase {mf.Id} against {needed} cyborgs at turn {d.Item1}."); added += this.SendClosestCyborgs(board, todoList, mf, needed, d.Item1); } }); // Check again copy = mf.Copy(); copy.CyborgsNumber -= 10; simulatedAvailabilities = copy.CountAvailableCyborgs(board); var simulatedAvailability = simulatedAvailabilities.Min(); if (simulatedAvailability >= 0) { Console.Error.WriteLine($"Can increase {mf.Id}."); mf.NextTroops.Add(new Troop() { Owner = 1, Source = mf, CyborgsNumber = 10 }); todoList.Add(new IncreaseAction() { Factory = mf }); // Don't send any unit please ! mf.CanSend = false; } } }); // 3) Retake mySideFactories.Where(f => f.Owner == -1).ToList().ForEach(f => { // Check for negative var dangers = new List <Tuple <int, int> >(); // turn, number var availability = f.CountAvailableCyborgs(board); for (int i = 0; i < availability.Count; ++i) { if (availability[i] < 0) { dangers.Add(new Tuple <int, int>(i, -availability[i])); } } int added = 0; dangers.ForEach(d => { int needed = d.Item2 - added; if (needed > 0) { Console.Error.WriteLine($"Has to defend {f.Id} from {needed} cyborgs at turn {1000}."); added += this.SendClosestCyborgs(board, todoList, f, needed, 1000); } }); }); // 4) Help increase board.MyFactories.OrderByDescending(f => f.Production).ToList().ForEach(mf => { if (mf.Production < 3) { // Simulate with 10 less Cyborgs var copy = mf.Copy(); copy.CyborgsNumber -= 10; // Send var dangers = new List <Tuple <int, int> >(); // turn, number var simulatedAvailabilities = copy.CountAvailableCyborgs(board); for (int j = 0; j < simulatedAvailabilities.Count; ++j) { if (simulatedAvailabilities[j] < 0) { dangers.Add(new Tuple <int, int>(j, -simulatedAvailabilities[j])); } } if (board.Troops.Count(t => t.Owner == -1 && t.Destination.Id == mf.Id) > 0) { // Like defense int added = 0; dangers.ForEach(d => { int needed = d.Item2 - added; if (needed > 0) { Console.Error.WriteLine($"Has to help to increase {mf.Id} against {needed} cyborgs at turn {d.Item1}."); added += this.SendClosestCyborgs(board, todoList, mf, needed, d.Item1); } }); } else { Console.Error.WriteLine($"Look if can fasten increase of {mf.Id}."); // Just find out if someone can send before prod's get it var last = simulatedAvailabilities.Last(); var closest = board.MyFactories.Where(f => f.Id != mf.Id && f.CanSend).OrderBy(f => BoardStaticData.GetDistance(f.Id, mf.Id)).FirstOrDefault(); if (closest != null) { // Check if can send enough var distance = BoardStaticData.GetDistance(closest.Id, mf.Id); var producted = distance * mf.Production; var missing = last + producted; if (missing < 0) { this.SendClosestCyborgs(board, todoList, mf, -missing, distance + 1); } } } // Don't send any unit please ! mf.CanSend = false; } }); // 5) Find most valuable neutral target in my side to Colonize board.MyFactories.ForEach(mf => { var neutralTargets = mySideFactories.Where(f => f.Owner == 0).OrderByDescending(f => f.Production).ThenBy(f => BoardStaticData.GetDistance(f.Id, mf.Id)).ToList(); var myFactoryAvailabilities = mf.CountAvailableCyborgs(board); var available = myFactoryAvailabilities.Min(); int i = 0; while (available > 0 && i < neutralTargets.Count) { Console.Error.WriteLine($"Still {available} cyborgs available on {mf.Id}."); var target = neutralTargets[i]; var targetAvailabilities = target.CountAvailableCyborgs(board); var distance = BoardStaticData.GetDistance(mf.Id, target.Id); int needed = 1; if (targetAvailabilities.Count == 1) { needed -= targetAvailabilities.First(); } else if (distance >= targetAvailabilities.Count) // > 1 { needed -= targetAvailabilities.Last(); } else { needed -= targetAvailabilities.Skip(distance).Min(); } Console.Error.WriteLine($"{needed} cyborgs needed on {target.Id} : "); targetAvailabilities.ForEach(a => Console.Error.Write($"{a} ")); if (needed > 0) { var sent = Math.Min(needed, available); Console.Error.WriteLine($"Send {sent} cyborgs on {target.Id}."); mf.NextTroops.Add(new Troop() { Owner = 1, Source = mf, Destination = target, CyborgsNumber = sent }); todoList.Add(new MoveAction() { Source = mf, Destination = target, CyborgsNumber = sent }); available -= sent; } ++i; } }); // 6) Find most valuable ennemy target -- better scoring here if (board.MyFactories.Count(f => f.Production < 3) == 0) { var ennemyTargets = board.Factories.Where(f => f.Owner != 1).OrderBy(f => (f.Id == BoardStaticData.MyStartId) ? 0 : BoardStaticData.GetDistance(f.Id, BoardStaticData.MyStartId)).ToList(); if (ennemyTargets.Count > 0) { ennemyTargets.ForEach(target => { Console.Error.WriteLine($"Target is {target.Id}."); var targetAvailabilities = target.CountAvailableCyborgs(board); if (targetAvailabilities.Last() > 0) { // Will be mine Console.Error.WriteLine($"{target.Id} will become mine in the end."); } else { // Should compute whole avail var needed = 10 - targetAvailabilities.Min(); this.SendClosestCyborgs(board, todoList, target, needed, 1000); } }); } } if (todoList.Count == 0) { todoList.Add(new WaitAction()); } return(todoList); }
private int SendClosestCyborgs(Board board, List <IAction> todoList, Factory destination, int neededCyborgs, int turn) { int sent = 0; Console.Error.WriteLine($"{neededCyborgs} cyborgs needed to go to {destination.Id}, within {turn} turns."); var orderedSenders = board.MyFactories.Where(f => f.Id != destination.Id && f.CanSend && BoardStaticData.GetDistance(f.Id, destination.Id) < turn).OrderBy(f => BoardStaticData.GetDistance(f.Id, destination.Id)).ToList(); for (int i = 0; i < orderedSenders.Count; ++i) { Factory factory = orderedSenders[i]; int available = factory.CountAvailableCyborgs(board).Min(); Console.Error.WriteLine($"{available} cyborgs available from {factory.Id}."); if (available >= neededCyborgs) { // Send needed Troop troop = new Troop() { CyborgsNumber = neededCyborgs, Source = factory, Destination = destination, Owner = 1, TurnsBeforeArrival = BoardStaticData.GetDistance(factory.Id, destination.Id) }; factory.NextTroops.Add(troop); var action = new MoveAction() { CyborgsNumber = neededCyborgs, Source = factory, Destination = destination }; todoList.Add(action); Console.Error.WriteLine($"{troop.CyborgsNumber} full cyborgs sent from {factory.Id}."); sent += troop.CyborgsNumber; break; } else if (available > 0) { // Send available Troop troop = new Troop() { CyborgsNumber = available, Source = factory, Destination = destination, Owner = 1, TurnsBeforeArrival = BoardStaticData.GetDistance(factory.Id, destination.Id) }; factory.NextTroops.Add(troop); var action = new MoveAction() { CyborgsNumber = available, Source = factory, Destination = destination }; todoList.Add(action); Console.Error.WriteLine($"{troop.CyborgsNumber} available cyborgs sent from {factory.Id}."); sent += troop.CyborgsNumber; neededCyborgs -= available; } } return(sent); }