use rand::{Rng, RngExt, seq::SliceRandom};
use crate::{
animation_state::SPINNING_FRAME_TIME,
paylines::{
PaylineCheckerFn, Paylines, check_above, check_above_sm, check_below, check_below_sm,
check_eye, check_hor_sm, check_hor_xl, check_zag, check_zag_sm, check_zig, check_zig_sm,
},
symbols::{REEL_STRIPS, Symbols},
};
#[derive(Debug, Clone)]
pub struct Machine {
pub reels: [Reel; 5],
pub name: String,
pub paylines: Vec<Paylines>,
pub bet: i32,
}
impl Machine {
pub fn create_n_machines(count: i32, bet: i32) -> Vec<Self> {
(1..=count).map(|n| Self::new(n, bet)).collect()
}
pub fn new(machine_num: i32, bet: i32) -> Self {
Self {
reels: std::array::from_fn(Reel::new),
name: format!("Machine {machine_num}"),
paylines: Vec::new(),
bet,
}
}
pub fn spin(&mut self) {
let mut rng = rand::rng();
for reel in &mut self.reels {
reel.spin(&mut rng);
}
}
pub fn get_all_paylines(&mut self) {
const PAYLINES_TO_CHECK: [PaylineCheckerFn; 11] = [
check_hor_sm,
check_above_sm,
check_below_sm,
check_zig_sm,
check_zag_sm,
check_hor_xl,
check_zig,
check_zag,
check_above,
check_below,
check_eye,
];
let visible_symbols = self.get_visible_symbols_for_payout();
let slices: Vec<&[Symbols]> = visible_symbols.iter().map(Vec::as_slice).collect();
for payline_checker in &PAYLINES_TO_CHECK {
if let Some(payline) = payline_checker(&slices) {
self.paylines.push(payline);
}
}
}
pub fn get_visible_symbols_for_payout(&self) -> Vec<Vec<Symbols>> {
get_visible_symbols_for_reel(&self.reels, None)
}
}
pub fn get_visible_symbols_for_reel(
reels: &[Reel; 5],
mid_override: Option<&[usize]>,
) -> Vec<Vec<Symbols>> {
let mut rows = vec![Vec::new(), Vec::new(), Vec::new()];
for (i, reel) in reels.iter().enumerate() {
let len = reel.symbols.len();
let mid = if let Some(mid) = mid_override {
mid[i]
} else {
reel.ptr
};
let above = (mid + len - 1) % len;
let below = (mid + 1) % len;
rows[0].push(reel.symbols[above].clone());
rows[1].push(reel.symbols[mid].clone());
rows[2].push(reel.symbols[below].clone());
}
rows
}
pub fn calc_reel_starting_points(machine: &Machine) -> Vec<usize> {
let mut starting_points: Vec<usize> = Vec::new();
for reel in &machine.reels {
let len = reel.symbols.len();
let start = (reel.ptr + len - SPINNING_FRAME_TIME % len) % len;
starting_points.push(start);
}
starting_points
}
#[derive(Debug, Clone)]
pub struct Reel {
symbols: Vec<Symbols>,
ptr: usize,
}
impl Reel {
pub fn new(reel_num: usize) -> Self {
let mut reel_set = REEL_STRIPS[reel_num].to_vec();
reel_set.shuffle(&mut rand::rng());
Reel {
symbols: reel_set,
ptr: 0,
}
}
pub fn spin<R: Rng>(&mut self, rng: &mut R) {
self.ptr = rng.random_range(0..self.symbols.len());
}
}