summaryrefslogtreecommitdiff
path: root/dungeon/src/wfc.rs
blob: 0309546962370b095f39a4b0b12f2b874982c0dc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
//! The `wfc` module contains the implementation of the
//! Wave Function Collapse algorithm for procedural generation of the `Floor`.

use crate::map::Tile;
use crate::pos::Pos;

/// The `State` struct represents each possible state of a tile in the WFC algorithm.
struct State {
	/// Position of the tile
	#[expect(dead_code)]
	pos: Pos,
	/// Possible tiles for this state
	possible_tiles: Vec<Tile>,
	/// Entropy of the state
	entropy: f32,
}
impl State {
	/// Creates a new State instance
	fn new(pos: Pos, possible_tiles: Vec<Tile>) -> Self {
		let entropy = 0.0;
		Self {
			pos,
			possible_tiles,
			entropy,
		}
	}

	/// Updates the possible tiles and recalculates entropy
	#[expect(dead_code)]
	fn update_possible_tiles(&mut self, possible_tiles: Vec<Tile>) {
		self.possible_tiles = possible_tiles;
		self.entropy = self.entropy();
	}

	/// Calculates the entropy of the state
	/// TODO: Implement shannon entropy calculation
	fn entropy(&self) -> f32 {
		self.possible_tiles.len() as f32
	}
}

/// The `Wfc` struct encapsulates the Wave Function Collapse algorithm.
pub(crate) struct Wfc {
	/// The seed used for randomness in the algorithm
	#[expect(dead_code)]
	seed: u64,
	/// The size of the map to generate
	#[expect(dead_code)]
	mapsize: u16,
	/// The current state of the WFC algorithm (smart pointer for interior mutability)
	states: Vec<std::cell::RefCell<State>>,
	/// The random number generator
	#[expect(dead_code)]
	rng: rand::rngs::StdRng,
}
impl Wfc {
	/// Creates a new Wfc instance with the given seed and map size
	pub(crate) fn new(seed: u64, mapsize: u16) -> Self {
		let rng = rand::SeedableRng::seed_from_u64(seed);
		Self {
			seed,
			mapsize,
			states: Vec::with_capacity(mapsize as usize),
			rng,
		}
	}

	/// Initializes the states vector with default states
	pub(crate) fn initialize_states(&mut self) {
		for pos in Pos::values() {
			let possible_tiles = Tile::values().collect();
			let state = State::new(pos, possible_tiles);
			self.states.push(std::cell::RefCell::new(state));
		}
	}

	/// Runs the Wave Function Collapse algorithm to generate the map
	#[expect(clippy::unused_self)]
	pub(crate) fn run(&mut self) {
		// ----- Step 1: Read in input sample and define constraints -----
		// TODO: add support for sample image input

		// ----- Step 2: Initialize the grid of possible states -----

		// Start with an empty box of tiles

		// Store a superposition of all possible tiles for each position

		// ----- Step 3: Collapse the superpositions -----
		// Calculate the shannon entropy of all superpositions
		// Collapse the tile with the lowest entropy
		// (Assign a seeded random superposition)

		// ----- Step 4: Propogate -----
		// Update neighboring superpositions based on the collapsed tile
		// (Remove any that violate constraints)

		// ----- Step 5: Repeat until all superpositions are collapsed -----
		// If any tiles are left with no possible states, restart
		// TODO: backtrack
	}
}