很长一段时间以来,我一直对“铁锈”感兴趣,我终于坐下来开始读“那本书”了。我还没有完成,所以可能有一些特性,我可以使用,但我不知道。
无论如何,这个程序的目的是生成一个迷宫(使用最简单的“随机DFS”算法)。
由于我的主要目标是练习语言,我试着使程序尽可能地“熟能生巧”。仍然困扰我的主要问题是有符号类型和无符号类型之间的所有类型转换。由于这是我的第一个锈蚀程序,我主要是寻找反馈,任何可能被认为是“坏代码”,或部分,可以改进的任何方式。
extern crate rand;
extern crate image;
use std::io::Write;
use rand::Rng;
#[derive(Clone, PartialEq)]
enum Cell {
Blocked,
Free,
}
fn make_odd(mut t: (usize, usize)) -> (usize, usize) {
let o = |v: &mut usize| if *v%2==0{*v+=1};
o(&mut t.0); o(&mut t.1); t
}
fn gen(s: (usize, usize)) -> Vec<Vec<Cell>> {
let mut t = vec![vec![Cell::Blocked; s.1]; s.0];
let mut stack = Vec::<(isize, isize)>::new();
let c = make_odd((s.0/2, s.1/2));
stack.push((c.0 as isize, c.1 as isize));
t[c.0][c.1] = Cell::Free;
let mut dirs: [(isize, isize); 4] = [(2, 0), (-2, 0), (0, 2), (0, -2)];
let mut rng = rand::thread_rng();
'o: while let Some(&(x, y)) = stack.last() {
rng.shuffle(&mut dirs);
for i in 0..4 {
let (dx, dy) = dirs[i];
let (nx, ny) = (x+dx, y+dy);
if nx < 0 || ny < 0 || nx >= (s.0 as isize) || ny >= (s.1 as isize) { continue; }
if t[nx as usize][ny as usize] != Cell::Free {
stack.push((nx, ny));
t[nx as usize][ny as usize] = Cell::Free;
t[(x+dx/2) as usize][(y+dy/2) as usize] = Cell::Free;
continue 'o;
}
}
stack.pop();
}
t[0][1] = Cell::Free;
t[s.0-1][s.1-2] = Cell::Free;
t
}
fn print_usage() -> ! {
let _ = writeln!(std::io::stderr(), "Usage: maze-gen width height [output.png]");
std::process::exit(1);
}
fn main() {
let args: Vec<_> = std::env::args().collect();
if args.len() < 3 { print_usage(); }
let mut nums = [0; 2];
for i in 0..2 {
match args[i+1].parse::<usize>() {
Err(_) => { print_usage(); },
Ok(v) => nums[i] = v,
}
}
let s0 = (nums[0], nums[1]);
let mut s = make_odd(s0);
if s.0 < 3 { s.0 = 3; }
if s.1 < 3 { s.1 = 3; }
if s != s0 {
let _ = writeln!(std::io::stderr(),
"Warning: Adjusting sizes to {} and {}!", s.0, s.1);
}
let m = gen(s);
let mut buf = image::ImageBuffer::new(s.0 as u32, s.1 as u32);
for (x,y,px) in buf.enumerate_pixels_mut() {
*px = image::Luma([
match m[x as usize][y as usize] {
Cell::Free => 255,
Cell::Blocked => 0,
}
]);
}
let filename = if args.len() >= 4 { args[3].as_str() } else { "out.png" };
let ref mut file = std::fs::File::create(&std::path::Path::new(filename)).unwrap();
image::ImageLuma8(buf).save(file, image::PNG).unwrap();
}示例输出:(它很小,您可能需要下载并放大以正确查看它。)

