How generate Point struct in range on Rust - rust

I can't understand how to write trait for generating Point in some range.
I try to use rand::Rng for generate random values for Point struct (for coordinates in minesweeper).
I use this site Generate Random Values - Rust Cookbook
And it fine worked for ranges for simple data types. Also, worked examples with Point.
Could someone provide example of code and some explanation about traits for Uniform for Point struct?
use rand::Rng;
use rand::distributions::{Distribution, Uniform};
fn main() {
let width: u8 = 15; let height: u8 = 15;
let mine_count: u8 = 40;
let mut rng = rand::thread_rng();
let ranger = Uniform::from(0..width);
for _i in 0..=mine_count{
let rand_point: Point = ranger.sample(&mut rng);
println!("Random Point: {:?}", rand_point);
}
}
#[derive(Debug)]
struct Point {
x: u8,
y: u8,
}
impl Distribution<Point> for Uniform<Point> {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Point {
let (rand_x, rand_y) = rng.gen();
Point {
x: rand_x,
y: rand_y,
}
}
}
Compiling my-project v0.1.0 (/home/runner/SyntaxTest)
error[E0277]: the trait bound `Point: SampleUniform` is not satisfied
--> src/main.rs:56:30
|
56 | impl Distribution<Point> for Uniform<Point> {
| ^^^^^^^^^^^^^^ the trait `SampleUniform` is not implemented for `Point`
note: required by a bound in `Uniform`
--> /home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/rand-0.8.5/src/distributions/uniform.rs:179:23
|
179 | pub struct Uniform<X: SampleUniform>(X::Sampler);
| ^^^^^^^^^^^^^ required by this bound in `Uniform`
error[E0277]: the trait bound `Point: SampleUniform` is not satisfied
--> src/main.rs:57:30
|
57 | fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Point {
| ^^^^^ the trait `SampleUniform` is not implemented for `Point`
note: required by a bound in `Uniform`
--> /home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/rand-0.8.5/src/distributions/uniform.rs:179:23
|
179 | pub struct Uniform<X: SampleUniform>(X::Sampler);
| ^^^^^^^^^^^^^ required by this bound in `Uniform`

The problem here is that your code has no concept of what is a distribution of Points.
If you look at the signature of the Uniform struct, its generic has to implement the SampleUniform trait. According to the docs, the SampleUniform trait defines the Sampler type that should be used in order to generate random distributions.
So, when you write this:
impl Distribution<Point> for Uniform<Point> {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Point {
let (rand_x, rand_y) = rng.gen();
Point {
x: rand_x,
y: rand_y,
}
}
}
When you call Uniform::from(0..width), you are also defining a sampler for u8 values, which is not what you want in the end. What you want (judging by your code) is to generate a random distribution of points between a min, say Point { x: 0, y: 0 }, and a maximum value, which could be another point, but it could also be defined as a range, a delta, an area, etc. The idea is to be able to write something like this:
let ranger = Uniform::from(
Point::default()..Point {
x: width,
y: height,
},
);
Where Point::default() is the origin.
To solve your problem you need to be able to tell the rand crate what exactlyis it that you mean when you ask for that distribution of Points.
To keep your code as is, you could rewrite it like this:
use rand::distributions::uniform::{SampleUniform, UniformInt, UniformSampler};
use rand::distributions::{Distribution, Uniform};
use rand::Rng;
fn main() {
let width: u8 = 4;
let height: u8 = 5;
let mine_count: u8 = 40;
let mut rng = rand::thread_rng();
let ranger = Uniform::from(
Point::default()..Point {
x: width,
y: height,
},
);
for _i in 0..=mine_count {
let rand_point: Point = ranger.sample(&mut rng);
println!("Random Point: {:?}", rand_point);
}
}
#[derive(Clone, Copy, Debug, Default)]
struct Point {
x: u8,
y: u8,
}
struct UniformPoint {
x: UniformInt<u8>,
y: UniformInt<u8>,
}
impl SampleUniform for Point {
type Sampler = UniformPoint;
}
impl UniformSampler for UniformPoint {
type X = Point;
fn new<B1, B2>(low: B1, high: B2) -> Self
where
B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
{
let low = *low.borrow();
let high = *high.borrow();
UniformPoint {
x: UniformInt::<u8>::new_inclusive(low.x, high.x - 1),
y: UniformInt::<u8>::new_inclusive(low.y, high.y - 1),
}
}
fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self
where
B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
{
let low = *low.borrow();
let high = *high.borrow();
UniformPoint {
x: UniformInt::<u8>::new_inclusive(low.x, high.x),
y: UniformInt::<u8>::new_inclusive(low.y, high.y),
}
}
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
Point {
x: self.x.sample(rng),
y: self.y.sample(rng),
}
}
}
impl Distribution<Point> for Point {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Point {
let (rand_x, rand_y) = rng.gen();
Point {
x: rand_x,
y: rand_y,
}
}
}
Notice that you don't need to implement the Distribution trait any longer, since Uniform::from only requires that your struct implements SampleUniform.
The trick here is that each field in Point needs to be generated from a distribution of values. Since you can use UniformInt::<u8>... to generate those distributions, then all you need is an accessory struct that can as a placeholders for those distributions.
Notice that now, when you call ranger.sample() you're actually making two calls. One to x.sample and one to y.sample.
This results in a neat API, where you can still use the ranger as you did before without any modifications.
Another solution would be to keep your u8 distribution and create your random points by doing:
for _i in 0..=mine_count {
let rand_point = Point {
x: ranger.sample(&mut rng),
y: ranger.sample(&mut rng),
}
println!("Random Point: {:?}", rand_point);
}
This way you don't need to implement anything, but it is also less fun.
Hope this helps.

You want to implement Distribution<Point> for Uniform<u8>, not Uniform<Point>:
use rand::Rng;
use rand::distributions::{Distribution, Uniform};
fn main() {
let width: u8 = 15; let height: u8 = 15;
let mine_count: u8 = 40;
let mut rng = rand::thread_rng();
let ranger = Uniform::from(0..width);
for _i in 0..=mine_count{
let rand_point: Point = ranger.sample(&mut rng);
println!("Random Point: {:?}", rand_point);
}
}
#[derive(Debug)]
struct Point {
x: u8,
y: u8,
}
impl Distribution<Point> for Uniform<u8> {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Point {
let (rand_x, rand_y) = rng.gen();
Point {
x: rand_x,
y: rand_y,
}
}
}
Playground

Related

Error type `bool` cannot be dereferenced in rust to Vector of structs in Rust lang

I'm making a maze algorithm using rust and wasm and I have two structs. A maze, and maze has an Vec of a Block struct.
Like this:
pub struct Maze {
pub cols: usize,
pub rows: usize,
pub blocks: Vec<Block>,
pub stack: Vec<usize>,
}
impl Maze {
pub fn new(cols: usize, rows: usize) -> Maze {
let mut maze = Maze {
cols,
rows,
blocks: vec![],
};
for y in 0..rows {
for x in 0..cols {
maze.blocks.push(Block::new(x, y))
}
}
maze
}
And the struct Block has an attribute called visited.
I want in a struct function of Maze change this value
// in Maze struct impl
pub fn run(&mut self) {
let current_index = self.get_current_index();
let mut current_block = &mut &self.blocks[current_index];
// .....
*current_block.visited = true;
In the last line occur an error:
error[E0614]: type `bool` cannot be dereferenced
--> src/maze.rs:119:17
|
119 | *current_block.visited = true;
| ^^^^^^^^^^^^^^^^^^^^^^
How can I do to change this value?
This is my implementation of Block
pub struct Block {
pub x: usize,
pub y: usize,
pub visited: bool,
}
impl Block {
pub fn new(x: usize, y: usize) -> Block {
Block {
x,
y,
visited: false,
}
}
How can I do to change the visited value from Maze.run?
There are two problems, one which is the error you see and one which you will encounter next. The problem with
*current_block.visited = true;
is that the precedence of * is lower than ., so you've written code equivalent to)
*(current_block.visited) = true;
which does not compile because the type of the visited field is bool, which indeed cannot be dereferenced. You could write
(*current_block).visited = true;
and that would work, but it's also unnecessary, because in Rust the . operator looks through references, so you only need
current_block.visited = true;
to assign to the visited field of an &mut Block.
The second problem is that you have an extra & here:
let mut current_block = &mut &self.blocks[current_index];
This means current_block is of type &mut &Block. You can never mutate through an & reference, so you need to remove the &, and it is not needed anyway:
let mut current_block = &mut self.blocks[current_index];

Return a Formatted String in Rust

I'd like to create a function that takes an x and y coordinate values and returns a string of the format (x,y):
pub struct Coord {
x: i32,
y: i32,
}
fn main() {
let my_coord = Coord {
x: 10,
y: 12
};
let my_string = coords(my_coord.x, my_coord.y);
fn coords(x: i32, y: i32) -> &str{
let l = vec!["(", x.to_string(), ",", y.to_string(), ")"];
let j = l.join("");
println!("{}", j);
return &j
}
}
This gives me the error:
|
14 | fn coords(x: i32, y: i32) -> &str {
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
help: consider using the `'static` lifetime
|
Adding the 'static lifetime seems to cause a host of other problems with this function? How can I fix this?
The more idiomatic approach would be to implement the Display trait for your type Coord which would allow you to call to_string() on it directly, and also would allow you to use it in the println! macro directly. Example:
use std::fmt::{Display, Formatter, Result};
pub struct Coord {
x: i32,
y: i32,
}
impl Display for Coord {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f, "({}, {})", self.x, self.y)
}
}
fn main() {
let my_coord = Coord { x: 10, y: 12 };
// create string by calling to_string()
let my_string = my_coord.to_string();
println!("{}", my_string); // prints "(10, 12)"
// can now also directly pass to println! macro
println!("{}", my_coord); // prints "(10, 12)"
}
playground
What you are trying to do is not possible. The String you are creating is local to the function and you are trying to return a reference to it.
j will be dropped at the end of the function, so you can't return a reference to it.
You will have to return a String:
fn coords(x: i32, y: i32) -> String {
let l = vec![
"(".into(),
x.to_string(),
",".into(),
y.to_string(),
")".into(),
];
let j = l.join("");
println!("{}", j);
return j;
}
Playground
A better way to do the same:
fn coords(x: i32, y: i32) -> String {
let x = format!("({},{})", x, y);
println!("{}", x);
return x;
}
Playground
this ended up working for me:
pub struct Coord{
x: i32,
y: i32,
}
fn main(){
let my_coord = Coord{
x: 10,
y: 12
};
let my_string = coords(my_coord.x, my_coord.y);
fn coords(x: i32, y: i32) -> String{
let myx = x.to_string();
let myy = y.to_string();
let l = vec!["(", &myx, ",", &myy, ")"];
let j = l.join("");
return j;
}
}

How to push a item from a function parameter to a vector from a function parameter - Different lifetime issue

I need to push an item to a vector. But both of item and vector are function parameters.
Simple code to reproduce:-
struct Point {
x: i32,
y: i32
}
fn main(){
let points: Vec<&Point> = vec!();
let start_point = Point {x: 1, y:2};
fn fill_points<F>(points: &mut Vec<&F>, point: &F ){
// Some conditions and loops
points.push(point);
}
fill_points(&mut points, & start_point);
}
Error:-
|
13 | fn fill_points<F>(points: &mut Vec<&F>, point: &F ){
| -- -- these two types are declared with different lifetimes...
14 | // Some conditions
15 | points.push(point);
| ^^^^^ ...but data from `point` flows into `points` here
Playground URL:- https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e1f2d738a22795ae11aab01ad8d00d96
You need to add a lifetime parameter:
struct Point {
x: i32,
y: i32,
}
fn main() {
let start_point = Point { x: 1, y: 2 };
let mut points: Vec<&Point> = vec![];
fn fill_points<'a, F>(points: &mut Vec<&'a F>, point: &'a F) {
// Some conditions
points.push(point);
}
fill_points(&mut points, &start_point);
}
(code simplified based the comment from #Stargateur)

Temporary value does not live long enough

I'm having trouble with this code. I have no idea why it errors.
It's supposed to take camera input and then put that inside of a buffer struct, contained inside the putter struct.
extern crate rscam;
// use std::fs::File;
// use std::io::prelude::*;
const WIDTH: usize = 1280;
const HEIGHT: usize = 720;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Pyxel {
r: u8,
g: u8,
b: u8,
}
impl Pyxel {
fn new() -> Pyxel {
Pyxel { r: 0, g: 0, b: 0 }
}
}
#[repr(transparent)]
struct Buffer {
pyxels: [[Pyxel; WIDTH]; HEIGHT],
}
// impl Buffer {
// fn new(s: [[Pyxel; WIDTH]; HEIGHT]) -> Buffer {
// Buffer {
// pyxels: s,
// }
// }
// }
struct Putter {
x: usize,
y: usize,
buffer: &'static mut Buffer,
}
impl Putter {
fn put_pyxel(&mut self, r: u8, g: u8, b: u8) {
if self.x >= WIDTH {
self.move_down();
}
let col = self.x;
let row = self.y;
self.buffer.pyxels[row][col] = Pyxel { r: r, g: g, b: b };
self.x += 1;
}
fn move_down(&mut self) {
self.y += 1;
}
fn new() -> Putter {
Putter {
x: 0,
y: 0,
buffer: &mut Buffer {
pyxels: [[Pyxel::new(); WIDTH]; HEIGHT],
},
}
}
}
fn main() {
let mut camera = rscam::new("/dev/video0").unwrap();
camera
.start(&rscam::Config {
interval: (1, 30),
resolution: (1280, 720),
format: b"RGB3",
..Default::default()
})
.unwrap();
let frame = camera.capture().unwrap();
let mut putter = Putter::new();
}
It errors:
error[E0597]: borrowed value does not live long enough
--> src/main.rs:65:20
|
57 | buffer: &mut Buffer {
| __________________________^
58 | | pyxels: [[Pyxel::new(); WIDTH]; HEIGHT],
59 | | },
| |_____________^ temporary value does not live long enough
60 | }
61 | }
| - temporary value only lives until here
|
= note: borrowed value must be valid for the static lifetime..
How do I use the buffer inside of the putter (structs)?
For the most part, I understand what this errors means, not how it works. I just need a workaround or a solution. Any help is appreciated. I could have written this better but im tired.
This is more or less logical error for me. You should carefully read about Rust ownership.
Consider thinking about how would your code work.
struct Putter {
x: usize,
y: usize,
buffer: &'static mut Buffer,
}
Buffer is a reference which you have lifetime equal to the lifetime of the program,
'static tells compiler that. Error message is pretty clear, you're creating temporary value in place and borrowing it. It will be destroyed right after exiting scope, so your reference will be pointing to invalid memory. Dangling references are prohibited in Rust. In language like C++ this example will compile fine, but will result in run-time error.
To fix this issue buffer should own value and struct design should be rethought while keeping attention to lifetimes.
struct Putter {
x: usize,
y: usize,
buffer: Buffer,
}

How to satisfy the Iterator trait bound in order to use Rayon here?

I'm attempting to parallelise the Ramer–Douglas-Peucker line simplification algorithm by using Rayon's par_iter instead of iter:
extern crate num_traits;
use num_traits::{Float, ToPrimitive};
extern crate rayon;
use self::rayon::prelude::*;
#[derive(PartialEq, Clone, Copy, Debug)]
pub struct Coordinate<T>
where T: Float
{
pub x: T,
pub y: T,
}
#[derive(PartialEq, Clone, Copy, Debug)]
pub struct Point<T>(pub Coordinate<T>) where T: Float;
impl<T> Point<T>
where T: Float + ToPrimitive
{
pub fn new(x: T, y: T) -> Point<T> {
Point(Coordinate { x: x, y: y })
}
pub fn x(&self) -> T {
self.0.x
}
pub fn y(&self) -> T {
self.0.y
}
}
unsafe impl<T> Send for Point<T> where T: Float {}
unsafe impl<T> Sync for Point<T> where T: Float {}
fn distance<T>(a: &Point<T>, p: &Point<T>) -> T
where T: Float
{
let (dx, dy) = (a.x() - p.x(), a.y() - p.y());
dx.hypot(dy)
}
// perpendicular distance from a point to a line
fn point_line_distance<T>(point: &Point<T>, start: &Point<T>, end: &Point<T>) -> T
where T: Float
{
if start == end {
distance(point, start)
} else {
let numerator = ((end.x() - start.x()) * (start.y() - point.y()) -
(start.x() - point.x()) * (end.y() - start.y()))
.abs();
let denominator = distance(start, end);
numerator / denominator
}
}
// Ramer–Douglas-Peucker line simplification algorithm
fn rdp<T>(points: &[Point<T>], epsilon: &T) -> Vec<Point<T>>
where T: Float + Send + Sync
{
if points.is_empty() {
return points.to_vec();
}
let mut dmax = T::zero();
let mut index: usize = 0;
let mut distance: T;
for (i, _) in points.par_iter().enumerate().take(points.len() - 1).skip(1) {
distance = point_line_distance(&points[i], &points[0], &*points.last().unwrap());
if distance > dmax {
index = i;
dmax = distance;
}
}
if dmax > *epsilon {
let mut intermediate = rdp(&points[..index + 1], &*epsilon);
intermediate.pop();
intermediate.extend_from_slice(&rdp(&points[index..], &*epsilon));
intermediate
} else {
vec![*points.first().unwrap(), *points.last().unwrap()]
}
}
#[cfg(test)]
mod test {
use super::{Point};
use super::{rdp};
#[test]
fn rdp_test() {
let mut vec = Vec::new();
vec.push(Point::new(0.0, 0.0));
vec.push(Point::new(5.0, 4.0));
vec.push(Point::new(11.0, 5.5));
vec.push(Point::new(17.3, 3.2));
vec.push(Point::new(27.8, 0.1));
let mut compare = Vec::new();
compare.push(Point::new(0.0, 0.0));
compare.push(Point::new(5.0, 4.0));
compare.push(Point::new(11.0, 5.5));
compare.push(Point::new(27.8, 0.1));
let simplified = rdp(&vec, &1.0);
assert_eq!(simplified, compare);
}
}
I've impld Send and Sync for Point<T>, but when I switch to par_iter, I get the following error:
error[E0277]: the trait bound rayon::par_iter::skip::Skip<rayon::par_iter::take::Take<rayon::par_iter::enumerate::Enumerate<rayon::par_iter::slice::SliceIter<'_, Point<T>>>>>: std::iter::Iterator is not satisfied
--> lib.rs:107:5
= note: rayon::par_iter::skip::Skip<rayon::par_iter::take::Take<rayon::par_iter::enumerate::Enumerate<rayon::par_iter::slice::SliceIter<'_, Point<T>>>>> is not an iterator; maybe try calling .iter() or a similar method
= note: required by std::iter::IntoIterator::into_iter
I don't understand what it's asking for. Is the problem that I'm operating on a tuple?
Rayon's parallel iterators implement ParallelIterator, not Iterator. In particular, this means you cannot just put a par_iter() in a for-loop header and expect it to suddenly be parallel. for is sequential.
Since your original code isn't written in terms of iterator functions, but rather as for loops, you can't parallelize it simply with the switch to par_iter(), but have to actually redesign the code.
In particular, the failing part of the code seems to be implementing the max_by_key function.

Resources