public int[] PlaceShipsRandomly() { int cellCount = rules.areaSize.x * rules.areaSize.y; var cells = new int[cellCount]; for (var i = 0; i < cellCount; i++) { cells[i] = EmptyCell; } foreach (var kvp in _pool) { var from = new List <int>(); for (var i = 0; i < cellCount; i++) { from.Add(i); } var isPlaced = false; while (!isPlaced) { if (from.Count == 0) { break; } int cell = from[Random.Range(0, from.Count)]; from.Remove(cell); isPlaced = PlaceShip(kvp.Key, kvp.Value, GridUtils.CellIndexToCoordinate(cell, rules.areaSize.x)); } } return(cells); bool PlaceShip(int shipId, Ship ship, Vector3Int pivot) { (int shipWidth, int shipHeight) = ship.GetShipSize(); if (!GridUtils.IsInsideBoundaries(shipWidth, shipHeight, pivot, rules.areaSize)) { return(false); } if (DoesCollideWithOtherShip(shipId, pivot, shipWidth, shipHeight)) { return(false); } RegisterShipToCells(shipId, ship, pivot); return(true); } bool DoesCollideWithOtherShip(int shipId, Vector3Int pivot, int shipWidth, int shipHeight) { // Create a frame of one cell thickness int xMin = pivot.x - 1; int xMax = pivot.x + shipWidth; int yMin = pivot.y - shipHeight; int yMax = pivot.y + 1; for (int y = yMin; y <= yMax; y++) { if (y < 0 || y > rules.areaSize.y - 1) { continue; // Avoid this row if it is out of the map } for (int x = xMin; x <= xMax; x++) { if (x < 0 || x > rules.areaSize.x - 1) { continue; // Avoid this column if it is out of the map } int cellIndex = GridUtils.CoordinateToCellIndex(new Vector3Int(x, y, 0), rules.areaSize); if (cellIndex != OutOfMap && (cells[cellIndex] == EmptyCell || cells[cellIndex] == shipId)) { continue; } return(true); } } return(false); } void RegisterShipToCells(int shipId, Ship ship, Vector3Int pivot) { // Clear the previous placement of this ship for (var i = 0; i < cellCount; i++) { if (cells[i] == shipId) { cells[i] = EmptyCell; } } // Find each cell the ship covers and register the ship on them foreach (int cellIndex in ship.partCoordinates .Select(part => new Vector3Int(pivot.x + part.x, pivot.y + part.y, 0)) .Select(coordinate => GridUtils.CoordinateToCellIndex(coordinate, rules.areaSize))) { if (cellIndex != OutOfMap) { cells[cellIndex] = shipId; } } } }