(不好意思语法不好,英语不是我的母语。)
发布于 2017-04-02 03:10:19
(usize, usize)是什么,都要做一个类型。至少,创建一个类型别名。map方法。stack,然后立即推送一个值。相反,只需使用vec!宏一次性创建它。dirs的类型dir中的元素数量,而且可能需要再次执行边界检查,只需直接在dirs上迭代即可。skip it以避免记住它在那里,然后在这里和那里添加数字来补偿。unwrap_or_else处理解析失败。enumerate避免再次索引args片。std::cmp::max为大小提供较低的值。expect。Vec::get代替检查大小,然后使用索引运算符(它再次检查大小)Path,只需传入&strexpect而不是unwrap。ImageBuffer::from_fn。请注意,这消除了使变量可变的需要。ref绑定中使用let。在右手边使用&更有习性。在这种情况下,&mut at call是比较惯用的。a + (-2)与a - (+2)相同。添加一个枚举来定义方向,一个方法将这些方向应用到一个点,在该方法中使用checked_add / checked_sub来处理以下/溢出,然后添加自己的“溢出”检查迷宫的大小。extern crate rand;
extern crate image;
use rand::Rng;
use std::cmp::max;
use std::io::Write;
#[derive(Clone, PartialEq)]
enum Cell {
Blocked,
Free,
}
#[derive(Debug, Copy, Clone)]
enum Direction {
Up,
Down,
Left,
Right,
}
#[derive(Debug, Copy, Clone, PartialEq)]
struct Point(usize, usize);
impl Point {
fn map<F>(self, mut f: F) -> Self
where F: FnMut(usize) -> usize
{
Point(f(self.0), f(self.1))
}
fn move_by(self, amount: usize, dir: Direction) -> Option<Self> {
use Direction::*;
match dir {
Left => self.0.checked_sub(amount).map(|x| Point(x, self.1)),
Right => self.0.checked_add(amount).map(|x| Point(x, self.1)),
Up => self.1.checked_sub(amount).map(|y| Point(self.0, y)),
Down => self.1.checked_add(amount).map(|y| Point(self.0, y)),
}
}
}
fn next_odd_number(n: usize) -> usize {
n + if n % 2 == 0 { 1 } else { 0 }
}
fn generate_maze(size: Point) -> Vec<Vec<Cell>> {
use Direction::*;
let center = size.map(|v| v / 2).map(next_odd_number);
let mut stack = vec![Point(center.0, center.1)];
let mut maze = vec![vec![Cell::Blocked; size.1]; size.0];
maze[center.0][center.1] = Cell::Free;
let mut dirs = [Left, Right, Up, Down];
let mut rng = rand::thread_rng();
let ensure_in_bounds = |z: Point| {
if z.0 >= size.0 || z.1 >= size.1 {
None
} else {
Some(z)
}
};
'next_odd_number: while let Some(&point) = stack.last() {
rng.shuffle(&mut dirs);
for &dir in &dirs {
let new_point = match point.move_by(2, dir).and_then(&ensure_in_bounds) {
Some(new_point) => new_point,
None => continue,
};
if maze[new_point.0][new_point.1] != Cell::Free {
stack.push(new_point);
maze[new_point.0][new_point.1] = Cell::Free;
let middle_point = point.move_by(1, dir)
.expect("Middle point cannot be out-of-bounds");
maze[middle_point.0][middle_point.1] = Cell::Free;
continue 'next_odd_number;
}
}
stack.pop();
}
maze[0][1] = Cell::Free;
maze[size.0 - 1][size.1 - 2] = Cell::Free;
maze
}
fn print_usage() -> ! {
writeln!(std::io::stderr(), "Usage: maze-gen width height [output.png]")
.expect("Unable to write to stderr");
std::process::exit(1);
}
fn main() {
let args: Vec<_> = std::env::args().skip(1).collect();
if args.len() < 2 {
print_usage();
}
let mut dimensions = [0; 2];
for (i, arg) in args.iter().enumerate() {
dimensions[i] = arg.parse().unwrap_or_else(|_| print_usage());
}
let requested_size = Point(dimensions[0], dimensions[1]);
let valid_size = requested_size.map(next_odd_number).map(|v| max(v, 3));
if valid_size != requested_size {
writeln!(std::io::stderr(),
"Warning: Adjusting sizes to {} and {}!",
valid_size.0,
valid_size.1)
.expect("Unable to write to stderr");
}
let maze = generate_maze(valid_size);
let buf = image::ImageBuffer::from_fn(valid_size.0 as u32, valid_size.1 as u32, |x, y| {
let luma = match maze[x as usize][y as usize] {
Cell::Free => 255,
Cell::Blocked => 0,
};
image::Luma([luma])
});
let filename = args.get(2).map(String::as_str).unwrap_or("out.png");
let mut file = std::fs::File::create(filename).expect("Couldn't open the file");
image::ImageLuma8(buf).save(&mut file, image::PNG).expect("Coulding write the file");
}接下来,我可能会研究如何为迷宫实现一个平面存储,这个存储可以由Point直接索引。这将允许这一变化:
-maze[middle_point.0][middle_point.1] = Cell::Free;
+maze[middle_point] = Cell::Free;老实说,我非常不喜欢标签循环的用法。根据我的经验,我认为我从来不需要它们,它们是锈菌中最稀有的建筑之一。我可能会花很多时间(比我已经花的多.)试图用不同的方式重写它。
https://codereview.stackexchange.com/questions/159565
复制相似问题