use crate::interaction::get_natural_number;
use crate::map::{Room, WumpusMap};
use crate::play::game::ExitStatus;
use crate::play::magic::{is_magic_tunnel_for_some_reason, select_random_room};
use crate::play::messages::{jump, pit_kill, pit_survive, wump_kill};
use crate::play::Things;
use crate::{dprint, Args};
use anyhow::Result;
use rand::prelude::ThreadRng;
use rand::Rng;
pub fn move_player(
room: Option<usize>,
things: &mut Things,
wumpus_map: &WumpusMap,
rng: &mut ThreadRng,
_conf: &Args,
) -> Result<ExitStatus> {
fn get_valid_room(room: Option<usize>, wumpus_map: &WumpusMap) -> anyhow::Result<usize> {
let mut room_number = room;
let room_count = wumpus_map.len();
loop {
if let Some(room_number) = room_number {
if room_number < room_count + 1 {
return Ok(room_number);
} else {
println!("What? The cave surely isn't quite that big!");
}
} else {
println!("Sorry, but we're constrained to a semi-Euclidean cave!");
}
room_number = get_natural_number("To which room do you wish to move? ")?;
}
}
fn actually_move_player(
destination_room: &Room,
things: &mut Things,
wumpus_map: &WumpusMap,
rng: &mut ThreadRng,
) -> Result<()> {
let mut room = destination_room;
if is_magic_tunnel_for_some_reason(room, wumpus_map)? {
dprint!("Randomizing room\n");
room = select_random_room(wumpus_map, rng)?;
jump(room.number);
}
things.set_player_location(&room.key);
dprint!(
"moving to room {room:?}. Player location now {:?}\n",
things.player
);
Ok(())
}
let mut just_moved_by_bats = false;
let room_number = get_valid_room(room, wumpus_map)?;
let player_room = wumpus_map.try_get_room(&things.player)?;
let targ_room = wumpus_map.get_room_from_room_number(room_number)?;
if !player_room.connects_to(targ_room, wumpus_map)? {
println!("*Oof!* (You hit the wall)");
if rng.gen_range(0..6) == 1 {
println!("Your colorful comments awaken the wumpus!");
move_wump(things, wumpus_map, rng)?;
if things.player_wumpus_collision() {
wump_kill();
return Ok(ExitStatus::NormalExit);
}
}
}
actually_move_player(targ_room, things, wumpus_map, rng)?;
loop {
if things.player_wumpus_collision() {
wump_kill();
return Ok(ExitStatus::NormalExit);
}
if things.player_pit_collision() {
if rng.gen_range(0..12) < 2 {
pit_survive();
return Ok(ExitStatus::Continue);
} else {
pit_kill();
return Ok(ExitStatus::NormalExit);
}
}
if things.player_bat_collision() {
println!(
"*flap* *flap* *flap* (humongous bats pick you up and move you{}!)",
if just_moved_by_bats { " again" } else { "" }
);
let new_player_room = select_random_room(wumpus_map, rng)?;
things.set_player_location(&new_player_room.key);
just_moved_by_bats = true;
} else {
return Ok(ExitStatus::Continue);
}
}
}
pub(crate) fn move_wump(
things: &mut Things,
wumpus_map: &WumpusMap,
rng: &mut ThreadRng,
) -> anyhow::Result<()> {
let wumpus = things.wump_room(wumpus_map)?;
let wump_vertex = wumpus.get_vertex(wumpus_map)?;
let neighbors = wump_vertex.neighbors();
let neighbor_count = neighbors.len();
let move_to = neighbors[rng.gen_range(0..neighbor_count)];
things.set_wumpus_location(&move_to, wumpus_map)?;
Ok(())
}