I'm making Tic-tac-toe in Rust. I want to count the amount of cells in a line, when the player is moving. Like -- x --. So I call count_result two times with the same dx and dy (that's why I pass dx and dy by reference). But here's the problem. My linter in IntelliJ IDEA complains that I use moved value. The compiler compiles without any warnings. What is the problem? Can you help me?
IntelliJ IDEA screenshot
Just to clarify - game_data.board is [[Option<Cell>; 3]; 3]
struct Data {
board: [[Option<Cell>; 3]; 3],
}
fn count_result(game_data: &Data, point: &Point, cell: &Cell, dx: &isize, dy: &isize) -> isize {
let mut count: isize = 0;
let point = (*point).clone();
let mut x = point.x;
let mut y = point.y;
while (x + dx < 3 && x + dx >= 0) && (y + dy >= 0 && y + dy < 3) {
x += 1;
y += 1;
if game_data.board[x as usize][y as usize] == Some(*cell) {
count += 1;
} else {
break;
}
}
count
}
Here is another example of the same problem.
game_data: &mut Data
IntelliJ IDEA screenshot
This is just a linter indexing invalid state. Just invalidate caches and you'll be fine.
Related
I'm writing a simple insert sort. Here are the relevant codes.
fn main() {
let mut sort_vec = vec![5,2,4,6,1,3];
for j in 1..sort_vec.len() {
let key = sort_vec[j];
let mut i = j - 1;
while i > 0 && sort_vec[i] > key {
sort_vec[i+1] = sort_vec[i];
i = i - 1;
}
sort_vec[i+1] = key;
}
println!("{:?}",sort_vec);
}
It's input is [5, 1, 2, 3, 4, 6].
The problem was when while i > 0 becomes while i >= 0 or while i > -1,it won't work.
So is there a problem comparing i32 with usize? I tried some methods and couldn't succeed. So how should I handle it? Be deeply grateful!
If you change while i > 0 to while i >= 0 the compiler gives you a warning:
warning: comparison is useless due to type limits
--> src\main.rs:9:15
|
9 | while i >= 0 && sort_vec[i] > key {
| ^^^^^^
|
= note: `#[warn(unused_comparisons)]` on by default
and the code panicks at runtime:
thread 'main' panicked at 'attempt to subtract with overflow', src\main.rs:11:17
The problem is that if i goes down to 0 and you try to subtract 1, the integer i overflows because its type is usize which has to be non-negative.
Because usize can't be negative your comparison i >= 0 is always true (that's the compiler warning).
I would recommend changing the logic a bit: Don't compare the second last element with the next one but compare the last element with the previous one.
So you have to start not at j - 1 but at j, and replace because of that in the following lines i in every index with i - 1:
sort_vec[i] -> sort_vec[i - 1]
sort_vec[i + 1] -> sort_vec[i]
working code:
fn main() {
let mut sort_vec = vec![5, 2, 4, 6, 1, 3];
for j in 1..sort_vec.len() {
let key = sort_vec[j];
let mut i = j;
while i > 0 && sort_vec[i - 1] > key {
sort_vec[i] = sort_vec[i - 1];
i = i - 1;
}
sort_vec[i] = key;
}
println!("{:?}", sort_vec);
}
Now you can see the unnecessary assignment let mut i = j. You could change the head of the for-loop to for mut j in ... to remove that and replace all i with j.
fn main() {
let mut sort_vec = vec![5, 2, 4, 6, 1, 3];
for mut j in 1..sort_vec.len() {
let key = sort_vec[j];
while j > 0 && sort_vec[j - 1] > key {
sort_vec[j] = sort_vec[j - 1];
j = j - 1;
}
sort_vec[j] = key;
}
println!("{:?}", sort_vec);
}
Here there's a nice trick (note that in Rust, wrapping arithmetic has to be explicit or it will panic in debug mode):
while i < j && sort_vec[i] > key {
sort_vec[i + 1] = sort_vec[i];
i = i.wrapping_sub(1);
}
sort_vec[i.wrapping_add(1)] = key;
Playground.
The idea is that we let i underflow then overflow back - but when it'll underflow it will be no longer less than j, so the loop will stop.
i has type usize, so it can never be less than 0. Therefore i >= 0 or i >= -1 are always true. One way to fix your issue is to use a for loop with a reversed range:
fn main() {
let mut sort_vec = vec![5, 2, 4, 6, 1, 3];
for j in 1..sort_vec.len() {
for i in (0..j).rev() {
if sort_vec[i+1] < sort_vec[i] {
sort_vec.swap (i, i+1);
} else {
break;
}
}
}
println!("{:?}", sort_vec);
}
Playground
I'm currently reading the book Computer graphics from scratch and can't get the example from the first chapter about a raytracer quite right in my rust project.
I'm using the image crate to render the picture. I convert the coordinates from renderer (x and y, origin upper left corner) to to my viewport (origin in the middle, with z on 10).
fn canvas_to_viewport(x: u32, y: u32, scene: &Scene) -> Point {
let x: f64 = x as f64 - (scene.width as f64 / 2.) ;
let y: f64 = y as f64 - (scene.width as f64 / 2.) ;
// x * viewport width / camera width
// y * viewport height / camera height
Point {
x: x * 1.,
y: y * 1.,
z: 10.
}
}
I then get the color of the pixel by my trace_ray function which looks for the closest intersection with a sphere with the helper function intersect_ray_sphere.
fn trace_ray(camera: Point, viewport: Point, t_min: f64, _t_max: f64, spheres: &Vec<Sphere>) -> Color {
let mut closest_t = 1000.;
let mut closest_sphere_color = Color (255,255,255);
for sphere in spheres {
let (t1, t2) = intersect_ray_sphere(camera, viewport, &sphere);
if t1 > t_min && t1 < closest_t {
closest_t = t1;
closest_sphere_color = sphere.color;
};
if t2 > t_min && t2 < closest_t {
closest_t = t2;
closest_sphere_color = sphere.color;
};
}
closest_sphere_color
}
fn intersect_ray_sphere(o: Point, d: Point, sphere: &Sphere) -> (f64, f64) {
let r = sphere.radius;
let co = Point {
x: o.x - sphere.center.x,
y: o.y - sphere.center.y,
z: o.z - sphere.center.z
};
let a = dot_product(&d, &d);
let b = 2. * dot_product(&co, &d);
let c = dot_product(&co, &co) - r*r;
let discriminant = b*b - 4.*a*c;
if discriminant < 0. {
return (1000., 1000.);
};
let t1 = (-b + discriminant.sqrt()) / (2.*a);
let t2 = (-b - discriminant.sqrt()) / (2.*a);
return (t1, t2)
}
The spheres farther from the middle are warped as you can see here:
I have played with pretty much all parameters but can't seem to figure it out. Every help would be much appreciated.
I think you are missing checks for t1 < t_max and t2 < t_max, though I suppose it doesn't matter much if your t_max is infinite.
Also, in case of a negative discriminant, you can actually return inf if you like, using f64::INFINITY; using 1000 is likely the culprit for the warping effect you are seeing.
Trying to convert this for loop from c++ to rust and i'm having a hard time figuring it out as I'm very new to Rust syntax.
double sinError = 0;
for (float x = -10 * M_PI; x < 10 * M_PI; x += M_PI / 300) {
double approxResult = sin_approx(x);
double libmResult = sinf(x);
sinError = MAX(sinError, fabs(approxResult - libmResult));
}
Iterate over integers
As #trentcl already pointed out, it's usually better to iterate over integers instead of floats, to prevent numerical errors from adding up:
use std::f32::consts::PI;
let mut sin_error = 0.0;
for x in (-3000..3000).map(|i| (i as f32) * PI / 300.0) {
sin_error = todo!();
}
Just replace todo!() with the code that computes the next sin_error.
A more functional way
use std::f32::consts::PI;
let sin_error = (-3000..3000)
.map(|i| (i as f32) * PI / 300.0)
.fold(0.0, |sin_error, x| todo!());
In case you don't care about numerical errors, or want to iterate over something else, here are some other options:
Use a while loop
It's not as nice, but does the job!
use std::f32::consts::PI;
let mut sin_error = 0.0;
let mut x = -10.0 * PI;
while (x < 10.0 * PI) {
sin_error = todo!();
x += PI / 300.0;
}
Create your iterator with successors()
The successors() function creates a new iterator where each successive item is computed based on the preceding one:
use std::f32::consts::PI;
use std::iter::successors;
let mut sin_error = 0.0;
let iter = successors(Some(-10.0 * PI), |x| Some(x + PI / 300.0));
for x in iter.take_while(|&x| x < 10.0 * PI) {
sin_error = todo!();
}
A more functional way
use std::f32::consts::PI;
use std::iter::successors;
let sin_error = successors(Some(-10.0 * PI), |x| Some(x + PI / 300.0))
.take_while(|&x| x < 10.0 * PI)
.fold(0.0, |sin_error, x| todo!());
In the C family of languages, I can do this on one line:
for(int i = lo, int j = mid+1; i <= mid && j <= hi; i++, j++){
...
}
But in Rust... I can only write it like this:
for i in lo..mid+1 {
let mut j = mid+1;
if j <= hi {
break;
}
...
j += 1;
}
Is there's a more efficient way to implement this?
Using an iterator works for above, but using an iterator makes some occasions like using arithmetic troublesome, such as
for (int i = 0; i < n; i ++) {
if (a[i] == ...) {
i += 5;
}
}
In Rust, this does not work. The variable i will not be incremented by 5, but by 1 instead:
for i in 0..n {
if a[i] == ... {
i += 5;
}
}
You can create two parallel range iterators, zip them, then iterate though the combination:
fn main() {
let values = [10, 20, 30, 40, 50, 60, 70, 80, 90];
let lo = 2;
let mid = 5;
let hi = 7;
let early_indexes = lo..(mid + 1);
let late_indexes = (mid + 1)..(hi + 1);
for (i, j) in early_indexes.zip(late_indexes) {
println!("{}, {}", i, j);
println!("{} - {}", values[i], values[j]);
}
}
Someday, inclusive ranges will be stabilized, and you should be able to something like this (depending on the eventual syntax):
let early_indexes = lo...mid;
let late_indexes = (mid + 1)...hi;
for (i, j) in early_indexes.zip(late_indexes) {
println!("{}, {}", i, j);
println!("{} - {}", values[i], values[j]);
}
If you are actually iterating though a slice as I've shown for my example, you can also just combine the two iterators directly and ignore the index:
let early_values = values[lo..(mid + 1)].iter();
let late_values = values[(mid + 1)..(hi + 1)].iter();
for (i, j) in early_values.zip(late_values) {
println!("{}, {}", i, j);
}
The variable i will not be incremented by 5, but by 1 instead.
Yes, incrementing by a step is annoying, and some day it will also be stabilized. In the meantime:
What is a stable way to iterate on a range with custom step?
How do I iterate over a range with a custom step?
If you need full control, you can always use while or loop:
let mut i = 0;
while i < n {
if a[i] == ... {
i += 5;
}
i += 1;
}
I've been trying to rewrite the code below for summing floating point numbers while minimizing the rounding errors, but I found it pretty hard to do in Rust. Any suggestions would be greatly appreciated. I attach my non-working Rust attempt
def msum(iterable):
"Full precision summation using multiple floats for intermediate values"
# Rounded x+y stored in hi with the round-off stored in lo. Together
# hi+lo are exactly equal to x+y. The inner loop applies hi/lo summation
# to each partial so that the list of partial sums remains exact.
# Depends on IEEE-754 arithmetic guarantees. See proof of correctness at:
#www-2.cs.cmu.edu/afs/cs/project/quake/public/papers/robust-arithmetic.ps
partials = [] # sorted, non-overlapping partial sums
for x in iterable:
i = 0
for y in partials:
if abs(x) < abs(y):
x, y = y, x
hi = x + y
lo = y - (hi - x)
if lo:
partials[i] = lo
i += 1
x = hi
partials[i:] = [x]
return sum(partials, 0.0)
The code below is what I have in Rust so far, but it's not working yet
fn inexact_sum(v: &Vec<f64>) -> f64 {
let mut partials: Vec<f64> = vec![];
for x in v {
let mut i: usize = 0;
let mut hi: f64;
let mut lo: f64;
for y in partials.clone().iter() {
hi = x + y;
lo = if x.abs() < y.abs() {
y - (hi - x)
} else {
x - (hi - y)
};
if lo != 0.0_f64 {
partials[i] = lo;
i += 1;
}
let x = hi;
println!("x = {}, y = {}", x, y);
}
partials.truncate(i);
partials.push(hi);
}
partials.iter().fold(0.0_f64, |a, b| a + b)
}
EDIT: Thinking about it a bit more, indeed, the error the compiler gave me error: use of possibly uninitialized variable: `hi` is indeed useful. I should have paid more attention to it. The point is that the first time the loop does not execute at all, so hi does not get initialized. So if I change partials.push(hi); to partials.push(*x); the code compiles and runs but it does not give the right answer.
Is this what you are looking for? I think you did not mean to clone the partials array but found that you needed to in order to satisfy the borrow checker; if you try to use the code:
for y in partials.iter() {
...
partials[i] = lo;
The borrow checker will complain:
<anon>:13:17: 13:25 error: cannot borrow `partials` as mutable because it is also borrowed as immutable [E0502]
I got around this by using an index into the array instead:
for j in 0..partials.len() {
let mut y = partials[j];
Then you are not cloning the whole array of partials each time around the outer loop! Since the partials array can be modified whilst iterating through it, taking a clone first means you will end up with the old value of y instead of the new one if it has been modified.
use std::mem;
fn msum(v: &[f64]) -> f64 {
let mut partials: Vec<f64> = vec![];
for x in v {
let mut x = *x;
let mut i = 0;
for j in 0..partials.len() {
let mut y = partials[j];
if x.abs() < y.abs() { mem::swap(&mut x, &mut y) }
let hi = x + y;
let lo = y - (hi - x);
if lo != 0.0 {
partials[i] = lo;
i += 1;
}
x = hi;
}
partials.truncate(i);
partials.push(x);
}
partials.iter().fold(0., |a, b| a + b)
}
fn main() {
let v = vec![1.234, 1e16, 1.234, -1e16];
println!("{}",msum(&v));
}
Playpen