summaryrefslogtreecommitdiff
path: root/dungeon/src/wfc.rs
blob: 596800074c4217a2905eca03934414e7135fd985 (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
//! 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.
pub(crate) struct State {
	/// Position of the tile
	pos: Pos,
	/// Possible tiles for this state
	possible_tiles: Vec<Tile>,
	/// Entropy of the state
	entropy: f32,
}

impl State {
	/// Creates a new State instance
	pub 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
	pub 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
	pub fn entropy(&self) -> f32 {
		self.possible_tiles.len() as f32
	}
}

/// The `Wfc` struct encapsulates the Wave Function Collapse algorithm.
pub struct Wfc {
	/// The seed used for randomness in the algorithm
	seed: u64,
	/// The size of the map to generate
	mapsize: u16,
	/// The current state of the WFC algorithm (smart pointer for interior mutability)
	states: Vec<std::cell::RefCell<State>>,
	/// The random number generator
	rng: rand::rngs::StdRng,
}

impl Wfc {
	/// Creates a new Wfc instance with the given seed and map size
	pub 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 fn initialize_states(&mut self) {

		for pos in Pos::values() {
            let possible_tiles = Tile::all_tiles();
            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
	pub 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
	}
}