use rlwfc::{
Cell, CellState, DefaultInitializer, GridBuilder, GridError,
GridSystem, Tile, TileId, TileSet, TileSetVirtual, WfcError, WfcManager,
};
struct Orthogonal2DGridBuilder {
width: usize,
height: usize,
}
impl Orthogonal2DGridBuilder {
fn new(width: usize, height: usize) -> Self {
Self { width, height }
}
}
impl GridBuilder for Orthogonal2DGridBuilder {
fn build_grid_system(&mut self, grid: &mut GridSystem) -> Result<(), GridError> {
println!("构建 {}x{} 正交2D网格...", self.width, self.height);
let mut cells = vec![vec![]; self.height];
for y in 0..self.height {
cells[y] = Vec::with_capacity(self.width);
for x in 0..self.width {
let cell_id = grid.add_cell_with_name(
Cell::with_id((y * self.width + x) as u32),
format!("cell_{}_{}", x, y),
);
cells[y].push(cell_id);
}
}
for y in 0..self.height {
for x in 0..self.width {
let current = cells[y][x];
if x < self.width - 1 {
grid.create_edge(current, Some(cells[y][x + 1]))?;
} else {
grid.create_edge(current, None)?;
}
if y < self.height - 1 {
grid.create_edge(current, Some(cells[y + 1][x]))?;
} else {
grid.create_edge(current, None)?;
}
if x > 0 {
grid.create_edge(current, Some(cells[y][x - 1]))?;
} else {
grid.create_edge(current, None)?;
}
if y > 0 {
grid.create_edge(current, Some(cells[y - 1][x]))?;
} else {
grid.create_edge(current, None)?;
}
}
}
println!(
"网格构建完成:{} 个单元格,{} 条边",
grid.get_cells_count(),
grid.get_edges_count()
);
Ok(())
}
fn get_dimensions(&self) -> Vec<usize> {
vec![self.width, self.height]
}
fn get_grid_type_name(&self) -> &'static str {
"Orthogonal2DGrid"
}
}
struct SquareTileSet {
tiles: TileSet<i32>,
}
impl SquareTileSet {
fn new() -> Self {
Self {
tiles: TileSet::new(),
}
}
}
impl TileSetVirtual<i32> for SquareTileSet {
fn build_tile_set(&mut self) -> Result<(), GridError> {
self.tiles.clear();
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());
Ok(())
}
fn judge_possibility(&self, neighbor_possibilities: &[Vec<TileId>], candidate: TileId) -> bool {
let candidate_tile = match self.tiles.get_tile(candidate) {
Some(tile) => tile,
None => return false,
};
for (direction_index, neighbor_tiles) in neighbor_possibilities.iter().enumerate() {
if neighbor_tiles.is_empty() {
continue;
}
let mut edge_compatible = false;
let candidate_edge = candidate_tile.edges[direction_index];
for &neighbor_tile_id in neighbor_tiles {
if let Some(neighbor_tile) = self.tiles.get_tile(neighbor_tile_id) {
let neighbor_edge_index = match direction_index {
0 => 2, 1 => 3, 2 => 0, 3 => 1, _ => continue,
};
let neighbor_edge = neighbor_tile.edges[neighbor_edge_index];
if candidate_edge == neighbor_edge {
edge_compatible = true;
break;
}
}
}
if !edge_compatible {
return false;
}
}
true
}
fn get_tile(&self, tile_id: TileId) -> Option<&Tile<i32>> {
self.tiles.get_tile(tile_id)
}
fn get_tile_count(&self) -> usize {
self.tiles.get_tile_count()
}
fn get_all_tile_ids(&self) -> Vec<TileId> {
self.tiles.get_all_tile_ids()
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("正交2D WFC系统演示");
println!("对应C++版本的basicWFCManager实现");
println!();
let width = 10;
let height = 10;
let grid_builder = Orthogonal2DGridBuilder::new(width, height);
let grid = GridSystem::from_builder(grid_builder)?;
let tile_set = Box::new(SquareTileSet::new());
let mut wfc_manager = WfcManager::new(grid, tile_set)?;
let mut initializer = DefaultInitializer;
wfc_manager.initialize_with(&mut initializer)?;
println!("WFC系统初始化完成\n");
println!("初始状态:");
print_statistics(&wfc_manager);
print_ascii_grid(&wfc_manager, width, height);
println!("开始WFC算法执行...\n");
let mut step_count = 0;
let max_steps = 500000;
loop {
step_count += 1;
match wfc_manager.run_step() {
Ok(rlwfc::StepResult::Collapsed) => {
if step_count <= 5 {
println!("步骤 {}: 成功坍塌一个单元", step_count);
}
}
Ok(rlwfc::StepResult::ConflictsResolved) => {
println!("步骤 {}: 解决了冲突", step_count);
}
Ok(rlwfc::StepResult::Complete) => {
println!("步骤 {}: WFC算法完成!", step_count);
break;
}
Ok(rlwfc::StepResult::ConflictResolutionFailed) => {
println!("步骤 {}: 冲突解决失败", step_count);
break;
}
Err(e) => {
println!("步骤 {}: 错误 - {:?}", step_count, e);
break;
}
}
if step_count % 20 == 0 {
print_ascii_grid(&wfc_manager, width, height);
}
if step_count >= max_steps {
println!("达到最大步数限制 ({})", max_steps);
break;
}
}
println!("\n最终结果:");
print_statistics(&wfc_manager);
print_ascii_grid(&wfc_manager, width, height);
demonstrate_tiles(&wfc_manager)?;
Ok(())
}
fn print_statistics(manager: &WfcManager<i32>) {
let grid = manager.get_grid();
let total_cells = grid.get_cells_count();
let mut uncollapsed_count = 0;
let mut collapsed_count = 0;
let mut conflict_count = 0;
for cell_id in grid.get_all_cells() {
match manager.get_cell_state(cell_id) {
Ok(rlwfc::CellState::Uncollapsed) => uncollapsed_count += 1,
Ok(rlwfc::CellState::Collapsed) => collapsed_count += 1,
Ok(rlwfc::CellState::Conflict) => conflict_count += 1,
Err(_) => {}
}
}
println!("系统统计:");
println!(" 总单元格数: {}", total_cells);
println!(" 已坍塌: {}", collapsed_count);
println!(" 未坍塌: {}", uncollapsed_count);
println!(" 冲突: {}", conflict_count);
println!(
" 完成率: {:.1}%",
(collapsed_count as f64 / total_cells as f64) * 100.0
);
}
fn print_ascii_grid(manager: &WfcManager<i32>, width: usize, height: usize) {
println!("\nWFC 系统状态可视化:");
print!("┏");
for _ in 0..width * 2 {
print!("━");
}
println!("┓");
for y in 0..height {
print!("┃");
for x in 0..width {
let cell_name = format!("cell_{}_{}", x, y);
let cell_id = manager.get_grid().get_cell_by_name(&cell_name).unwrap();
let symbol = match manager.get_cell_state(cell_id) {
Ok(CellState::Collapsed) => {
let tile_id = manager.get_collapsed_cell_tile(cell_id).unwrap();
let tile = manager.get_tile(tile_id).unwrap();
tile_to_symbol(tile)
}
Ok(CellState::Uncollapsed) => "?",
Ok(CellState::Conflict) => "X",
Err(_) => "E",
};
print!("{} ", symbol);
}
println!("┃");
}
print!("┗");
for _ in 0..width * 2 {
print!("━");
}
println!("┛");
println!("图例: ? = 未坍塌, X = 冲突, = 空地, ┼ = 四通");
println!(" ─ │ = 直通道, ┌┐└┘ = 拐角, ├┤┬┴ = 三通, ╵╴╷╶ = 端点");
}
fn tile_to_symbol(tile: &Tile<i32>) -> &'static str {
match tile.edges.as_slice() {
[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] => "↑",
[0, 1, 0, 0] => "←",
[0, 0, 1, 0] => "↓",
[0, 0, 0, 1] => "→",
[0, 1, 1, 1] => "┬", [1, 0, 1, 1] => "├", [1, 1, 0, 1] => "┴", [1, 1, 1, 0] => "┤",
_ => "?",
}
}
fn demonstrate_tiles(manager: &WfcManager<i32>) -> Result<(), WfcError> {
println!("\n瓷砖信息:");
println!("{}", "─".repeat(40));
let tile_ids = manager.get_all_tile_ids();
for (i, &tile_id) in tile_ids.iter().enumerate() {
if let Some(tile) = manager.get_tile(tile_id) {
let symbol = tile_to_symbol(tile);
println!("瓷砖 {}: 边配置 {:?}, 符号: '{}'", i, tile.edges, symbol);
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_orthogonal_2d_grid_builder() {
let mut builder = Orthogonal2DGridBuilder::new(3, 3);
let mut grid = GridSystem::new();
builder.build_grid_system(&mut grid).unwrap();
assert_eq!(grid.get_cells_count(), 9);
let cell_1_1 = grid.get_cell_by_name("cell_1_1").unwrap();
assert!(grid.contains_cell(cell_1_1));
}
#[test]
fn test_square_tile_set() {
let mut tile_set = SquareTileSet::new();
tile_set.build_tile_set().unwrap();
assert_eq!(tile_set.get_tile_count(), 8);
let all0_tile = tile_set.get_tile(0).unwrap();
assert_eq!(all0_tile.edges, vec![0, 0, 0, 0]);
let all1_tile = tile_set.get_tile(1).unwrap();
assert_eq!(all1_tile.edges, vec![1, 1, 1, 1]);
}
#[test]
fn test_tile_compatibility() {
let mut tile_set = SquareTileSet::new();
tile_set.build_tile_set().unwrap();
let neighbor_constraints = vec![
vec![0], vec![], vec![],
vec![],
];
assert!(tile_set.judge_possibility(&neighbor_constraints, 0)); }
}