I think you can generate all the move steps first and then change the current point with the steps one by one in one single loop.
There are four kinds of steps -- (-1, 0), (1, 0), (0, 1) and (0, -1), corresponding to moving left, right, up and down. You can calculate how many steps are needed and which direction needs to be taken first based on the relative positions of the curr and end points and the moving_horizontal flag.
use std::iter::repeat;
struct Point {
x: usize,
y: usize,
}
fn main() {
const HEIGHT: usize = 25;
const WIDTH: usize = 80;
const LEFT: (i8, i8) = (-1, 0);
const RIGHT: (i8, i8) = (1, 0);
const UP: (i8, i8) = (0, 1);
const DOWN: (i8, i8) = (0, -1);
let grid: Vec<u8> = vec![0; WIDTH * HEIGHT];
let mut curr = Point {x: 6, y: 2 };
let end = Point {x: 3, y: 4 };
let (x_step, x_num) = if end.x > curr.x { (RIGHT, end.x - curr.x) }
else { (LEFT, curr.x - end.x) };
let (y_step, y_num) = if end.y > curr.y { (UP, end.y - curr.y) }
else { (DOWN, curr.y - end.y) };
let moving_horizontal = true;
let all_steps = if moving_horizontal {
repeat(x_step).take(x_num).chain(repeat(y_step).take(y_num))
} else {
repeat(y_step).take(y_num).chain(repeat(x_step).take(x_num))
};
println!("Start: (x:{}, y:{})", curr.x, curr.y);
println!("End: (x:{}, y:{})", end.x, end.y);
println!("Steps (Horizontal: {}):", moving_horizontal);
for (i, step) in all_steps.enumerate() {
// do stuff with this
grid[curr.x + curr.y * HEIGHT];
curr.x = match step.0 {
1 => curr.x + 1,
-1 => curr.x - 1,
_ => curr.x
};
curr.y = match step.1 {
1 => curr.y + 1,
-1 => curr.y -1,
_ => curr.y
};
println!("{} => (x:{}, y:{})", i, curr.x, curr.y);
}
}
Playground
The output when moving_horizontal is true:
Start: (x:6, y:2)
End: (x:3, y:4)
Steps (Horizontal: true):
0 => (x:5, y:2)
1 => (x:4, y:2)
2 => (x:3, y:2)
3 => (x:3, y:3)
4 => (x:3, y:4)
The output when moving_horizontal is false:
Start: (x:6, y:2)
End: (x:3, y:4)
Steps (Horizontal: false):
0 => (x:6, y:3)
1 => (x:6, y:4)
2 => (x:5, y:4)
3 => (x:4, y:4)
4 => (x:3, y:4)