Объединить меньшие прямоугольники в большие
у меня проблема, когда мне нужно объединить маленькие квадраты в большие прямоугольники. Скажем, у меня есть 2D-сетка, заполненная случайными 1 и 0:
1 0 1 1 0
1 0 1 1 1
0 1 0 1 1
0 1 0 1 1
0 0 1 0 0
1 представляют области, которые заполнены, и я рисую их на экране вниз по линии в виде квадратов. Однако для этой проблемы мне нужно сначала сопоставить их в прямоугольники. В примере показано, что 1 в верхнем левом углу ->
1
1
можно соединить в прямоугольник.
Я думаю, что должно быть достаточно объяснить, что мне нужно. Однако предпочтительно, чтобы конкретный квадрат не использовался более чем в одном прямоугольнике. Кроме того, это не должен быть лучший случай с наименьшим количеством прямоугольников, просто лучший случай с меньшим количеством прямоугольников. Прямоугольники 1x1 также разрешены, если бы это упростило дело.
любое понимание того, с чего я мог бы начать, или даже решение будет оценено.
Если вы хотите знать причину этой проблемы, я работаю на level builder для игры, над которой я работаю, и я хочу уменьшить количество вершин. Я думал, что начну с квадратов, потому что они будут простыми, но даже это ошеломляет меня.
Спасибо, что нашли время для чтения!
2 ответов
простым подходом было бы искать соседние квадраты и превращать их в прямоугольники. Для этого сначала пройдите горизонтально через сетку и соедините горизонтально соседние квадраты, затем пройдите через сетку вертикально и соедините вертикально соседние квадраты.
считаем:
H = кусок горизонтального прямоугольника
V = кусок вертикального прямоугольника
ваш исходный пример:
1 0 1 1 0
1 0 1 1 1
0 1 0 1 1
0 1 0 1 1
0 0 1 0 0
получилось бы в:
V 0 H H 0
V 0 H H H
0 V 0 H H
0 V 0 H H
0 0 1 0 0
этот подход не является оптимальным, но он превратит квадраты в прямоугольники, если это возможно сделать с учетом 2D-сетки.
Я использую 2 шага, чтобы уменьшить количество коллайдеров в моей игре. Объединение горизонтально последовательных типов, затем объединение вертикально типов, имеющих одинаковую ширину.
код находится в процессе работы, но, похоже, работает~
public class Tiles
{
public char Type { get; set; }
public int X { get; set; }
public int Y { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public override string ToString()
{
return $@"({X}, {Y}, {Width}, {Height}) '{Type}'";
}
}
public class TilesFromStrings
{
private List<Tiles> Result = new List<Tiles>();
public IEnumerable<Tiles> Create(params string[] lines)
{
Result.Clear();
CreateMergedHorizontalTiles(lines);
MergeVerticallyTilesWithSameWidth();
return Result.Where(f => f.Height > 0);
}
private void MergeVerticallyTilesWithSameWidth()
{
foreach (var current in Result)
{
foreach (var other in Result)
{
if (other.Y + other.Height == current.Y
&& other.X == current.X
&& other.Height > 0
&& current.Height > 0)
{
if (other.Type == current.Type)
{
if (other.Width == current.Width)
{
current.Height--;
current.Y++;
other.Height++;
break;
}
}
}
}
}
}
private void CreateMergedHorizontalTiles(string[] tiles)
{
Tiles currentRect = null;
var lastColumnIndex = tiles[0].Length - 1;
for (int rowIndex = 0; rowIndex < tiles.Length; rowIndex++)
{
for (int columnIndex = 0; columnIndex < tiles[rowIndex].Length; columnIndex++)
{
var currentType = tiles[rowIndex][columnIndex];
if (columnIndex == 0)
{
currentRect = new Tiles
{
X = columnIndex + 1,
Y = rowIndex + 1,
Width = 1,
Height = 1,
Type = currentType
};
continue;
}
if (columnIndex == lastColumnIndex)
{
if (currentRect.Type == currentType)
{
Result.Add(currentRect);
currentRect.Width++;
}
else
{
Result.Add(currentRect);
currentRect = new Tiles
{
X = columnIndex + 1,
Y = rowIndex + 1,
Width = 1,
Height = 1,
Type = currentType
};
Result.Add(currentRect);
}
continue;
}
if (currentRect.Type == currentType)
{
currentRect.Width++;
}
else
{
Result.Add(currentRect);
currentRect = new Tiles
{
X = columnIndex + 1,
Y = rowIndex + 1,
Width = 1,
Height = 1,
Type = currentType
};
}
}
}
}
}