Removendo Ilhas
Eu já fiz esse tipo de coisa antes em um dos meus jogos. Para se livrar das ilhas externas, o processo foi basicamente:
- Primeiro, deve haver uma garantia de que o centro do mapa sempre pertence à terra principal e cada pixel começa como "Terra" ou "Água" (ou seja, cores diferentes).
- Em seguida, faça um preenchimento de quatro direções, começando no centro do mapa e se espalhando por todos os ladrilhos "Terreno". Marque cada pixel visitado por esse preenchimento como um tipo diferente, como "MainLand".
- Por fim, percorra o mapa inteiro e converta qualquer pixel "Land" restante em "Water" para se livrar de outras ilhas.
Remoção de lagos
Quanto a se livrar dos buracos (ou lagos) dentro da ilha, você faz um processo semelhante, mas partindo dos cantos do mapa e se espalhando pelos ladrilhos "Água". Isso permitirá que você diferencie o "Mar" dos outros ladrilhos de água, e então você pode se livrar deles da mesma maneira que antes.
Exemplo
Deixe-me desenterrar minha implementação do preenchimento de inundação que tenho aqui em algum lugar (isenção de responsabilidade, não me importei com eficiência, por isso tenho certeza de que existem muitas maneiras mais eficientes de implementá-lo):
private void GenerateSea()
{
// Initialize visited tiles list
visited.Clear();
// Start generating sea from the four corners
GenerateSeaRecursive(new Point(0, 0));
GenerateSeaRecursive(new Point(size.Width - 1, 0));
GenerateSeaRecursive(new Point(0, size.Height - 1));
GenerateSeaRecursive(new Point(size.Width - 1, size.Height - 1));
}
private void GenerateSeaRecursive(Point point)
{
// End recursion if point is outside bounds
if (!WithinBounds(point)) return;
// End recursion if the current spot is a land
if (tiles[point.X, point.Y].Land) return;
// End recursion if this spot has already been visited
if (visited.Contains(point)) return;
// Add point to visited points list
visited.Add(point);
// Calculate neighboring tiles coordinates
Point right = new Point(point.X + 1, point.Y);
Point left = new Point(point.X - 1, point.Y);
Point up = new Point(point.X, point.Y - 1);
Point down = new Point(point.X, point.Y + 1);
// Mark neighbouring tiles as Sea if they're not Land
if (WithinBounds(right) && tiles[right.X, right.Y].Empty)
tiles[right.X, right.Y].Sea = true;
if (WithinBounds(left) && tiles[left.X, left.Y].Empty)
tiles[left.X, left.Y].Sea = true;
if (WithinBounds(up) && tiles[up.X, up.Y].Empty)
tiles[up.X, up.Y].Sea = true;
if (WithinBounds(down) && tiles[down.X, down.Y].Empty)
tiles[down.X, down.Y].Sea = true;
// Call the function recursively for the neighboring tiles
GenerateSeaRecursive(right);
GenerateSeaRecursive(left);
GenerateSeaRecursive(up);
GenerateSeaRecursive(down);
}
Eu usei isso como um primeiro passo para me livrar de lagos no meu jogo. Depois de chamar isso, tudo o que eu precisava fazer era algo como:
private void RemoveLakes()
{
// Now that sea is generated, any empty tile should be removed
for (int j = 0; j != size.Height; j++)
for (int i = 0; i != size.Width; i++)
if (tiles[i, j].Empty) tiles[i, j].Land = true;
}
Editar
Adicionando algumas informações extras com base nos comentários. Caso seu espaço de pesquisa seja muito grande, poderá ocorrer um estouro de pilha ao usar a versão recursiva do algoritmo. Aqui está um link no stackoverflow (trocadilho pretendido :-)) para uma versão não recursiva do algoritmo, usando uma Stack<T>
alternativa (também em C # para corresponder à minha resposta, mas deve ser fácil de se adaptar a outros idiomas, e há outras implementações nesse link também).