use rand::prelude::*; use std::fmt::{Display, Formatter, write}; use std::mem; use crate::uno::UnoState::NotStarted; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Color { Wild, Blue, Green, Red, Yellow, } impl Display for Color { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Color::Wild => { write!(f, "Wild") } Color::Blue => { write!(f, "Blue") } Color::Green => { write!(f, "Green") } Color::Red => { write!(f, "Red") } Color::Yellow => { write!(f, "Yellow") } } } } #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Type { Number(usize), DrawTwo, DrawFour, ChooseColor, Reverse, Skip, } impl Display for Type { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Type::Number(n) => { write!(f, "{}", n) } Type::DrawTwo => { write!(f, "+2") } Type::DrawFour => { write!(f, "+4") } Type::ChooseColor => { write!(f, "Choose Color") } Type::Reverse => { write!(f, "Reverse") } Type::Skip => { write!(f, "Skip") } } } } #[derive(Debug, Eq, PartialEq)] pub struct UnoCard { typ: Type, col: Color, } impl UnoCard { pub fn new(typ: Type, col: Color) -> UnoCard { UnoCard { typ, col } } pub fn can_stack(&self, other: &UnoCard) -> bool { return if self.typ == other.typ || self.col == other.col || self.col == Color::Wild || other.col == Color::Wild { true } else { false }; } } impl Default for UnoCard { fn default() -> Self { UnoCard::new(Type::Number(0), Color::Wild) } } impl Display for UnoCard { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{} {}", self.col, self.typ) } } #[derive(Debug)] pub struct UnoPlayer { pub name: String, pub hand: Vec, } impl UnoPlayer { pub fn new(name: String) -> Self { UnoPlayer { name, hand: vec![] } } pub fn take_hand(&mut self) -> Vec { mem::take(&mut self.hand) } pub fn give_hand(&mut self, hand: Vec) { self.hand = hand; } pub fn take_card(&mut self, idx: usize) -> UnoCard { let mut hand = self.take_hand(); let result = hand.remove(idx); self.give_hand(hand); result } } #[derive(Debug, Eq, PartialEq)] pub enum UnoState { NotStarted, Started, Ended, } fn new_uno_stack() -> Vec { let mut deck: Vec = vec![]; for col in [Color::Blue, Color::Red, Color::Green, Color::Yellow] { deck.push(UnoCard::new(Type::Number(0), col)); for n in 1..=9 { deck.push(UnoCard::new(Type::Number(n), col)); deck.push(UnoCard::new(Type::Number(n), col)); } for typ in [Type::Reverse, Type::Skip, Type::DrawTwo] { deck.push(UnoCard::new(typ, col)); } for _ in 0..4 { deck.push(UnoCard::new(Type::DrawFour, Color::Wild)); deck.push(UnoCard::new(Type::ChooseColor, Color::Wild)); } } deck } #[derive(Debug)] pub struct Uno { card_stack: Vec, pub players: Vec, pub admin: String, pub active_player: usize, pub direction: i32, pub draw_amount: u32, pub state: UnoState, pub top: UnoCard, } impl Uno { pub fn new(admin: String) -> Self { Uno { card_stack: new_uno_stack(), players: vec![], admin, active_player: 0, direction: 1, draw_amount: 0, state: UnoState::Ended, top: UnoCard::default(), } } pub fn draw(&mut self) -> UnoCard { self.card_stack.pop().unwrap() } pub fn end(&mut self) { self.state = UnoState::Ended; } pub fn init(&mut self) { self.state = UnoState::Started; self.shuffle(); let mut card_buf: Vec = vec![]; for _ in 0..(7 * self.players.len()) { card_buf.push(self.draw()); } for player in self.players.iter_mut() { for _ in 0..7 { player.hand.push(card_buf.pop().unwrap()); } } self.top = self.draw(); } pub fn join(&mut self, name: String) { if self.state == UnoState::NotStarted { self.players.push(UnoPlayer::new(name)); } } pub fn kick(&mut self, name: String) { let mut kick_idx: usize = usize::MAX; for (i, p) in self.players.iter_mut().enumerate() { if p.name == name { let mut hand = p.take_hand(); self.card_stack.append(&mut hand); kick_idx = i; if i < self.active_player { self.active_player -= 1; } } } if kick_idx < self.players.len() { self.players.remove(kick_idx); } self.shuffle(); } pub fn next_player(&mut self) { let mult: i32 = match self.top.typ { Type::Skip => { 2 } _ => { 1 } }; self.active_player = (self.active_player + self.players.len() + (self.direction * mult) as usize) % self.players.len(); } pub fn place(&mut self, card: UnoCard) { self.card_stack.push(mem::take(&mut self.top)); self.top = card; self.shuffle(); match self.top.typ { Type::Number(_) => { self.draw_amount = 0; } Type::DrawTwo => { self.draw_amount += 2; } Type::DrawFour => { self.draw_amount += 4; } Type::ChooseColor => { self.draw_amount = 0; } Type::Reverse => { self.direction *= -1; self.draw_amount = 0; } Type::Skip => { self.draw_amount = 0; } } self.next_player(); } pub fn shuffle(&mut self) { let mut rng = thread_rng(); self.card_stack.shuffle(&mut rng); } pub fn reset(&mut self, admin: String) { self.admin = admin; self.players = vec![]; self.card_stack = new_uno_stack(); self.active_player = 0; self.direction = 1; self.draw_amount = 0; self.state = NotStarted; self.top = UnoCard::default(); } }