Пример #1
0
        /// <summary>
        /// Calculates cells Cost for specified player.
        /// </summary>
        /// <param name="klopPlayer">The klop player.</param>
        /// <param name="callback">Callback for evaluation result.</param>
        public void EvaluateCells(IKlopPlayer klopPlayer, Action<IKlopCell, double> callback)
        {
            var toRemove = new HashSet<Tuple<IKlopPlayer, IKlopCell>>();
            foreach (IKlopCell cell in _klopModel.Cells)
            {
                var cacheKey = new Tuple<IKlopPlayer, IKlopCell>(klopPlayer, cell);
                if (!CellValueCache.ContainsKey(cacheKey)) continue;

                var cachedCell = CellValueCache[cacheKey];
                if (cachedCell.Item2 == cell.State) continue;

                // Remove cell and adjanced cells from cache (do not remove immediately, needed for adjanced cells check)
                toRemove.Add(cacheKey);
                toRemove.AddRange(_klopModel.GetNeighborCells(cell).Select(c => new Tuple<IKlopPlayer, IKlopCell>(klopPlayer, c)));
            }
            CellValueCache.RemoveRange(toRemove);

            foreach (IKlopCell cell in _klopModel.Cells)
            {
                var cacheKey = new Tuple<IKlopPlayer, IKlopCell>(klopPlayer, cell);
                double cost;
                if (CellValueCache.ContainsKey(cacheKey))
                {
                    cost = CellValueCache[cacheKey].Item1;
                    //Debug.Assert(f.Cost == GetCellCost(cell, klopPlayer));  // Cache integrity test
                }
                else
                {
                    cost = GetCellCost(cell, klopPlayer);
                    CellValueCache[cacheKey] = new Tuple<double, ECellState>(cost, cell.State);
                }
                callback(cell, cost);
            }
        }
Пример #2
0
        /// <summary>
        /// Generates the starting pattern: returns next position for the initial standoff.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="player">The player.</param>
        /// <param name="enemyDistanceFunc">The enemy distance function.</param>
        public static IKlopCell GenerateStartingPattern(this IKlopModel model, IKlopPlayer player, Func <IKlopCell, double> enemyDistanceFunc)
        {
            if (model == null || player == null || enemyDistanceFunc == null)
            {
                throw new ArgumentNullException();
            }

            // TODO: Target sometimes falls behing enemy cells, and, however, target cell is not close to enemy, the path is.
            // TODO: "Safe path"?? "Safe evaluator".. or SafePathFinder. How to build safe cells map fast?
            return(model.Cells
                   .Where(c =>
            {
                if (c.X < 1 || c.Y < 1 || c.X >= model.FieldWidth - 2 || c.Y >= model.FieldHeight - 2)
                {
                    return false;
                }
                if (model.GetNeighborCells(c).Any(cc => cc.Owner != null))
                {
                    return false;
                }
                var dx1 = Math.Abs(c.X - player.BasePosX);
                var dy1 = Math.Abs(c.Y - player.BasePosY);
                return dx1 > 1 && dy1 > 1 &&
                ((dx1 * dx1 + dy1 * dy1) < (Math.Pow(model.FieldHeight, 2) + Math.Pow(model.FieldWidth, 2)) / 3) &&
                (enemyDistanceFunc(c) > model.TurnLength / 1.7);
            }).Random() ?? model.Cells.Where(c => c.Owner == null).Random());
        }
Пример #3
0
 /// <summary>
 /// Evaluates the cells for specified player.
 /// </summary>
 /// <param name="klopPlayer">The klop player.</param>
 private void EvaluateCells(IKlopPlayer klopPlayer)
 {
     _cellEvaluator.EvaluateCells(klopPlayer, (cell, cost) =>
     {
         var node = _field[cell.X, cell.Y];
         node.Reset();
         node.Cost = cost;
     });
 }
