private IMove EvaluateMove()
    {
//        throw new NotImplementedException();
        var multiMove = new MultiMove();

        multiMove.AddMove(new Message($"Fight for {FactoryState.FactoryId}"));
        var moveTroops = new MoveTroops();

        multiMove.AddMove(moveTroops);
        for (int i = 0; i < StepsToPredict; i++)
        {
            //взять  мои фабрики на этом расстоянии
            var myFactoriesForAttack = graph.Factories[FactoryState.FactoryId].GetLinks()
                                       .Where(x => x.Distance <= i && graph.Factories[x.DestinationId].Side == Side.MyOwn)
                                       .Select(x => graph.Factories[x.DestinationId])
                                       .ToList();
            //если могут захватить - ура
            if (myFactoriesForAttack.Any() && myFactoriesForAttack.Sum(x => x.TroopsCanBeUsed) > FactoryState.Enemies[i])
            {
                int troopsUsed, needed;
                needed = troopsUsed = FactoryState.Enemies[i] ?? int.MaxValue;
                foreach (var myFactory in myFactoriesForAttack)
                {
//TODO: sort factories by distance or smth else
                    var sendedTroops = Math.Min(needed + 1, myFactory.TroopsCanBeUsed); // TODO: захват нейтралов совместный. +1 не совсем точно. нужно только для захвата но не деф.
                    myFactory.TroopsCanBeUsed =
                        graph.Factories[myFactory.Id].TroopsCanBeUsed = myFactory.TroopsCanBeUsed - sendedTroops;

                    var shortestPath = GraphLinks.Links[myFactory.Id, FactoryState.FactoryId];
                    moveTroops.AddTroop(new Troop {
                        Dst          = FactoryState.FactoryId,
                        DstInCommand = shortestPath.FirstFactoryId,
                        Side         = Side.MyOwn,
                        Remaining    = shortestPath.Distance + 1,
                        Src          = myFactory.Id,
                        Size         = sendedTroops
                    });

                    needed -= sendedTroops;
                    if (needed <= 0)
                    {
                        break;
                    }
                }

                priorityValue = CostFunction.GetJobEstimatePriority(
                    graph.Factories[FactoryState.FactoryId].Income * (graph.Factories[FactoryState.FactoryId].Side == Side.Neutral ? 1 : 2),
                    troopsUsed, i);

                break;
            }
        }
        return(multiMove);
    }
