例如:
如果向右移动,则可以向上,向右或向下移动,但不能向左移动。
有一个简单的方向指示枚举:
#[derive(Debug, PartialEq)]
enum Direction {
Up,
Right,
Down,
Left,
}
我会说这是完成任务的功能签名:
fn next_direction(current_dir: Direction) -> Direction
这是我当前的实现:
use rand::prelude::*;
fn next_direction(current_dir: Direction) -> Direction {
let mut rng = thread_rng();
// Possible next direction
let next_dir_iter = [
Direction::Up,
Direction::Down,
Direction::Left,
Direction::Right,
]
.iter()
.filter(|&dir| match (current_dir, dir) {
(Direction::Up, Direction::Down) => false,
(Direction::Down, Direction::Up) => false,
(Direction::Left, Direction::Right) => false,
(Direction::Right, Direction::Left) => false,
(_, _) => true,
});
// Choose one
let dir = next_dir_iter.choose(&mut rng).unwrap();
// Return Direction instead of &Direction
match dir {
Direction::Up => Direction::Up,
Direction::Down => Direction::Down,
Direction::Left => Direction::Left,
Direction::Right => Direction::Right,
}
}
可以用更清晰,更简单,更有效的方式编写此函数吗?
我会说可读性是一个加号,所以一个划线员或代码高尔夫实施不可能是最佳的。
我已经发现了一个相关的问题:如何从枚举中选择随机值?。
谢谢 =)
您可以手动编写每种情况的可能指示:
use rand::prelude::*;
use Direction::*;
#[derive(Debug, PartialEq, Copy, Clone)]
enum Direction {
Up,
Right,
Down,
Left,
}
impl Direction {
fn next_random(self) -> Self {
match self {
Up => [Up, Left, Right],
Down => [Down, Left, Right],
Left => [Up, Down, Left],
Right => [Up, Down, Right],
}
.choose(&mut thread_rng())
.copied()
.unwrap()
}
}
当然,如果您的枚举有很多变体,那么最好有一个更通用的解决方案:
impl Direction {
fn all() -> &'static [Self] {
&[Up, Down, Left, Right]
}
fn opposite(self) -> Self {
match self {
Up => Down,
Down => Up,
Left => Right,
Right => Left,
}
}
fn next_random(self) -> Self {
let next = Self::all()
.iter()
.filter(|&&d| d != self.opposite())
.choose(&mut thread_rng());
*next.unwrap()
}
}
请注意,如果您想要更好的性能或灵活性,则可以将随机数生成器作为参数传递:
fn next_random(self, rng: &mut impl Rng) -> Self {
let next = Self::all()
.iter()
.filter(|&&d| d != self.opposite())
.choose(rng);
*next.unwrap()
}
假定所有RNG都传递随机比特,并且该
choose()
方法将始终统一选择随机元素。传递RNG允许使用其他RNG,例如,较快的RNG(不是密码安全的)或具有某种已知随机状态的RNG,以便您可以重现结果。它还允许在该方法的许多调用之间重用RNG,因此您无需thread_rng()
每次都调用。@SvenMarnach您的评论值得在单独的问答中进行
我知道我的话题不多了。:)我只是不禁回复您关于非均匀分布的附带说明。