Пример #4
0
        /// <summary>
        /// Gets the cell cost.
        /// </summary>
        /// <param name="cell">The cell.</param>
        /// <param name="klopPlayer">The klop player.</param>
        /// <returns></returns>
        private double GetCellCost(IKlopCell cell, IKlopPlayer klopPlayer)
        {
            if (cell.Owner == klopPlayer)
            {
                return 0; // Zero cost for owned cell
            }

            if (cell.State == ECellState.Dead)
            {
                return TurnBlockedCost; // Can't move into own dead cell or base cell
            }

            //TODO: Additive cost! E.g. near own clop + near enemy clop!!
            if (cell.Owner != null && cell.State == ECellState.Alive)
            {
                if (IsCellNearBase(cell, klopPlayer))
                {
                    return TurnEatOwnbaseCost;
                }

                if (_klopModel.Players.Where(p => p != klopPlayer).Any(enemy => IsCellNearBase(cell, enemy)))
                {
                    return TurnEatEnemyBaseCost;
                }

                return TurnEatCost;
            }

            if (IsCellNearBase(cell, klopPlayer))
            {
                return TurnNearOwnBaseCost;
            }

            var neighbors = _klopModel.GetNeighborCells(cell).ToArray();
            if (neighbors.Any(c => c.State == ECellState.Base))
            {
                return TurnNearEnemyBaseCost;
            }

            var enemyCount = neighbors.Count(c => c.Owner != null && c.Owner != klopPlayer);
            if (enemyCount > 0)
            {
                //return TurnNearEnemyEmptyCost*(1 + (double) enemyCount/2); // Turn near enemy klop costs a bit more.
                return TurnEmptyCost + TurnNearEnemyEmptyCostAddition*enemyCount;
            }

            var neighborCount = neighbors.Count(c => c.Owner != null);

            return TurnEmptyCost*(1 + (double) neighborCount/2); // Default - turn into empty cell.
        }
Пример #5
0
        /// <summary>
        /// Finds the path between two nodes.
        /// </summary>
        public IEnumerable <Node> FindPath(Node startNode, Node finishNode, IKlopPlayer klopPlayer, bool inverted, bool skipEvaluate = false)
        {
            // Init field
            if (!skipEvaluate)
            {
                EvaluateCells(klopPlayer);
            }

            // Get result
            var lastNode = _aStar.FindPath(startNode, finishNode, GetDistance, GetNodeByCoordinates, inverted);

            while (lastNode != null)
            {
                yield return(lastNode);

                lastNode = lastNode.Parent;
            }
        }
Пример #6
0
 private static bool IsCellNearBase(IKlopCell cell, IKlopPlayer baseOwner)
 {
     return Math.Max(Math.Abs(cell.X - baseOwner.BasePosX), Math.Abs(cell.Y - baseOwner.BasePosY)) == 1;
 }
Пример #7
0
 /// <summary>
 /// Finds the path betweed specified nodes for specified player.
 /// </summary>
 public List <IKlopCell> FindPath(int startX, int startY, int finishX, int finishY, IKlopPlayer klopPlayer, bool inverted = false)
 {
     return(FindPath(GetNodeByCoordinates(startX, startY), GetNodeByCoordinates(finishX, finishY), klopPlayer, inverted)
            .Select(n => _klopModel[n.X, n.Y]).Where(c => c.Owner != klopPlayer).ToList());
 }
Пример #8
0
 /// <summary>
 /// Determines whether specified player is defeated and cannot longer make moves.
 /// </summary>
 public bool IsPlayerDefeated(IKlopPlayer player)
 {
     return(_defeatedPlayers.Contains(player));
 }
Пример #9
0
        /// <summary>
        /// Finds the most important cell: cell which most of all affects total path cost.
        /// </summary>
        /// <returns>Tuple of most important cell and path cost difference.</returns>
        private Tuple <IKlopCell, double> FindMostImportantCell(int startX, int startY, int finishX, int finishY, IKlopPlayer klopPlayer)
        {
            var    startN      = _pathFinder.GetNodeByCoordinates(startX, startY);
            var    finishN     = _pathFinder.GetNodeByCoordinates(finishX, finishY);
            var    initialCost = _pathFinder.FindPath(startN, finishN, klopPlayer, false).Sum(n => n.Cost);
            double maxCost     = 0;
            Node   resultNode  = null;

            foreach (
                var node in
                Model.Cells.Where(c => c.Available && c.Owner == klopPlayer && c.State == ECellState.Alive).Select(
                    c => _pathFinder.GetNodeByCoordinates(c.X, c.Y)))
            {
                var oldCost = node.Cost;
                node.Cost = KlopCellEvaluator.TurnBlockedCost;

                var cost = _pathFinder.FindPath(startN, finishN, klopPlayer, false, true).Sum(n => n.Cost);
                if (cost > maxCost)
                {
                    maxCost    = cost;
                    resultNode = node;
                }

                node.Cost = oldCost;
            }
            return(resultNode == null ? null : new Tuple <IKlopCell, double>(Model[resultNode.X, resultNode.Y], maxCost - initialCost));
        }