Describes a ship
Inheritance: ICloneable
Example #1
0
        public static Ship Parse(string s)
        {
            string[] parts = s.Split(delimiters);
            if (parts.Length != 3)
                throw new ArgumentException("s");

            Position p1 = Position.Parse(parts[1]);
            Position p2 = Position.Parse(parts[2]);

            if (p2 < p1)
            {
                Position swap = p1;
                p1 = p2;
                p2 = swap;
            }
            Ship ship = new Ship() { Position = p1, Size = p1 - p2 + 1, Orientation = (p1.Row == p2.Row) ? Orientation.Horizontal : Orientation.Vertical, Code = parts[0] };
            return ship;
        }
Example #2
0
 /// <summary>
 /// Whether or not a ship intersects or is next to another ship
 /// </summary>
 /// <param name="ship"></param>
 /// <returns></returns>
 public bool IntersectsOrAdjacent(Ship ship)
 {
     foreach (Position p in ship.Positions)
     {
         if (AtOrAdjacent(p)) return true;
     }
     return false;
 }
        /// <summary>
        /// Adjust position possibilies based on the fact that a ship was sunk
        /// </summary>
        /// <param name="size">size of ship</param>
        void Sink(Ship ship)
        {
            // Remove this ship type from ship position consideration
            for (var i = 0; i < AdaptivePlayer.Width; ++i)
            {
                for (var j = 0; j < AdaptivePlayer.Width; ++j)
                {
                    if (_score[i, j].Score > 0)
                        _score[i, j].Sink(ship.Size);
                }
            }

            _sunkSpots += ship.Size;

            // We sunk a ship, go back to search mode if we don't have any pending hit boats
            if (_sunkSpots == _hits.Count)
            {
                _sunkSpots = 0;

                List<Position> adjacent = new List<Position>();

                // We can now adjust scores for these hits
                foreach (Position p in _hits)
                {
                    AdjustScore(p);
                    if (!_assumeAdjacent)
                    {
                        AdjustNotAdjacentScore(p);
                        adjacent.AddRange(AdjacentPositions(p));
                    }
                }

                if (!_assumeAdjacent)
                {
                    adjacent = adjacent.Except(_hits).Distinct().ToList();
                    foreach (Position p in adjacent)
                    {
                        AdjustNotAdjacentScore(p);
                    }
                }

                _hits.Clear();
                _targettingMode = TargettingMode.Search;
            }
            else
            {
                // We found two ships that are adjacent
                _assumeAdjacent = true;

                // Let's see if we can remove some hits from further consideration
                List<Ship> possibleLayouts = new List<Ship>();

                if ((_destroySearchOrientation & Orientation.Horizontal) == Orientation.Horizontal)
                {
                    Ship layout = ship.Clone() as Ship;
                    layout.Orientation = Orientation.Horizontal;

                    // Let's see if we can find the end points of the ship
                    var possibilities = _hits.Where(p => p.Row == _lastShot.Row && Math.Abs(p.Column - _lastShot.Column) < ship.Size);

                    if (possibilities.Count() == ship.Size)
                    {
                        layout.Position = possibilities.Min();
                        if (!layout.Positions.Except(_hits).Any())
                        {
                            // If all positions in the layout are contained in hits
                            possibleLayouts.Add(layout);
                        }
                    }
                }

                if ((_destroySearchOrientation & Orientation.Vertical) == Orientation.Vertical)
                {
                    Ship layout = ship.Clone() as Ship;
                    layout.Orientation = Orientation.Vertical;

                    // Let's see if we can find the end points of the ship
                    var possibilities = _hits.Where(p => p.Column == _lastShot.Column && Math.Abs(p.Row - _lastShot.Row) < ship.Size);

                    if (possibilities.Count() == ship.Size)
                    {
                        layout.Position = possibilities.Min();
                        if (!layout.Positions.Except(_hits).Any())
                        {
                            // If all positions in the layout are contained in hits
                            possibleLayouts.Add(layout);
                        }
                    }
                }

                if (possibleLayouts.Count == 1)
                {
                    // Remove these positions from consideration
                    _hits = _hits.Except(possibleLayouts[0].Positions).ToList();
                    _sunkSpots -= ship.Size;

                    foreach (Position p in possibleLayouts[0].Positions)
                        AdjustScore(p);
                }
            }

            // Reset our destroy orientation pattern
            _destroySearchOrientation = Orientation.Horizontal | Orientation.Vertical;
        }
Example #4
0
 /// <summary>
 /// Returns true if a ship is adjacent to this ship
 /// </summary>
 /// <param name="ship"></param>
 /// <returns></returns>
 public bool Adjacent(Ship ship)
 {
     foreach (Position p in ship.Positions)
     {
         if (Adjacent(p)) return true;
     }
     return false;
 }
        /// <summary>
        /// Place ships on board
        /// </summary>
        /// <returns>List of ship placements</returns>
        public List<Ship> PlaceShips()
        {
            // We want to be both random and smart
            // Generate a series of positions, score them based on position probability and opponent shooting data
            List<Ship> placedShips = new List<Ship>(AdaptivePlayer.Ships.Count);
            List<Ship> bestShipPlacement = new List<Ship>(AdaptivePlayer.Ships.Count);
            double minimumScore = double.MaxValue;
            bool allowTouching = true;

            // Randomly decide to disallow touching ships
            if (BattleshipGame.Random.NextDouble() < 0.6d)
            {
                allowTouching = false;
            }

            // Randomly choose 1000 different layouts, choose the layout with the lowest score
            for (int sample = 0; sample < _samples; ++sample)
            {
                double currentScore = 0.0d;
                placedShips.Clear();
                foreach (Ship ship in AdaptivePlayer.Ships)
                {
                    bool intersects = false;
                    Ship placedShip = new Ship() { Size = ship.Size, Code = ship.Code };

                    // Keep generating positions until we have a set that has no intersecting ships
                    do
                    {
                        intersects = false;
                        placedShip.Place(AdaptivePlayer.Width, AdaptivePlayer.Height);
                        foreach (Ship checkShip in placedShips)
                        {
                            if (allowTouching)
                            {
                                if (placedShip.Intersects(checkShip))
                                {
                                    intersects = true;
                                    break;
                                }
                            }
                            else
                            {
                                if (placedShip.IntersectsOrAdjacent(checkShip))
                                {
                                    intersects = true;
                                    break;
                                }
                            }
                        }
                    } while (intersects);

                    // Score the positions of each ship
                    foreach(Position p in placedShip.Positions)
                    {
                        // Default to probability distribution, otherwise use previous shot history
                        currentScore += (double)AdaptivePlayer.Data.IncomingShots[p.Row][p.Column] / (double)_totalPositions;
                    }
                    placedShips.Add(placedShip);
                }

                if (currentScore < minimumScore)
                {
                    minimumScore = currentScore;
                    bestShipPlacement.Clear();
                    foreach (Ship ship in placedShips)
                        bestShipPlacement.Add(ship);
                }
            }

            // We want to avoid using this placement again, add some points to the current location
            int totalShipSize = bestShipPlacement.Sum(x => x.Size);
            foreach (Ship ship in bestShipPlacement)
            {
                foreach (Position p in ship.Positions)
                {
                    AdaptivePlayer.Data.IncomingShots[p.Row][p.Column] += (int)((double)ship.Size / (double)totalShipSize * 1000.0d);
                }
            }

            return bestShipPlacement;
        }