- Update landgen to use the latest rand crate
- Change Size width and height from usize to u32 for portability
- Implement backtracking in wfc generator
--- a/rust/integral-geometry/src/lib.rs Tue Jan 28 10:37:46 2025 +0100
+++ b/rust/integral-geometry/src/lib.rs Tue Jan 28 15:49:45 2025 +0100
@@ -113,20 +113,20 @@
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct Size {
- pub width: usize,
- pub height: usize,
+ pub width: u32,
+ pub height: u32,
}
impl Size {
pub const EMPTY: Self = Self::square(0);
#[inline]
- pub const fn new(width: usize, height: usize) -> Self {
+ pub const fn new(width: u32, height: u32) -> Self {
Self { width, height }
}
#[inline]
- pub const fn square(size: usize) -> Self {
+ pub const fn square(size: u32) -> Self {
Self {
width: size,
height: size,
@@ -134,12 +134,12 @@
}
#[inline]
- pub const fn area(&self) -> usize {
+ pub const fn area(&self) -> u32 {
self.width * self.height
}
#[inline]
- pub const fn linear_index(&self, x: usize, y: usize) -> usize {
+ pub const fn linear_index(&self, x: u32, y: u32) -> u32 {
y * self.width + x
}
@@ -194,7 +194,7 @@
impl PotSize {
#[inline]
- const fn new_impl(width: usize, height: usize) -> Self {
+ const fn new_impl(width: u32, height: u32) -> Self {
debug_assert!(width.is_power_of_two() && height.is_power_of_two());
Self {
size: Size::new(width, height),
@@ -202,7 +202,7 @@
}
#[inline]
- pub const fn new(width: usize, height: usize) -> Option<Self> {
+ pub const fn new(width: u32, height: u32) -> Option<Self> {
if width.is_power_of_two() && height.is_power_of_two() {
Some(Self::new_impl(width, height))
} else {
@@ -214,16 +214,16 @@
self.size
}
- pub const fn width(&self) -> usize {
+ pub const fn width(&self) -> u32 {
self.size.width
}
- pub const fn height(&self) -> usize {
+ pub const fn height(&self) -> u32 {
self.size.height
}
#[inline]
- pub const fn square(size: usize) -> Option<Self> {
+ pub const fn square(size: u32) -> Option<Self> {
if size.is_power_of_two() {
Some(Self::new_impl(size, size))
} else {
@@ -232,12 +232,12 @@
}
#[inline]
- pub const fn area(&self) -> usize {
+ pub const fn area(&self) -> u32 {
self.size.area()
}
#[inline]
- pub const fn linear_index(&self, x: usize, y: usize) -> usize {
+ pub const fn linear_index(&self, x: u32, y: u32) -> u32 {
self.size.linear_index(x, y)
}
@@ -289,18 +289,18 @@
}
#[inline]
- pub fn contains_x<T: Into<usize>>(&self, x: T) -> bool {
+ pub fn contains_x<T: Into<u32>>(&self, x: T) -> bool {
(self.size.width & x.into()) == 0
}
#[inline]
- pub fn contains_y<T: Into<usize>>(&self, y: T) -> bool {
+ pub fn contains_y<T: Into<u32>>(&self, y: T) -> bool {
(self.size.height & y.into()) == 0
}
#[inline]
pub fn contains(&self, point: Point) -> bool {
- self.contains_x(point.x as usize) && self.contains_y(point.y as usize)
+ self.contains_x(point.x as u32) && self.contains_y(point.y as u32)
}
#[inline]
@@ -439,7 +439,7 @@
)
}
- pub fn from_size_coords(x: i32, y: i32, width: usize, height: usize) -> Self {
+ pub fn from_size_coords(x: i32, y: i32, width: u32, height: u32) -> Self {
Self::from_size(Point::new(x, y), Size::new(width, height))
}
@@ -448,13 +448,13 @@
}
#[inline]
- pub const fn width(&self) -> usize {
- (self.right() - self.left() + 1) as usize
+ pub const fn width(&self) -> u32 {
+ (self.right() - self.left() + 1) as u32
}
#[inline]
- pub const fn height(&self) -> usize {
- (self.bottom() - self.top() + 1) as usize
+ pub const fn height(&self) -> u32 {
+ (self.bottom() - self.top() + 1) as u32
}
#[inline]
@@ -463,7 +463,7 @@
}
#[inline]
- pub const fn area(&self) -> usize {
+ pub const fn area(&self) -> u32 {
self.size().area()
}
@@ -504,7 +504,10 @@
#[inline]
pub fn with_margin(&self, margin: i32) -> Self {
- let offset = Point::new(min(margin, self.width() as i32 / 2), min(margin, self.height() as i32 / 2));
+ let offset = Point::new(
+ min(margin, self.width() as i32 / 2),
+ min(margin, self.height() as i32 / 2),
+ );
Self::new(self.top_left() + offset, self.bottom_right() - offset)
}
@@ -566,7 +569,7 @@
}
#[inline]
- pub fn quotient(self, x: usize, y: usize) -> Point {
+ pub fn quotient(self, x: u32, y: u32) -> Point {
self.top_left() + Point::new((x % self.width()) as i32, (y % self.height()) as i32)
}
}
--- a/rust/land2d/src/lib.rs Tue Jan 28 10:37:46 2025 +0100
+++ b/rust/land2d/src/lib.rs Tue Jan 28 15:49:45 2025 +0100
@@ -48,12 +48,12 @@
}
#[inline]
- pub fn play_width(&self) -> usize {
+ pub fn play_width(&self) -> u32 {
self.play_box.width()
}
#[inline]
- pub fn play_height(&self) -> usize {
+ pub fn play_height(&self) -> u32 {
self.play_box.height()
}
@@ -69,12 +69,12 @@
#[inline]
pub fn is_valid_x(&self, x: i32) -> bool {
- self.mask.contains_x(x as usize)
+ self.mask.contains_x(x as u32)
}
#[inline]
pub fn is_valid_y(&self, y: i32) -> bool {
- self.mask.contains_y(y as usize)
+ self.mask.contains_y(y as u32)
}
#[inline]
@@ -150,7 +150,7 @@
dir: isize,
) {
let yd = y as isize + dir;
- if mask.contains_y(yd as usize) {
+ if mask.contains_y(yd as u32) {
stack.push((xl, xr, yd as usize, dir));
}
}
@@ -331,7 +331,7 @@
#[test]
fn basics() {
- let l: Land2D<u8> = Land2D::new(Size::new(30, 50), 0);
+ let l: Land2D<u8> = Land2D::new(&Size::new(30, 50), 0);
assert_eq!(l.play_width(), 30);
assert_eq!(l.play_height(), 50);
@@ -348,7 +348,7 @@
#[test]
fn fill() {
- let mut l: Land2D<u8> = Land2D::new(Size::square(128), 0);
+ let mut l: Land2D<u8> = Land2D::new(&Size::square(128), 0);
l.draw_line(Line::new(Point::new(0, 0), Point::new(32, 96)), 1);
l.draw_line(Line::new(Point::new(32, 96), Point::new(64, 32)), 1);
--- a/rust/landgen/Cargo.toml Tue Jan 28 10:37:46 2025 +0100
+++ b/rust/landgen/Cargo.toml Tue Jan 28 15:49:45 2025 +0100
@@ -9,7 +9,7 @@
land2d = { path = "../land2d" }
vec2d = { path = "../vec2d" }
png = "0.17"
-rand = "0.8"
+rand = "0.9"
[dev-dependencies]
criterion = "0.5"
--- a/rust/landgen/src/maze.rs Tue Jan 28 10:37:46 2025 +0100
+++ b/rust/landgen/src/maze.rs Tue Jan 28 15:49:45 2025 +0100
@@ -3,12 +3,13 @@
use integral_geometry::{Point, Polygon, Rect, Size};
use land2d::Land2D;
use rand::Rng;
+use vec2d::Vec2D;
#[derive(Clone)]
pub struct MazeTemplate {
- pub width: usize,
- pub height: usize,
- pub cell_size: usize,
+ pub width: u32,
+ pub height: u32,
+ pub cell_size: u32,
pub inverted: bool,
pub distortion_limiting_factor: u32,
pub braidness: u32,
@@ -21,10 +22,10 @@
num_cells: Size,
num_edges: Size,
seen_cells: Size,
- cell_size: usize,
- seen_list: Vec<Vec<Option<usize>>>,
- walls: Vec<Vec<Vec<bool>>>,
- edge_list: Vec<Vec<Vec<bool>>>,
+ cell_size: u32,
+ seen_list: Vec2D<Option<usize>>,
+ walls: Vec<Vec2D<bool>>,
+ edge_list: Vec<Vec2D<bool>>,
last_cell: Vec<Point>,
came_from: Vec<Vec<Point>>,
came_from_pos: Vec<i32>,
@@ -80,7 +81,7 @@
impl Maze {
pub fn new(
size: &Size,
- cell_size: usize,
+ cell_size: u32,
num_steps: usize,
inverted: bool,
braidness: u32,
@@ -96,17 +97,17 @@
let mut last_cell = vec![Point::diag(0); num_steps];
let came_from_pos = vec![0; num_steps];
- let came_from = vec![vec![Point::diag(0); num_steps]; num_cells.area()];
+ let came_from = vec![vec![Point::diag(0); num_steps]; num_cells.area() as usize];
- let seen_list = vec![vec![None as Option<usize>; seen_cells.width]; seen_cells.height];
- let walls = vec![vec![vec![true; seen_cells.width]; seen_cells.height]; 2];
- let edge_list = vec![vec![vec![false; num_cells.width]; num_cells.height]; 2];
+ let seen_list = Vec2D::new(&seen_cells, None);
+ let walls = vec![Vec2D::new(&seen_cells, true); 2];
+ let edge_list = vec![Vec2D::new(&num_cells, false); 2];
for current_step in 0..num_steps {
- let x = random_numbers.gen_range(0..seen_cells.width - 1) / num_steps;
+ let x = random_numbers.random_range(0..seen_cells.width as i32 - 1) / num_steps as i32;
last_cell[current_step] = Point::new(
- (x + current_step * seen_cells.width / num_steps) as i32,
- random_numbers.gen_range(0..seen_cells.height) as i32,
+ x + current_step as i32 * seen_cells.width as i32 / num_steps as i32,
+ random_numbers.random_range(..seen_cells.height) as i32,
);
}
@@ -141,7 +142,7 @@
let p = self.last_cell[current_step];
self.seen_list[p.y as usize][p.x as usize] = Some(current_step);
- let next_dir_clockwise = random_numbers.gen();
+ let next_dir_clockwise = random_numbers.random();
for _ in 0..5 {
let sp = p + dir.0;
@@ -158,7 +159,7 @@
match when_seen {
Some(a) if a == current_step => {
// try another direction
- if !self.inverted && random_numbers.gen_range(0..self.braidness) == 0 {
+ if !self.inverted && random_numbers.random_range(..self.braidness) == 0 {
if dir.0.x == -1 && p.x > 0 {
self.walls[dir.orientation()][p.y as usize][p.x as usize - 1] =
false;
@@ -261,46 +262,46 @@
pub fn to_islands(mut self) -> (Vec<Polygon>, Vec<Point>) {
let mut islands: Vec<Polygon> = vec![];
let mut polygon: Vec<Point> = vec![];
- let mut maze = vec![vec![false; self.num_cells.width]; self.num_cells.height];
+ let mut maze = Vec2D::new(&self.num_cells, false);
- for x in 0..self.seen_cells.width {
- for y in 0..self.seen_cells.height {
+ for x in 0..self.seen_cells.width as usize {
+ for y in 0..self.seen_cells.height as usize {
if self.seen_list[y][x].is_some() {
maze[y * 2 + 1][x * 2 + 1] = true;
}
}
- for y in 0..self.seen_cells.height - 1 {
+ for y in 0..self.seen_cells.height as usize - 1 {
if !self.walls[0][y][x] {
maze[y * 2 + 2][x * 2 + 1] = true;
}
}
}
- for x in 0..self.seen_cells.width - 1 {
- for y in 0..self.seen_cells.height {
+ for x in 0..self.seen_cells.width as usize - 1 {
+ for y in 0..self.seen_cells.height as usize {
if !self.walls[1][y][x] {
maze[y * 2 + 1][x * 2 + 2] = true;
}
}
}
- for x in 0..self.num_edges.width {
- for y in 0..self.num_cells.height {
+ for x in 0..self.num_edges.width as usize {
+ for y in 0..self.num_cells.height as usize {
self.edge_list[0][y][x] = maze[y][x] != maze[y][x + 1];
}
}
- for x in 0..self.num_cells.width {
- for y in 0..self.num_edges.height {
+ for x in 0..self.num_cells.width as usize {
+ for y in 0..self.num_edges.height as usize {
self.edge_list[1][y][x] = maze[y][x] != maze[y + 1][x];
}
}
let mut fill_points = vec![];
- for x in 0..self.num_edges.width {
- for y in 0..self.num_cells.height {
+ for x in 0..self.num_edges.width as usize {
+ for y in 0..self.num_cells.height as usize {
if self.edge_list[0][y][x] {
self.edge_list[0][y][x] = false;
self.add_vertex(Point::new(x as i32 + 1, y as i32 + 1), &mut polygon);
@@ -328,13 +329,13 @@
}
}
- for x in 0..self.num_cells.width {
- for y in 0..self.num_cells.height {
+ for x in 0..self.num_cells.width as usize {
+ for y in 0..self.num_cells.height as usize {
if maze[y][x] {
let half_cell = self.cell_size / 2;
let fill_point = Point::new(
- (x * self.cell_size + half_cell) as i32 + self.off.x,
- (y * self.cell_size + half_cell) as i32 + self.off.y,
+ (x as u32 * self.cell_size + half_cell) as i32 + self.off.x,
+ (y as u32 * self.cell_size + half_cell) as i32 + self.off.y,
);
islands.push(Polygon::new(&[fill_point]));
fill_points.push(fill_point);
@@ -348,13 +349,13 @@
if x > 0 {
points.push((x - 1, y));
}
- if x < self.num_cells.width - 1 {
+ if x < self.num_cells.width as usize - 1 {
points.push((x + 1, y));
}
if y > 0 {
points.push((x, y - 1));
}
- if y < self.num_cells.height - 1 {
+ if y < self.num_cells.height as usize - 1 {
points.push((x, y + 1));
}
}
@@ -371,7 +372,7 @@
maze_template: MazeTemplate,
}
-fn prev_odd(num: usize) -> usize {
+fn prev_odd(num: u32) -> u32 {
if num & 1 == 0 {
num - 1
} else {
@@ -409,7 +410,7 @@
for current_step in 0..num_steps {
if !step_done[current_step] {
- let dir = Direction::new(random_numbers.gen());
+ let dir = Direction::new(random_numbers.random_range(..4));
step_done[current_step] = maze.see_cell(current_step, dir, random_numbers);
done = false;
}
--- a/rust/landgen/src/outline_template_based/outline.rs Tue Jan 28 10:37:46 2025 +0100
+++ b/rust/landgen/src/outline_template_based/outline.rs Tue Jan 28 15:49:45 2025 +0100
@@ -27,7 +27,7 @@
.map(|i| {
i.iter()
.map(|rect| {
- let (rnd_a, rnd_b) = random_numbers.gen();
+ let (rnd_a, rnd_b) = random_numbers.random();
play_box.top_left() + rect.quotient(rnd_a, rnd_b)
})
.collect::<Vec<_>>()
@@ -241,8 +241,9 @@
Some(mid_point)
} else {
// select distance within [-dist_right; dist_left], keeping min_distance in mind
- let d = random_numbers
- .gen_range(-(dist_right as i32) + min_distance..=dist_left as i32 - min_distance);
+ let d = random_numbers.random_range(
+ -(dist_right as i32) + min_distance..=dist_left as i32 - min_distance,
+ );
Some(mid_point + normal * d / normal_len as i32)
}
--- a/rust/landgen/src/outline_template_based/template_based.rs Tue Jan 28 10:37:46 2025 +0100
+++ b/rust/landgen/src/outline_template_based/template_based.rs Tue Jan 28 15:49:45 2025 +0100
@@ -20,7 +20,7 @@
random_numbers: &mut impl Rng,
) -> Land2D<T> {
let do_invert = self.outline_template.is_negative
- && (!self.outline_template.can_invert || random_numbers.gen());
+ && (!self.outline_template.can_invert || random_numbers.random());
let (basic, zero) = if do_invert {
(parameters.zero, parameters.basic)
} else {
@@ -37,17 +37,17 @@
);
// mirror
- if self.outline_template.can_mirror && random_numbers.gen() {
+ if self.outline_template.can_mirror && random_numbers.random() {
points.mirror();
}
// flip
- if self.outline_template.can_flip && random_numbers.gen() {
+ if self.outline_template.can_flip && random_numbers.random() {
points.flip();
}
if !parameters.skip_distort {
- let distortion_limiting_factor = 100 + random_numbers.gen_range(0..8) * 10;
+ let distortion_limiting_factor = 100 + random_numbers.random_range(0..8) * 10;
points.distort(
parameters.distance_divisor,
--- a/rust/landgen/src/wavefront_collapse/generator.rs Tue Jan 28 10:37:46 2025 +0100
+++ b/rust/landgen/src/wavefront_collapse/generator.rs Tue Jan 28 15:49:45 2025 +0100
@@ -91,10 +91,8 @@
let mut reader = decoder.read_info()?;
let info = reader.info();
- let mut tiles_image = vec2d::Vec2D::new(
- &Size::new(info.width as usize, info.height as usize),
- parameters.zero,
- );
+ let mut tiles_image =
+ vec2d::Vec2D::new(&Size::new(info.width, info.height), parameters.zero);
let mut buf = vec![0; reader.output_buffer_size()];
let info = reader.next_frame(&mut buf)?;
@@ -325,19 +323,20 @@
// render tiles into resulting land array
let mut result = land2d::Land2D::new(&self.template.size, parameters.zero);
- let offset_y = result.height() - result.play_height();
- let offset_x = (result.width() - result.play_width()) / 2;
+ let offset_y = result.height() - result.play_height() as usize;
+ let offset_x = (result.width() - result.play_width() as usize) / 2;
- for row in 0..wfc_size.height {
- for column in 0..wfc_size.width {
+ for row in 0..wfc_size.height as usize {
+ for column in 0..wfc_size.width as usize {
if let Some(Tile::Numbered(tile_index)) = wfc.grid().get(row, column) {
let tile = &tiles[*tile_index];
- for tile_row in 0..tile.size().height {
- for tile_column in 0..tile.size().width {
+ for tile_row in 0..tile.size().height as usize {
+ for tile_column in 0..tile.size().width as usize {
result.map(
- (row * tile.size().height + tile_row + offset_y) as i32,
- (column * tile.size().width + tile_column + offset_x) as i32,
+ (row * tile.size().height as usize + tile_row + offset_y) as i32,
+ (column * tile.size().width as usize + tile_column + offset_x)
+ as i32,
|p| {
*p =
*tile.get(tile_row, tile_column).unwrap_or(¶meters.zero)
--- a/rust/landgen/src/wavefront_collapse/wavefront_collapse.rs Tue Jan 28 10:37:46 2025 +0100
+++ b/rust/landgen/src/wavefront_collapse/wavefront_collapse.rs Tue Jan 28 15:49:45 2025 +0100
@@ -1,6 +1,6 @@
use integral_geometry::Size;
-use rand::distributions::Distribution;
-use rand::distributions::WeightedIndex;
+use rand::distr::{weighted::WeightedIndex, Distribution};
+use rand::prelude::IndexedRandom;
use rand::Rng;
use std::collections::HashSet;
use vec2d::Vec2D;
@@ -59,7 +59,19 @@
seed_fn(&mut self.grid);
- while self.collapse_step(random_numbers) {}
+ let mut backtracks = 0usize;
+ while let Some(b) = self.collapse_step(random_numbers) {
+ backtracks += b;
+
+ if backtracks >= 1000 {
+ println!("[WFC] Too much backtracking, stopping generation!");
+ break;
+ }
+ }
+
+ if backtracks > 0 {
+ println!("[WFC] Had to backtrack {} times...", backtracks);
+ }
}
pub fn set_rules(&mut self, rules: Vec<CollapseRule>) {
@@ -109,7 +121,7 @@
})
}
- fn collapse_step(&mut self, random_numbers: &mut impl Rng) -> bool {
+ fn collapse_step(&mut self, random_numbers: &mut impl Rng) -> Option<usize> {
let mut tiles_to_collapse = (usize::MAX, Vec::new());
// Iterate through the tiles in the land
@@ -118,11 +130,16 @@
let current_tile = self.get_tile(y, x);
if let Tile::Empty = current_tile {
+ let neighbors = [
+ (y, x.wrapping_add(1)),
+ (y.wrapping_add(1), x),
+ (y, x.wrapping_sub(1)),
+ (y.wrapping_sub(1), x),
+ ];
+
// calc entropy
- let right_tile = self.get_tile(y, x.wrapping_add(1));
- let bottom_tile = self.get_tile(y.wrapping_add(1), x);
- let left_tile = self.get_tile(y, x.wrapping_sub(1));
- let top_tile = self.get_tile(y.wrapping_sub(1), x);
+ let [right_tile, bottom_tile, left_tile, top_tile] =
+ neighbors.map(|(y, x)| self.get_tile(y, x));
let possibilities: Vec<(u32, Tile)> = self
.rules
@@ -146,7 +163,8 @@
let weights = possibilities.iter().map(|(weight, _)| *weight);
let distribution = WeightedIndex::new(weights).unwrap();
- let entry = (y, x, possibilities[distribution.sample(random_numbers)]);
+ let entry =
+ (y, x, possibilities[distribution.sample(random_numbers)].1);
if entropy < tiles_to_collapse.0 {
tiles_to_collapse = (entropy, vec![entry])
@@ -155,12 +173,26 @@
}
}
} else {
- /*println!("We're here: {}, {}", x, y);
+ /*
+ println!("We're here: {}, {}", x, y);
println!(
"Neighbour tiles are: {:?} {:?} {:?} {:?}",
right_tile, bottom_tile, left_tile, top_tile
);
- println!("Rules are: {:?}", self.rules);*/
+ println!("Rules are: {:?}", self.rules);
+ */
+
+ let entries = neighbors
+ .iter()
+ .filter(|(y, x)| self.grid.get(*y, *x).is_some())
+ .map(|(y, x)| (*y, *x, Tile::Empty))
+ .collect::<Vec<_>>();
+
+ if entropy < tiles_to_collapse.0 {
+ tiles_to_collapse = (entropy, entries);
+ } else {
+ tiles_to_collapse.1.extend(entries);
+ }
//todo!("no collapse possible - what to do?")
}
@@ -168,23 +200,28 @@
}
}
- let tiles_to_collapse = tiles_to_collapse.1;
- let possibilities_number = tiles_to_collapse.len();
+ if tiles_to_collapse.0 == 0 {
+ // cannot collapse, we're clearing some tiles
- if possibilities_number > 0 {
- let weights = tiles_to_collapse.iter().map(|(_, _, (weight, _))| *weight);
- let distribution = WeightedIndex::new(weights).unwrap();
-
- let (y, x, (_, tile)) = tiles_to_collapse[distribution.sample(random_numbers)];
+ for (y, x, tile) in tiles_to_collapse.1 {
+ *self
+ .grid
+ .get_mut(y, x)
+ .expect("correct iteration over grid") = tile;
+ }
- *self
- .grid
- .get_mut(y, x)
- .expect("correct iteration over grid") = tile;
+ Some(1)
+ } else {
+ if let Some(&(y, x, tile)) = tiles_to_collapse.1.as_slice().choose(random_numbers) {
+ *self
+ .grid
+ .get_mut(y, x)
+ .expect("correct iteration over grid") = tile;
- true
- } else {
- false
+ Some(0)
+ } else {
+ None
+ }
}
}
--- a/rust/lib-hwengine-future/src/lib.rs Tue Jan 28 10:37:46 2025 +0100
+++ b/rust/lib-hwengine-future/src/lib.rs Tue Jan 28 15:49:45 2025 +0100
@@ -39,8 +39,8 @@
#[no_mangle]
pub extern "C" fn create_empty_game_field(width: u32, height: u32) -> *mut GameField {
let game_field = Box::new(GameField {
- collision: land2d::Land2D::new(&Size::new(width as usize, height as usize), 0),
- pixels: land2d::Land2D::new(&Size::new(width as usize, height as usize), 0),
+ collision: land2d::Land2D::new(&Size::new(width, height), 0),
+ pixels: land2d::Land2D::new(&Size::new(width, height), 0),
landgen_parameters: None,
});
--- a/rust/mapgen/src/lib.rs Tue Jan 28 10:37:46 2025 +0100
+++ b/rust/mapgen/src/lib.rs Tue Jan 28 15:49:45 2025 +0100
@@ -19,10 +19,10 @@
},
LandGenerationParameters, LandGenerator,
};
-use rand::{seq::SliceRandom, Rng};
+use rand::Rng;
+use rand::prelude::IndexedRandom;
use std::{borrow::Borrow, collections::hash_map::HashMap};
-use rand::prelude::IndexedRandom;
use vec2d::Vec2D;
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
@@ -68,7 +68,7 @@
if let Some(land_sprite) = theme.land_texture() {
for (row_index, (land_row, tex_row)) in land.rows().zip(texture.rows_mut()).enumerate()
{
- let sprite_row = land_sprite.get_row(row_index % land_sprite.height());
+ let sprite_row = land_sprite.get_row(row_index % land_sprite.height() as usize);
let mut x_offset = 0;
while sprite_row.len() < land.width() - x_offset {
let copy_range = x_offset..x_offset + sprite_row.len();
@@ -79,7 +79,7 @@
sprite_row,
);
- x_offset += land_sprite.width()
+ x_offset += land_sprite.width() as usize
}
if x_offset < land.width() {
@@ -107,8 +107,10 @@
&mut offsets,
border_width,
|x, y| {
- border_sprite
- .get_pixel(x % border_sprite.width(), border_sprite.height() - 1 - y)
+ border_sprite.get_pixel(
+ x % border_sprite.width() as usize,
+ border_sprite.height() as usize - 1 - y,
+ )
},
);
@@ -119,7 +121,7 @@
land.rows().zip(texture.rows_mut()),
&mut offsets,
border_width,
- |x, y| border_sprite.get_pixel(x % border_sprite.width(), y),
+ |x, y| border_sprite.get_pixel(x % border_sprite.width() as usize, y),
);
}
@@ -169,7 +171,10 @@
.map(|(size, indices)| {
(
TemplateType(size),
- indices.iter().map(|i| templates[*i].to_template(&desc.tiles, &desc.edges)).collect(),
+ indices
+ .iter()
+ .map(|i| templates[*i].to_template(&desc.tiles, &desc.edges))
+ .collect(),
)
})
.collect();
--- a/rust/mapgen/src/template/maze.rs Tue Jan 28 10:37:46 2025 +0100
+++ b/rust/mapgen/src/template/maze.rs Tue Jan 28 15:49:45 2025 +0100
@@ -4,10 +4,10 @@
use std::collections::hash_map::HashMap;
#[derive(Deserialize)]
pub struct TemplateDesc {
- width: usize,
- height: usize,
+ width: u32,
+ height: u32,
max_hedgehogs: u8,
- cell_size: usize,
+ cell_size: u32,
distortion_limiting_factor: u32,
braidness: u32,
invert: bool,
--- a/rust/mapgen/src/template/outline.rs Tue Jan 28 10:37:46 2025 +0100
+++ b/rust/mapgen/src/template/outline.rs Tue Jan 28 15:49:45 2025 +0100
@@ -21,8 +21,8 @@
#[derive(Deserialize, Clone)]
pub struct TemplateDesc {
- width: usize,
- height: usize,
+ width: u32,
+ height: u32,
can_flip: bool,
can_invert: bool,
can_mirror: bool,
@@ -55,10 +55,7 @@
.map(|v| {
v.iter()
.map(|r| {
- Rect::from_size(
- Point::new(r.x as i32, r.y as i32),
- Size::new(r.w as usize, r.h as usize),
- )
+ Rect::from_size(Point::new(r.x as i32, r.y as i32), Size::new(r.w, r.h))
})
.collect()
})
@@ -70,10 +67,7 @@
.map(|v| {
v.iter()
.map(|r| {
- Rect::from_size(
- Point::new(r.x as i32, r.y as i32),
- Size::new(r.w as usize, r.h as usize),
- )
+ Rect::from_size(Point::new(r.x as i32, r.y as i32), Size::new(r.w, r.h))
})
.collect()
})
--- a/rust/mapgen/src/template/wavefront_collapse.rs Tue Jan 28 10:37:46 2025 +0100
+++ b/rust/mapgen/src/template/wavefront_collapse.rs Tue Jan 28 15:49:45 2025 +0100
@@ -33,8 +33,8 @@
#[derive(Debug, Deserialize)]
pub struct TemplateDesc {
- pub width: usize,
- pub height: usize,
+ pub width: u32,
+ pub height: u32,
pub can_invert: Option<bool>,
pub is_negative: Option<bool>,
pub put_girders: Option<bool>,
@@ -53,7 +53,11 @@
}
impl TemplateDesc {
- pub fn to_template(&self, tiles: &HashMap<String, Vec<TileDesc>>, edges: &HashMap<String, NonStrictComplexEdgesDesc>) -> TemplateDescription {
+ pub fn to_template(
+ &self,
+ tiles: &HashMap<String, Vec<TileDesc>>,
+ edges: &HashMap<String, NonStrictComplexEdgesDesc>,
+ ) -> TemplateDescription {
let [top, right, bottom, left]: [Option<ComplexEdgeDescription>; 4] =
if let Some(edges_name) = &self.edges {
let edges = edges.get(edges_name).expect("missing template edges");
@@ -63,7 +67,11 @@
[None, None, None, None]
};
- let tiles = self.tiles.iter().flat_map(|t| tiles.get(t).expect("missing template tiles")).collect::<Vec<_>>();
+ let tiles = self
+ .tiles
+ .iter()
+ .flat_map(|t| tiles.get(t).expect("missing template tiles"))
+ .collect::<Vec<_>>();
TemplateDescription {
size: Size::new(self.width, self.height),
--- a/rust/mapgen/src/theme.rs Tue Jan 28 10:37:46 2025 +0100
+++ b/rust/mapgen/src/theme.rs Tue Jan 28 15:49:45 2025 +0100
@@ -22,12 +22,12 @@
}
#[inline]
- pub fn width(&self) -> usize {
+ pub fn width(&self) -> u32 {
self.size().width
}
#[inline]
- pub fn height(&self) -> usize {
+ pub fn height(&self) -> u32 {
self.size().height
}
@@ -61,7 +61,7 @@
let size = self.size();
assert!(size.is_power_of_two());
let tile_width_shift = size.width.trailing_zeros() as usize + 2;
- let mut pixels = vec![0u32; size.area()];
+ let mut pixels = vec![0u32; size.area() as usize];
for (y, row) in self.pixels.rows().enumerate() {
for (x, v) in row.iter().enumerate() {
@@ -95,12 +95,12 @@
}
#[inline]
- pub fn width(&self) -> usize {
+ pub fn width(&self) -> u32 {
self.size().width
}
#[inline]
- pub fn height(&self) -> usize {
+ pub fn height(&self) -> u32 {
self.size().height
}
@@ -237,7 +237,7 @@
info.color_type
)));
}
- let size = Size::new(info.width as usize, info.height as usize);
+ let size = Size::new(info.width, info.height);
let mut pixels: Vec2D<u32> = Vec2D::new(&size, 0);
reader.next_frame(slice_u32_to_u8_mut(pixels.as_mut_slice()))?;
--- a/rust/vec2d/src/lib.rs Tue Jan 28 10:37:46 2025 +0100
+++ b/rust/vec2d/src/lib.rs Tue Jan 28 15:49:45 2025 +0100
@@ -4,7 +4,7 @@
slice::SliceIndex,
};
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct Vec2D<T> {
data: Vec<T>,
size: Size,
@@ -30,19 +30,19 @@
let pos = row * self.width();
- &mut self.data[pos..pos + self.size.width]
+ &mut self.data[pos..pos + self.size.width as usize]
}
}
impl<T> Vec2D<T> {
#[inline]
pub fn width(&self) -> usize {
- self.size.width
+ self.size.width as usize
}
#[inline]
pub fn height(&self) -> usize {
- self.size.height
+ self.size.height as usize
}
#[inline]
@@ -55,7 +55,7 @@
pub fn new(size: &Size, value: T) -> Self {
Self {
size: *size,
- data: vec![value; size.area()],
+ data: vec![value; size.area() as usize],
}
}
@@ -85,7 +85,10 @@
column: usize,
) -> Option<&mut <usize as SliceIndex<[T]>>::Output> {
if row < self.height() && column < self.width() {
- Some(unsafe { self.data.get_unchecked_mut(row * self.size.width + column) })
+ Some(unsafe {
+ self.data
+ .get_unchecked_mut(row * self.size.width as usize + column)
+ })
} else {
None
}
@@ -106,7 +109,8 @@
row: usize,
column: usize,
) -> &mut <usize as SliceIndex<[T]>>::Output {
- self.data.get_unchecked_mut(row * self.size.width + column)
+ self.data
+ .get_unchecked_mut(row * self.size.width as usize + column)
}
#[inline]
@@ -146,7 +150,7 @@
impl<T: Clone> Vec2D<T> {
pub fn from_iter<I: IntoIterator<Item = T>>(iter: I, size: &Size) -> Option<Vec2D<T>> {
let data: Vec<T> = iter.into_iter().collect();
- if size.width * size.height == data.len() {
+ if size.width as usize * size.height as usize == data.len() {
Some(Vec2D { data, size: *size })
} else {
None
@@ -160,7 +164,7 @@
#[test]
fn basics() {
- let mut v: Vec2D<u8> = Vec2D::new(Size::new(2, 3), 0xff);
+ let mut v: Vec2D<u8> = Vec2D::new(&Size::new(2, 3), 0xff);
assert_eq!(v.width(), 2);
assert_eq!(v.height(), 3);
@@ -173,7 +177,7 @@
assert_eq!(v[2][0], 0xff);
assert_eq!(v[2][1], 0);
- v.get_mut(2, 1).map(|v| *v = 1);
+ v.get_mut(2, 1).into_iter().for_each(|v| *v = 1);
assert_eq!(v[2][1], 1);
assert_eq!(v.get_mut(2, 2), None);