Случайное дерево объектов

This commit is contained in:
2026-02-24 00:39:40 +03:00
parent aeda3ee0d0
commit 1a94cc8bfd
6 changed files with 203 additions and 48 deletions

View File

@@ -40,3 +40,43 @@ pub fn addShape(self: *Document, parent: ?*Object, shape: Object.ShapeKind) !voi
try self.addObject(obj);
}
}
fn randomShapeKind(rng: std.Random) Object.ShapeKind {
const shapes_implemented = [_]Object.ShapeKind{ .line, .ellipse, .broken };
return shapes_implemented[rng.intRangeLessThan(usize, 0, shapes_implemented.len)];
}
/// Создаёт случайное количество фигур в документе (в т.ч. вложенных).
/// Используются только реализованные типы: line, ellipse, broken.
/// Ограничение max_total предотвращает экспоненциальный рост и переполнение.
pub fn addRandomShapes(self: *Document, rng: std.Random) !void {
const max_total: usize = 80;
var total_count: usize = 0;
const n_root = rng.intRangeLessThan(usize, 1, 5);
for (0..n_root) |_| {
if (total_count >= max_total) break;
try self.addShape(null, randomShapeKind(rng));
total_count += 1;
}
var stack = std.ArrayList(*Object).empty;
defer stack.deinit(self.allocator);
for (self.objects.items) |*obj| {
try stack.append(self.allocator, obj);
}
while (stack.pop()) |obj| {
if (total_count >= max_total) continue;
const n_children = rng.intRangeLessThan(usize, 0, 2);
const base_len = obj.children.items.len;
for (0..n_children) |_| {
if (total_count >= max_total) break;
try self.addShape(obj, randomShapeKind(rng));
total_count += 1;
}
// Пушим в стек только после всех append, чтобы не держать указатели при реаллокации obj.children
for (obj.children.items[base_len..]) |*child| {
try stack.append(self.allocator, child);
}
}
}