Esempio n. 2
0
    public static IEnumerable <IMove> ProposeMoves(this Graph graph)
    {
        var stepsToPredict = Math.Max(graph.GetMaxCountSteps(), GraphLinks.MaxDistance);

        bool canSendBomb            = graph.BombsAvailable_MyOwn > 0;
        var  bombFactoriesCandidate = new List <Factory>();

        var factories = new List <FactoryStates>();
        var multiMove = new MultiMove();

        yield return(multiMove);

        { //Get List available for attack/defense
            var holdState = Graph.GetCopy(graph);
            graph.UpdateAvailableTroops(holdState, true);
            for (int i = 0; i < stepsToPredict; i++)
            {
                holdState.DoNextMove();
                graph.UpdateAvailableTroops(holdState);
            }
//            multiMove.AddMove(new Message("CBU:"+graph.Factories.Sum(x=>x.TroopsCanBeUsed)));
            if (canSendBomb)
            {
                var sendedBombTo = graph.Bombs.Any(x => x.Side == Side.MyOwn) ? graph.Bombs.Select(x => x.Dst).First() : -1;
                bombFactoriesCandidate = holdState.Factories.Where(x => x.Side == Side.Enemy && x.Income > 1 && x.Id != sendedBombTo).ToList();
            }
            // если не моя по истечению ходов то стоит ее проверить.
            foreach (var factoryTarget in holdState.Factories.Where(x => x.Side != Side.MyOwn && x.Income > 0))
            {
                var testGraph = Graph.GetCopy(graph);
                var move      = new MoveTroops();
                // шлем со всех туда.
                foreach (var myFactory in testGraph.Factories.Where(x => x.Side == Side.MyOwn && x.Id != factoryTarget.Id))
                {
                    var availableTroops = graph.Factories[myFactory.Id].TroopsCanBeUsed;
                    if (availableTroops <= 0)
                    {
                        continue;
                    }

                    //TODO: слать с переправами
                    var linkTo = myFactory.GetLinks().FirstOrDefault(link => link.DestinationId == factoryTarget.Id);
                    if (linkTo.Distance > 0)
                    {
                        // if any
                        move.AddTroop(new Troop {
                            Dst       = factoryTarget.Id,
                            Side      = myFactory.Side,
                            Src       = myFactory.Id,
                            Remaining = linkTo.Distance + 1,
                            Size      = availableTroops
                        });
                    }
                }
                move.ChangeGraph(testGraph);
                testGraph.DoSteps(testGraph.GetMaxCountSteps());
                // Если изменился статус фабрики - запоминаем
                if (testGraph.Factories[factoryTarget.Id].Side == Side.MyOwn)
                {
                    factories.Add(new FactoryStates(factoryTarget.Id, stepsToPredict));
                }
            }
        }
        //Select & send the bomb
        if (canSendBomb)
        {
            var bombTo = bombFactoriesCandidate
                         .OrderByDescending(x => x.Income)
                         .ThenByDescending(f => f.GetLinks().Where(x => graph.Factories[x.DestinationId].Side == Side.MyOwn).Min(x => x.Distance)) // Самая удаленная от нас
                         .FirstOrDefault();
            if (bombTo != null)
            {
                var bombLinkSources = bombTo.GetLinks().Where(x => graph.Factories[x.DestinationId].Side == Side.MyOwn).OrderBy(x => x.Distance);
                if (bombLinkSources.Any())
                {
                    var bombLinkSettings = bombLinkSources.FirstOrDefault();
                    multiMove.AddMove(
                        new SendBomb(new Bomb
                    {
                        Src       = bombLinkSettings.DestinationId,
                        Dst       = bombTo.Id,
                        Side      = Side.MyOwn,
                        Remaining = bombLinkSettings.Distance + 1,
                    }));
                }
            }
        }

        {
            var jobs = new List <IJob>();

            // Get moves to minimum attack
            if (factories.Any())
            {
                multiMove.AddMove(new Message("Init Atack/Defense"));

                var holdState = Graph.GetCopy(graph);
                for (int i = 0; i < stepsToPredict; i++)
                {
                    holdState.DoNextMove();
                    foreach (var factoryState in factories)
                    {
                        var factory = holdState.Factories[factoryState.FactoryId];
                        if (factory.Side == Side.MyOwn)
                        {
                            factoryState.Enemies[i] = null;
                        }
                        else
                        {
                            factoryState.Enemies[i] = factory.TroopsCount;
                        }
                    }
                }
                // fill nulls be next first value
                foreach (var factoryState in factories)
                {
                    for (int i = stepsToPredict - 2; i >= 0; i--)
                    {
                        if (!factoryState.Enemies[i].HasValue)
                        {
                            factoryState.Enemies[i] = factoryState.Enemies[i + 1];
                        }
                    }
                }
                //multiMove.AddMove(new Message($"FS #{factories.Count}: "  + string.Join(", ", factories.Select(x => $"({x.FactoryId})" + string.Join(".", x.Enemies.Select(t=> t ?? -1))))));

                factories.ForEach(x => { jobs.Add(new AtackFactory(x, stepsToPredict)); });
            }

            jobs.AddRange(
                graph.Factories
                .Where(x => x.Side == Side.MyOwn && x.Income < 3)     //TODO: condition can be changed, income check when bomb
                .Select(x => {
                if (x.TroopsCount >= 10 && x.TroopsCanBeUsed >= 9)
                {
                    return((IJob) new UpgradeFactoryJob(x.Id));
                }
                else
                {
                    return((IJob) new WaitToUpgradeFactoryJob(x.Id));
                }
            })
                );

            //Evaluate jobs
            var jobGraph = Graph.GetCopy(graph);
            while (true)
            {
                jobs.ForEach(x => { x.EvaluateInnerState(jobGraph); });
                var first = jobs.OrderByDescending(x => x.GetPriorityValue()).FirstOrDefault();
                if (first == null || first.GetPriorityValue() == int.MinValue)
                {
                    break;
                }
                var jobMove = first.GetMove();
                Logger.ErrorLog("Best job Cost: " + first.GetPriorityValue() + " ACT: " + jobMove.GetConsoleCommand(), LogReportLevel.BestJobCost);

                jobMove.ChangeGraph(jobGraph);
                multiMove.AddMove(jobMove);
                jobs.Remove(first);
                yield return(multiMove);
            }

            multiMove.AddMove(new Message("Init basic moves"));
            // Just move troops
            {
                // TODO: независимо для каждой фабрики выбирать
                foreach (var factory in graph.Factories.Where(x => x.Side == Side.MyOwn && x.TroopsCanBeUsed > 0))
                {
                    foreach (var factoryLink in factory.GetLinks())
                    {
                        var checkedMove = new MoveTroops(new Troop {
                            Dst          = factoryLink.DestinationId,
                            DstInCommand = factoryLink.FirstFactoryId,
                            Side         = Side.MyOwn,
                            Remaining    = factoryLink.Distance + 1,
                            Src          = factory.Id,
                            Size         = factory.TroopsCanBeUsed
                        });
                        multiMove.AddMove(checkedMove);
                        yield return(multiMove);

                        multiMove.RemoveMove(checkedMove);
                    }
                }
//                var l = graph.Factories.Where(x => x.Side == Side.MyOwn && x.TroopsCanBeUsed > 0)
//                    .OrderByDescending(x => {
//                        var links = x.GetLinks().Where(t => graph.Factories[t.DestinationId].Side == Side.Enemy);
//                        if (!links.Any()) return 0;
//
//                        return links.Min(t => t.Distance);
//                    });
            }

            yield return(multiMove);
        }
    }