use grid::{GridCoord, GridPoint3, Dir};
use super::transform::*;
use super::turn::turn_around_and_face_neighbor;
use super::util::*;
pub fn step_forward_and_face_neighbor(
pos: &mut GridPoint3,
dir: &mut Dir,
resolution: [GridCoord; 2],
last_turn_bias: &mut super::TurnDir,
) -> Result<(), ()> {
move_forward(pos, dir, resolution)?;
if is_pentagon(pos, resolution) {
*last_turn_bias = last_turn_bias.opposite();
last_turn_bias.apply_one_unit(dir);
}
Ok(())
}
pub fn step_backward_and_face_neighbor(
pos: &mut GridPoint3,
dir: &mut Dir,
resolution: [GridCoord; 2],
last_turn_bias: &mut super::TurnDir,
) -> Result<(), ()> {
turn_around_and_face_neighbor(pos, dir, resolution, *last_turn_bias);
if is_pentagon(pos, resolution) {
*last_turn_bias = last_turn_bias.opposite();
}
step_forward_and_face_neighbor(pos, dir, resolution, last_turn_bias)?;
turn_around_and_face_neighbor(pos, dir, resolution, *last_turn_bias);
if is_pentagon(pos, resolution) {
*last_turn_bias = last_turn_bias.opposite();
}
Ok(())
}
pub fn move_forward(
pos: &mut GridPoint3,
dir: &mut Dir,
resolution: [GridCoord; 2],
) -> Result<(), ()> {
debug_assert_pos_within_root(pos, resolution);
if !dir.points_at_hex_edge() {
return Err(());
}
*pos = adjacent_pos_in_dir(*pos, *dir)?;
debug_assert_pos_within_root(pos, resolution);
maybe_rebase_on_adjacent_root_following_movement(pos, dir, resolution);
Ok(())
}
fn maybe_rebase_on_adjacent_root_following_movement(
pos: &mut GridPoint3,
dir: &mut Dir,
resolution: [GridCoord; 2],
) {
if !is_on_root_edge(pos, resolution) {
return;
}
let tri = if is_pentagon(pos, resolution) {
let dir_we_came_from = dir.opposite();
triangle_on_pos_with_closest_mid_axis(pos, &dir_we_came_from, resolution)
} else {
closest_triangle_to_point(pos, resolution)
};
let (new_pos, new_dir) = world_to_local(*pos, *dir, resolution, tri);
*pos = new_pos;
*dir = new_dir;
let next_pos = adjacent_pos_in_dir(*pos, *dir).expect(
"Caller should have assured we're pointing at a hex edge.",
);
let still_in_same_quad = next_pos.x >= 0 && next_pos.y >= 0;
if still_in_same_quad {
transform_into_exit_triangle(pos, dir, resolution, &tri.exits[0]);
return;
}
if pos.x == 0 && pos.y == 0 && dir.index == 6 {
*dir = Dir::new(1);
transform_into_exit_triangle(pos, dir, resolution, &tri.exits[2]);
return;
}
if pos.x == 0 && pos.y == 0 && dir.index == 8 {
*dir = Dir::new(1);
transform_into_exit_triangle(pos, dir, resolution, &tri.exits[3]);
return;
}
if next_pos.x < 0 {
pos.x = pos.y;
pos.y = 0;
*dir = dir.next_hex_edge_right();
transform_into_exit_triangle(pos, dir, resolution, &tri.exits[1]);
return;
}
if next_pos.y < 0 {
pos.y = pos.x;
pos.x = 0;
*dir = dir.next_hex_edge_left();
transform_into_exit_triangle(pos, dir, resolution, &tri.exits[4]);
return;
}
panic!("Oops, we must have forgotten a movement case. Sounds like we didn't test hard enough!")
}