/// <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; }