예제 #1
0
        /// <summary>
        /// Finds enemy cell(s) which are closest to specified cell, or to any player cell if targetCell is null.
        /// if targetCell is not specified, all player-owned cells are used as targets.
        /// </summary>
        /// <returns></returns>
        private IEnumerable <IKlopCell> FindNearestEnemyCells(IKlopCell targetCell = null)
        {
            if (targetCell == null)
            {
                var availableCellsWithDistances = Model.Cells.Where(c => c.Available).Select(c => new
                {
                    c,
                    d = _distanceMap[c.X, c.Y]
                }).ToArray();
                var minDistance = availableCellsWithDistances.Select(c => c.d).Min();
                // Go over all available cells with the same minimum distance
                foreach (var c in availableCellsWithDistances.Where(c => c.d == minDistance).SelectMany(c => FindNearestEnemyCells(c.c)))
                {
                    yield return(c);
                }
                yield break;
            }


            var cell         = targetCell;
            var cellDistance = _distanceMap[cell.X, cell.Y];

            if (cellDistance == 0)
            {
                // End of recursion, we have found enemy cell.
                yield return(cell);
            }
            else
            {
                foreach (var c in Model.GetNeighborCells(cell).Where(c => _distanceMap[c.X, c.Y] < cellDistance).SelectMany(FindNearestEnemyCells))
                {
                    yield return(c);
                }
            }
        }
예제 #2
0
        private IKlopCell FindEnemyCellToAttack(IKlopCell targetCell = null)
        {
            var nearestEnemyCells = FindNearestEnemyCells(targetCell);
            // There could be several enemy cells with equal distances. Find the one closer to enemy base!
            var pathLengths = nearestEnemyCells.Select(c => new
            {
                c,
                pathLength = _pathFinder.FindPath(c.X, c.Y, c.Owner.BasePosX, c.Owner.BasePosY, this).Count
            });

            return(pathLengths.Highest((c1, c2) => c1.pathLength < c2.pathLength).c);
        }
예제 #3
0
        private void OnKlopCellChanged(DependencyPropertyChangedEventArgs e)
        {
            var oldCell = e.OldValue as IKlopCell;

            if (oldCell != null)
            {
                oldCell.PropertyChanged -= Cell_PropertyChanged;
            }

            _cell = Cell; // Cache value for faster access
            _cell.PropertyChanged += Cell_PropertyChanged;
            UpdateBrushes();
        }
예제 #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>
 /// Gets the neighbor cells.
 /// </summary>
 /// <param name="cell">The cell.</param>
 /// <param name="model">The model.</param>
 /// <returns></returns>
 private static IEnumerable <IKlopCell> GetNeighborCells(IKlopCell cell, IKlopModel model)
 {
     for (int x = -1; x < 1; x++)
     {
         for (int y = -1; y < 1; y++)
         {
             var xx = cell.X + x;
             var yy = cell.Y + y;
             if ((x == y && x == 0) || xx < 0 || yy < 0 || xx >= model.FieldWidth || yy > model.FieldHeight)
             {
                 continue;
             }
             yield return(model[xx, yy]);
         }
     }
 }
예제 #6
0
        /// <summary>
        /// Gets the neighbor cells.
        /// </summary>
        /// <param name="cell">The cell.</param>
        /// <returns></returns>
        public IEnumerable <IKlopCell> GetNeighborCells(IKlopCell cell)
        {
            // This method is called very often. Here is fastest implementation for now:
            var cx      = cell.X;
            var cy      = cell.Y;
            var xNotMin = cx != 0;
            var xNotMax = cx < _fieldWidth - 1;

            if (cy != 0)
            {
                if (xNotMin)
                {
                    yield return(_cells[cx - 1, cy - 1]);
                }
                yield return(_cells[cx, cy - 1]);

                if (xNotMax)
                {
                    yield return(_cells[cx + 1, cy - 1]);
                }
            }

            if (xNotMin)
            {
                yield return(_cells[cx - 1, cy]);
            }
            if (xNotMax)
            {
                yield return(_cells[cx + 1, cy]);
            }

            if (cy != _fieldHeight - 1)
            {
                if (xNotMin)
                {
                    yield return(_cells[cx - 1, cy + 1]);
                }
                yield return(_cells[cx, cy + 1]);

                if (xNotMax)
                {
                    yield return(_cells[cx + 1, cy + 1]);
                }
            }
        }
예제 #7
0
        public void HighlightPath(IKlopCell cell)
        {
            if (!_model.CurrentPlayer.Human && _highlightedCells.Count == 0)
            {
                return;
            }

            _highlightedCells.Clear();

            if (_model.CurrentPlayer.Human)
            {
                var path = PathFinder.FindPath(_model.CurrentPlayer.BasePosX, _model.CurrentPlayer.BasePosY, cell.X, cell.Y, _model.CurrentPlayer);
                var i    = path.Count;
                foreach (var klopCell in path)
                {
                    _highlightedCells[klopCell] = i--;
                }
            }

            InvokeHighlightChanged();
        }
예제 #8
0
 private void MakeTurn(IKlopCell cell)
 {
     if (cell.Available)
     {
         Model.MakeTurn(cell);
     }
     else if (PathHighlighter.IsHighlighted(cell))
     {
         // Cell is highlighted - perform multiple turns:
         while (Model.RemainingKlops > 1) //TODO: Configurable whether leave one clop or not
         {
             var currentCell = Model.Cells.FirstOrDefault(c => c.Available && PathHighlighter.IsHighlighted(c));
             if (currentCell == null)
             {
                 break;
             }
             Model.MakeTurn(currentCell);
             if (currentCell == cell)
             {
                 break;                      // Destination reached
             }
         }
     }
 }
예제 #9
0
 /// <summary>
 /// Determines whether the specified cell is highlighted.
 /// </summary>
 /// <param name="cell">The cell.</param>
 /// <returns>
 ///     <c>true</c> if the specified cell is highlighted; otherwise, <c>false</c>.
 /// </returns>
 public bool IsHighlighted(IKlopCell cell)
 {
     return(cell != null && _highlightedCells.ContainsKey(cell));
 }
예제 #10
0
 /// <summary>
 /// Determines whether the specified cell is highlighted. When highlighted, returns positive number indicating path length.
 /// If not highlighted, returns -1.
 /// </summary>
 /// <param name="cell">The cell.</param>
 public int GetPathLength(IKlopCell cell)
 {
     return(cell != null && _highlightedCells.ContainsKey(cell) ? _highlightedCells[cell] : -1);
 }
예제 #11
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;
 }
예제 #12
0
 /// <summary>
 /// Makes the turn to the specified cell.
 /// </summary>
 /// <param name="cell">The cell.</param>
 public void MakeTurn(IKlopCell cell)
 {
     MakeTurn(cell.X, cell.Y);
 }
예제 #13
0
 /// <summary>
 /// Gets the distance to the closest enemy cell.
 /// </summary>
 private double GetEnemyDistance(IKlopCell cell)
 {
     return(_distanceMap[cell.X, cell.Y]);
 }