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