rust-ufo/src/movable/ufo.rs

89 lines
2.7 KiB
Rust

use std::cmp::{max, min};
use rand::Rng;
use crate::Direction;
use crate::Direction::{Left, Right};
use crate::movable::Movable;
use crate::terminal::{clear_pos, MAX_UFO_ROW, MIN_UFO_ROW, print_str_at, WIDTH};
const UFO_STR: &str = "<=000=>";
pub struct Ufo {
row: u16,
column: i16,
direction: Direction,
}
impl Movable<Ufo> for Ufo {
fn create() -> Ufo {
let mut rng = rand::thread_rng();
let direction: Direction = if rng.gen() { Left } else { Right };
let row = rng.gen_range(MIN_UFO_ROW..=MAX_UFO_ROW);
let column = match direction {
// If the UFO is moving right, we will initially place it just at the left edge.
Right => -(UFO_STR.len() as i16),
// If the UFO is moving left, we will initially place it just at the right edge.
Left => WIDTH as i16,
// Above, we're creating either a Left or a Right direction value. So, we CANNOT get here. Hence: PANIC!
_ => panic!("Programming error. We're not supposed to get here.")
};
let ufo = Ufo { row, column, direction };
ufo.draw();
ufo
}
fn mov(&mut self, _direction: Direction) {
clear(self);
match self.direction {
Left => {
let ufo_str_len = UFO_STR.len() as i16;
if self.column >= -ufo_str_len {
self.column -= 1;
}
}
Right => {
if self.column <= WIDTH as i16 {
self.column += 1;
}
}
_ => { /* Ignore, this can't be the case. */ }
};
self.draw();
}
fn draw(&self) {
let ufo_str_len = UFO_STR.len() as i16;
let left_cutoff = min(max(0, -self.column), ufo_str_len) as usize;
let right_cutoff = max(0, min(ufo_str_len, WIDTH as i16 - self.column)) as usize;
let ufo_str_slice = &UFO_STR[left_cutoff..right_cutoff];
let col = max(0, min(self.column, (WIDTH as i16) - (right_cutoff as i16))) as u16;
print_str_at(col, self.row, ufo_str_slice);
}
fn is_on_screen(&self) -> bool {
self.column >= -(UFO_STR.len() as i16)
&& self.column <= (WIDTH as i16)
}
}
fn clear(ufo: &Ufo) {
match ufo.direction {
Right => {
if ufo.column >= 0 {
clear_pos(ufo.column as u16, ufo.row);
}
}
Left => {
let current_right = ufo.column + (UFO_STR.len() as i16) - 1;
if current_right >= 0 && current_right < (WIDTH as i16) {
clear_pos(current_right as u16, ufo.row);
}
}
_ => {}
};
}