Bayangkan dunia berbasis kubus (seperti Minecraft, Trove, atau Cube World) di mana semuanya terdiri dari kubus berukuran identik dan semua kubusnya memiliki jenis yang sama .
Tujuannya adalah untuk mewakili dunia dengan jumlah kotak persegi paling sedikit (dengan menggabungkan kubus tetapi mempertahankan bentuk cembung (alias, bentuk kotak persegi panjang)). Algoritme saya berhasil dalam hal ini, tetapi kinerjanya terlalu lambat untuk tujuan yang dimaksudkan. Apakah ada algoritma yang lebih cepat?
Kode-pseudo-C # untuk algoritme saya pada dasarnya:
struct Coordinate { int x,y,z; }; //<-- integer based grid
HashSet<Coordinate> world; // <-- contains all the cubes
//width, height, and length represent how many cubes it spans
struct RectangularBox { Coordinate coord; int width,height,length; }
void Begin()
{
List<RectangularBox> fewestBoxes = new List<RectangularBox>();
while(world.Count > 0)
{
RectangularBox currentLargest = ExtractLargest();
fewestBoxes.Add(currentLargest);
world.RemoveRange(currentLargest.ContainedCubes());
}
//done; `fewestBoxes` contains the fewest rectangular boxes needed.
}
private RectangularBox ExtractLargest()
{
RectangularBox largestBox = new RectangularBox();
foreach (Coordinate origin in world)
{
RectangularBox box = FindMaximumSpan(origin);
if (box.CalculateVolume() >= largestBox.CalculateVolume())
largestBox = box;
}
return largestBox;
}
private RectangularBox FindMaximumSpan(Coordinate origin)
{
int maxX, maxY,maxZ;
while (world.Contains(origin.Offset(maxX, 0, 0))) maxX++;
while (world.Contains(origin.Offset(0, maxY, 0))) maxY++;
while (world.Contains(origin.Offset(0, 0, maxZ))) maxZ++;
RectangularBox largestBox;
for (int extentX = 0; extentX <= maxX; extentX++)
for (int extentY = 0; extentY <= maxY; extentY++)
for (int extentZ = 0; extentZ <= maxZ; extentZ++)
{
int lengthX = extentX + 1;
int lengthY = extentY + 1;
int lengthZ = extentZ + 1;
if (BoxIsFilledWithCubes(origin, lengthX, lengthY, lengthZ))
{
int totalVolume = lengthX * lengthY * lengthZ;
if (totalVolume >= largestBox.ComputeVolume())
largestBox = new RectangularBox(origin, lengthX, lengthY, lengthZ);
}
else
break;
}
return largestBox;
}
private bool BoxIsFilledWithCubes(Coordinate coord,
int lengthX, int lengthY, int lengthZ)
{
for (int gX = 0; gX < lengthX; gX++)
for (int gY = 0; gY < lengthY; gY++)
for (int gZ = 0; gZ < lengthZ; gZ++)
if (!world.Contains(coord.Offset(gX, gY, gZ)))
return false;
return true;
}
Pada dasarnya, untuk setiap blok di dunia, pertama-tama ia menemukan berapa banyak blok religius yang ada di masing-masing dari tiga dimensi positif (+ X, + Y, + Z). Dan kemudian itu agak mengisi volume itu dan memeriksa mana yang merupakan isian terbesar yang tidak hilang blok.
Pembaruan: Karena saya sepertinya menyiratkan ini untuk mesin render game, saya hanya ingin menjelaskan, ini bukan untuk mesin render game; ini untuk konverter file; tidak ada GUI.