Beispiel #1
0
        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)
                );
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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);
        }