1use rlwfc::{
19 Cell, CellState, DefaultInitializer, GridBuilder, GridError,
20 GridSystem, Tile, TileId, TileSet, TileSetVirtual, WfcError, WfcManager,
21};
22
23struct Orthogonal2DGridBuilder {
29 width: usize,
30 height: usize,
31}
32
33impl Orthogonal2DGridBuilder {
34 fn new(width: usize, height: usize) -> Self {
35 Self { width, height }
36 }
37}
38
39impl GridBuilder for Orthogonal2DGridBuilder {
40 fn build_grid_system(&mut self, grid: &mut GridSystem) -> Result<(), GridError> {
41 println!("构建 {}x{} 正交2D网格...", self.width, self.height);
42
43 let mut cells = vec![vec![]; self.height];
45 for y in 0..self.height {
46 cells[y] = Vec::with_capacity(self.width);
47 for x in 0..self.width {
48 let cell_id = grid.add_cell_with_name(
49 Cell::with_id((y * self.width + x) as u32),
50 format!("cell_{}_{}", x, y),
51 );
52 cells[y].push(cell_id);
53 }
54 }
55
56 for y in 0..self.height {
59 for x in 0..self.width {
60 let current = cells[y][x];
61
62 if x < self.width - 1 {
64 grid.create_edge(current, Some(cells[y][x + 1]))?;
65 } else {
66 grid.create_edge(current, None)?;
67 }
68
69 if y < self.height - 1 {
71 grid.create_edge(current, Some(cells[y + 1][x]))?;
72 } else {
73 grid.create_edge(current, None)?;
74 }
75
76 if x > 0 {
78 grid.create_edge(current, Some(cells[y][x - 1]))?;
79 } else {
80 grid.create_edge(current, None)?;
81 }
82
83 if y > 0 {
85 grid.create_edge(current, Some(cells[y - 1][x]))?;
86 } else {
87 grid.create_edge(current, None)?;
88 }
89 }
90 }
91
92 println!(
93 "网格构建完成:{} 个单元格,{} 条边",
94 grid.get_cells_count(),
95 grid.get_edges_count()
96 );
97 Ok(())
98 }
99
100 fn get_dimensions(&self) -> Vec<usize> {
101 vec![self.width, self.height]
102 }
103
104 fn get_grid_type_name(&self) -> &'static str {
105 "Orthogonal2DGrid"
106 }
107}
108
109struct SquareTileSet {
115 tiles: TileSet<i32>,
116}
117
118impl SquareTileSet {
119 fn new() -> Self {
120 Self {
121 tiles: TileSet::new(),
122 }
123 }
124
125}
126
127impl TileSetVirtual<i32> for SquareTileSet {
128 fn build_tile_set(&mut self) -> Result<(), GridError> {
129 self.tiles.clear();
130
131 self.tiles.add_tile(vec![0, 0, 0, 0], 1); self.tiles.add_tile(vec![1, 0, 1, 0], 1); self.tiles.add_tile(vec![0, 1, 0, 1], 1); self.tiles.add_tile(vec![1, 1, 1, 0], 1); self.tiles.add_tile(vec![1, 0, 1, 1], 1); self.tiles.add_tile(vec![0, 1, 1, 1], 1); self.tiles.add_tile(vec![1, 1, 0, 1], 1); self.tiles.add_tile(vec![1, 1, 1, 1], 1); println!("瓷砖集构建完成:{} 种瓷砖", self.tiles.get_tile_count());
163 Ok(())
164 }
165
166 fn judge_possibility(&self, neighbor_possibilities: &[Vec<TileId>], candidate: TileId) -> bool {
167 let candidate_tile = match self.tiles.get_tile(candidate) {
168 Some(tile) => tile,
169 None => return false,
170 };
171
172 for (direction_index, neighbor_tiles) in neighbor_possibilities.iter().enumerate() {
175 if neighbor_tiles.is_empty() {
176 continue;
177 }
178
179 let mut edge_compatible = false;
180 let candidate_edge = candidate_tile.edges[direction_index];
181
182 for &neighbor_tile_id in neighbor_tiles {
183 if let Some(neighbor_tile) = self.tiles.get_tile(neighbor_tile_id) {
184 let neighbor_edge_index = match direction_index {
187 0 => 2, 1 => 3, 2 => 0, 3 => 1, _ => continue,
192 };
193
194 let neighbor_edge = neighbor_tile.edges[neighbor_edge_index];
195
196 if candidate_edge == neighbor_edge {
198 edge_compatible = true;
199 break;
200 }
201 }
202 }
203
204 if !edge_compatible {
205 return false;
206 }
207 }
208
209 true
210 }
211
212 fn get_tile(&self, tile_id: TileId) -> Option<&Tile<i32>> {
213 self.tiles.get_tile(tile_id)
214 }
215
216 fn get_tile_count(&self) -> usize {
217 self.tiles.get_tile_count()
218 }
219
220 fn get_all_tile_ids(&self) -> Vec<TileId> {
221 self.tiles.get_all_tile_ids()
222 }
223}
224
225fn main() -> Result<(), Box<dyn std::error::Error>> {
230 println!("正交2D WFC系统演示");
231 println!("对应C++版本的basicWFCManager实现");
232 println!();
233
234 let width = 10;
236 let height = 10;
237
238 let grid_builder = Orthogonal2DGridBuilder::new(width, height);
240 let grid = GridSystem::from_builder(grid_builder)?;
241
242 let tile_set = Box::new(SquareTileSet::new());
244
245 let mut wfc_manager = WfcManager::new(grid, tile_set)?;
247
248 let mut initializer = DefaultInitializer;
250 wfc_manager.initialize_with(&mut initializer)?;
251
252 println!("WFC系统初始化完成\n");
253
254 println!("初始状态:");
256 print_statistics(&wfc_manager);
257 print_ascii_grid(&wfc_manager, width, height);
258
259 println!("开始WFC算法执行...\n");
261
262 let mut step_count = 0;
263 let max_steps = 500000;
264
265 loop {
266 step_count += 1;
267
268 match wfc_manager.run_step() {
269 Ok(rlwfc::StepResult::Collapsed) => {
270 if step_count <= 5 {
271 println!("步骤 {}: 成功坍塌一个单元", step_count);
272 }
273 }
274 Ok(rlwfc::StepResult::ConflictsResolved) => {
275 println!("步骤 {}: 解决了冲突", step_count);
276 }
277 Ok(rlwfc::StepResult::Complete) => {
278 println!("步骤 {}: WFC算法完成!", step_count);
279 break;
280 }
281 Ok(rlwfc::StepResult::ConflictResolutionFailed) => {
282 println!("步骤 {}: 冲突解决失败", step_count);
283 break;
284 }
285 Err(e) => {
286 println!("步骤 {}: 错误 - {:?}", step_count, e);
287 break;
288 }
289 }
290
291 if step_count % 20 == 0 {
293 print_ascii_grid(&wfc_manager, width, height);
294 }
295
296 if step_count >= max_steps {
297 println!("达到最大步数限制 ({})", max_steps);
298 break;
299 }
300 }
301
302 println!("\n最终结果:");
304 print_statistics(&wfc_manager);
305 print_ascii_grid(&wfc_manager, width, height);
306
307 demonstrate_tiles(&wfc_manager)?;
309
310 Ok(())
311}
312
313fn print_statistics(manager: &WfcManager<i32>) {
315 let grid = manager.get_grid();
316 let total_cells = grid.get_cells_count();
317
318 let mut uncollapsed_count = 0;
319 let mut collapsed_count = 0;
320 let mut conflict_count = 0;
321
322 for cell_id in grid.get_all_cells() {
323 match manager.get_cell_state(cell_id) {
324 Ok(rlwfc::CellState::Uncollapsed) => uncollapsed_count += 1,
325 Ok(rlwfc::CellState::Collapsed) => collapsed_count += 1,
326 Ok(rlwfc::CellState::Conflict) => conflict_count += 1,
327 Err(_) => {}
328 }
329 }
330
331 println!("系统统计:");
332 println!(" 总单元格数: {}", total_cells);
333 println!(" 已坍塌: {}", collapsed_count);
334 println!(" 未坍塌: {}", uncollapsed_count);
335 println!(" 冲突: {}", conflict_count);
336 println!(
337 " 完成率: {:.1}%",
338 (collapsed_count as f64 / total_cells as f64) * 100.0
339 );
340}
341
342fn print_ascii_grid(manager: &WfcManager<i32>, width: usize, height: usize) {
344 println!("\nWFC 系统状态可视化:");
345
346 print!("┏");
348 for _ in 0..width * 2 {
349 print!("━");
350 }
351 println!("┓");
352
353 for y in 0..height {
354 print!("┃");
355 for x in 0..width {
356 let cell_name = format!("cell_{}_{}", x, y);
357 let cell_id = manager.get_grid().get_cell_by_name(&cell_name).unwrap();
358
359 let symbol = match manager.get_cell_state(cell_id) {
360 Ok(CellState::Collapsed) => {
361 let tile_id = manager.get_collapsed_cell_tile(cell_id).unwrap();
362 let tile = manager.get_tile(tile_id).unwrap();
363 tile_to_symbol(tile)
364 }
365 Ok(CellState::Uncollapsed) => "?",
366 Ok(CellState::Conflict) => "X",
367 Err(_) => "E",
368 };
369
370 print!("{} ", symbol);
371 }
372 println!("┃");
373 }
374
375 print!("┗");
377 for _ in 0..width * 2 {
378 print!("━");
379 }
380 println!("┛");
381
382 println!("图例: ? = 未坍塌, X = 冲突, = 空地, ┼ = 四通");
383 println!(" ─ │ = 直通道, ┌┐└┘ = 拐角, ├┤┬┴ = 三通, ╵╴╷╶ = 端点");
384}
385
386fn tile_to_symbol(tile: &Tile<i32>) -> &'static str {
388 match tile.edges.as_slice() {
390 [0, 0, 0, 0] => " ", [1, 1, 1, 1] => "┼", [1, 0, 1, 0] => "│", [0, 1, 0, 1] => "─", [1, 0, 0, 1] => "└", [0, 0, 1, 1] => "┌", [0, 1, 1, 0] => "┐", [1, 1, 0, 0] => "┘", [1, 0, 0, 0] => "↑",
404 [0, 1, 0, 0] => "←",
405 [0, 0, 1, 0] => "↓",
406 [0, 0, 0, 1] => "→",
407
408 [0, 1, 1, 1] => "┬", [1, 0, 1, 1] => "├", [1, 1, 0, 1] => "┴", [1, 1, 1, 0] => "┤", _ => "?",
416 }
417}
418
419fn demonstrate_tiles(manager: &WfcManager<i32>) -> Result<(), WfcError> {
421 println!("\n瓷砖信息:");
422 println!("{}", "─".repeat(40));
423
424 let tile_ids = manager.get_all_tile_ids();
425
426 for (i, &tile_id) in tile_ids.iter().enumerate() {
427 if let Some(tile) = manager.get_tile(tile_id) {
428 let symbol = tile_to_symbol(tile);
429 println!("瓷砖 {}: 边配置 {:?}, 符号: '{}'", i, tile.edges, symbol);
430 }
431 }
432
433 Ok(())
434}
435
436#[cfg(test)]
437mod tests {
438 use super::*;
439
440 #[test]
441 fn test_orthogonal_2d_grid_builder() {
442 let mut builder = Orthogonal2DGridBuilder::new(3, 3);
443 let mut grid = GridSystem::new();
444
445 builder.build_grid_system(&mut grid).unwrap();
446
447 assert_eq!(grid.get_cells_count(), 9);
448
449 let cell_1_1 = grid.get_cell_by_name("cell_1_1").unwrap();
451 assert!(grid.contains_cell(cell_1_1));
452 }
453
454 #[test]
455 fn test_square_tile_set() {
456 let mut tile_set = SquareTileSet::new();
457 tile_set.build_tile_set().unwrap();
458
459 assert_eq!(tile_set.get_tile_count(), 8); let all0_tile = tile_set.get_tile(0).unwrap();
463 assert_eq!(all0_tile.edges, vec![0, 0, 0, 0]);
464
465 let all1_tile = tile_set.get_tile(1).unwrap();
467 assert_eq!(all1_tile.edges, vec![1, 1, 1, 1]);
468 }
469
470 #[test]
471 fn test_tile_compatibility() {
472 let mut tile_set = SquareTileSet::new();
473 tile_set.build_tile_set().unwrap();
474
475 let neighbor_constraints = vec![
477 vec![0], vec![], vec![],
480 vec![],
481 ];
482
483 assert!(tile_set.judge_possibility(&neighbor_constraints, 0)); }
485}