extern crate rand; use std::{ io::{ Read, Write }, net::TcpStream }; use rand::Rng; const GAME_INTEGRITY_ERROR: &'static str = "game integrity compromised"; const PROTOCOL_ERROR_STRING: &str = "Client/Server protocol mismatch"; //enums, structs and types #[derive(Clone)] #[derive(Debug)] #[derive(Eq)] #[derive(Hash)] pub enum CardValue { PLUS_TWO, PLUS_FOUR, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, REVERSE, SKIP, CHANGE_COLOR, } #[derive(Clone)] #[derive(Debug)] #[derive(Eq)] #[derive(Hash)] pub enum CardColor { RED, BLUE, GREEN, YELLOW, BLACK, } pub enum Direction { CLOCKWISE, COUNTER_CLOCKWISE, } #[derive(PartialEq)] #[derive(Debug)] pub enum TURN_RESULT { NEXT_TURN, REPEAT_TURN, GAME_OVER, } #[derive(Clone)] pub struct PlayerState<'a> { pub player_name: &'a str, pub cards: Vec, pub said_uno: bool, } pub struct PlayerConnection<'a, S> where S: Read + Write { pub player_name: &'a str, pub stream: S, } #[derive(Debug)] #[derive(Eq)] #[derive(Hash)] pub struct Card { pub value: CardValue, pub color: CardColor, } pub struct GameState<'a, S: Read + Write> { pub turns: u64, pub current_turn: u32, deck: Deck, trash: Deck, pub current_card: Card, pub player_states: Vec>, pub player_connections: Vec>, pub current_color: CardColor, pub current_direction: Direction, plus_twos: u32, } type Deck = Vec; // PartialEq trait implements impl PartialEq for CardValue { fn eq(&self, other: &Self) -> bool { core::mem::discriminant(self) == core::mem::discriminant(other) } } impl PartialEq for CardColor { fn eq(&self, other: &Self) -> bool { core::mem::discriminant(self) == core::mem::discriminant(other) } } impl PartialEq for Direction { fn eq(&self, other: &Self) -> bool { core::mem::discriminant(self) == core::mem::discriminant(other) } } impl PartialEq for Card { fn eq(&self, other: &Self) -> bool { self.value == other.value && self.color == other.color } } //Clone trait implements impl Clone for Card { fn clone(&self) -> Self { Self { value: self.value.clone(), color: self.color.clone() } } } //Copy trait implements impl Copy for Card {} impl Copy for CardColor {} impl Copy for CardValue {} //struct implementations impl CardValue { pub fn to_string<'a>(self) -> &'a str { match self { CardValue::PLUS_FOUR => "PLUS_FOUR", CardValue::CHANGE_COLOR => "CHANGE_COLOR", CardValue::PLUS_TWO => "PLUS_TWO", CardValue::SKIP => "SKIP", CardValue::REVERSE => "REVERSE", CardValue::ZERO => "ZERO", CardValue::ONE => "ONE", CardValue::TWO => "TWO", CardValue::THREE => "THREE", CardValue::FOUR => "FOUR", CardValue::FIVE => "FIVE", CardValue::SIX => "SIX", CardValue::SEVEN => "SEVEN", CardValue::EIGHT => "EIGHT", CardValue::NINE => "NINE", } } } impl CardColor { pub fn to_string<'a>(self) -> &'a str { match self { CardColor::BLACK => "BLACK", CardColor::BLUE => "BLUE", CardColor::GREEN => "GREEN", CardColor::YELLOW => "YELLOW", CardColor::RED => "RED", } } } impl PlayerState<'_> { pub fn new(player_name: &str, cards: Vec) -> PlayerState { PlayerState { player_name: player_name, cards: cards, said_uno: false, } } } impl PlayerConnection<'_, TcpStream> { pub fn register_player<'a>( mut stream: TcpStream ) -> Result, String> { let buffer: &mut [u8] = &mut []; match stream.read(buffer) { Ok(_) => (), Err(_) => { return Err("could not read from socket".to_owned()); } } let msg = match std::str::from_utf8(buffer) { Ok(msg) => msg, Err(_) => { return Err("could not parse UTF-8".to_owned()); } }; let mut lines = msg.lines(); let is_valid1 = lines.next().unwrap_or_else(|| &PROTOCOL_ERROR_STRING) == "app:uno"; let is_valid2 = lines.next().unwrap_or_else(|| &PROTOCOL_ERROR_STRING) == "version:0.1"; let player_name: &str = lines.next().unwrap_or_else(|| &PROTOCOL_ERROR_STRING); let is_valid3 = if player_name != "invalid" && player_name.contains("player_name:") { true } else { false }; if lines.next() != None || !(is_valid1 && is_valid2 && is_valid3) { stream.write_all(PROTOCOL_ERROR_STRING.as_bytes()).unwrap(); stream.flush().unwrap(); return Err(PROTOCOL_ERROR_STRING.to_owned()); } stream.write_all("Ok".as_bytes()).unwrap(); stream.flush().unwrap(); return Ok(PlayerConnection { player_name: player_name[..].split(':').collect::>()[1], stream: stream, }); } } impl GameState<'_, S> where S: Read + Write { fn cards_left(player: &PlayerState) -> usize { return player.cards.len(); } fn next_player(&mut self) { match self.current_direction { Direction::CLOCKWISE => { if self.current_turn + 1 >= (self.player_states.len() as u32) { self.current_turn = 0; return; } self.current_turn += 1; } Direction::COUNTER_CLOCKWISE => { if self.current_turn == 0 { self.current_turn = (self.player_states.len() -1) as u32; return; } self.current_turn -= 1; } } } fn game_init(&mut self) { let players = self.player_states.clone(); for player in players { self.draw(player.player_name, 7); } self.turns += 1; } fn has_any_moves(&self, player: PlayerState) -> bool { for card in player.cards { if GameState::::check_if_legal( self.current_card, card, self.current_color ) { return true; } } return false; } fn add_to_trash(&mut self, card: Card) { self.trash.push(card); } fn play(player: &mut PlayerState, card_to_be_played: Card) -> Result { if player.cards.contains(&card_to_be_played) { return Ok( player.cards.remove( player.cards .iter() .position(|x| *x == card_to_be_played) .expect(&GAME_INTEGRITY_ERROR) ) ); } else { return Err(String::from("Card not held by player")); } } fn check_if_legal( current_card: Card, card_to_be_played: Card, current_color: CardColor ) -> bool { if card_to_be_played.color == CardColor::BLACK || card_to_be_played.color == current_color || card_to_be_played.value == current_card.value { return true; } else { return false; } } pub fn next_turn(&mut self, card_to_be_played: Card) -> TURN_RESULT { if self.turns == 0 { self.game_init(); return TURN_RESULT::NEXT_TURN; } if !GameState::has_any_moves(&self, self.player_states .get(self.current_turn as usize) .expect(&GAME_INTEGRITY_ERROR) .to_owned() ){ let player = &mut self.player_states.clone(); if !GameState::::check_if_legal(self.current_card,self .draw( player .get_mut(self.current_turn as usize) .expect(&GAME_INTEGRITY_ERROR).player_name, 1 ).get(0) .expect(&GAME_INTEGRITY_ERROR) .to_owned(), self.current_color ){ self.next_player(); return TURN_RESULT::NEXT_TURN; } let mut player = self.player_states.clone(); self.add_to_trash( GameState:: ::play( player.get_mut(self.current_turn as usize).expect(&GAME_INTEGRITY_ERROR), card_to_be_played ) .expect(&GAME_INTEGRITY_ERROR) ); } if !GameState::::check_if_legal( self.current_card, card_to_be_played, self.current_color ) { return TURN_RESULT::REPEAT_TURN; } if self.current_card.value == CardValue::PLUS_TWO && card_to_be_played.value != CardValue::PLUS_TWO { let player = &mut self.player_states.clone(); self.draw( player .get_mut(self.current_turn as usize) .expect(&GAME_INTEGRITY_ERROR).player_name, self.plus_twos ); } else if self.current_card.value == CardValue::PLUS_TWO && card_to_be_played.value == CardValue::PLUS_TWO { self.plus_twos += 1; if self.current_color != card_to_be_played.color { self.current_color = card_to_be_played.color; } let mut player = self.player_states.clone(); self.add_to_trash( GameState:: ::play( player.get_mut(self.current_turn as usize).expect(&GAME_INTEGRITY_ERROR), card_to_be_played ) .expect(&GAME_INTEGRITY_ERROR) ); self.next_player(); return TURN_RESULT::NEXT_TURN; } if self.current_card.value == CardValue::PLUS_FOUR { let mut player = self.player_states.clone(); self.draw( player .get_mut(self.current_turn as usize) .expect(&GAME_INTEGRITY_ERROR).player_name, 4 ); } if card_to_be_played.value == CardValue::SKIP { self.current_card = card_to_be_played; for _ in 0 .. 2 { self.next_player()}; self.turns += 1; return TURN_RESULT::NEXT_TURN; } let mut player = self.player_states.clone(); if player.get(self.current_turn as usize).expect(&GAME_INTEGRITY_ERROR).said_uno == true && GameState::::cards_left( player.get(self.current_turn as usize).expect(&GAME_INTEGRITY_ERROR) ) == 1 { self.add_to_trash( GameState:: ::play( player.get_mut(self.current_turn as usize).expect(&GAME_INTEGRITY_ERROR), card_to_be_played ) .expect(&GAME_INTEGRITY_ERROR) ); self.turns += 1; return TURN_RESULT::GAME_OVER; } if card_to_be_played.value == CardValue::REVERSE { if self.current_direction == Direction::CLOCKWISE { self.current_direction = Direction::COUNTER_CLOCKWISE; } else { self.current_direction = Direction::CLOCKWISE; } } if [CardValue::CHANGE_COLOR, CardValue::PLUS_FOUR].contains(&card_to_be_played.value) { self.current_color = card_to_be_played.color; } else if [ CardValue::EIGHT, CardValue::FIVE, CardValue::FOUR, CardValue::NINE, CardValue::ONE, CardValue::SEVEN, CardValue::SIX, CardValue::THREE, CardValue::TWO, CardValue::ZERO, CardValue::PLUS_TWO, CardValue::SKIP, CardValue::REVERSE, CardValue::PLUS_TWO, ].contains(&card_to_be_played.value) { if card_to_be_played.color != self.current_color { self.current_color = card_to_be_played.color; } } let mut player = self.player_states.clone(); self.add_to_trash( GameState:: ::play( player.get_mut(self.current_turn as usize).expect(&GAME_INTEGRITY_ERROR), card_to_be_played ) .expect(&GAME_INTEGRITY_ERROR) ); self.current_card = card_to_be_played; self.turns += 1; self.next_player(); return TURN_RESULT::NEXT_TURN; } fn new_game_helper<'a>( player_states: Vec>, player_connections: Vec> ) -> GameState<'a, S> { GameState { turns: 0, current_turn: 0, deck: GameState::::base_deck(), trash: vec![], current_card: Card { value: CardValue::ZERO, color: CardColor::RED }, player_states: player_states.clone(), player_connections: player_connections, current_color: CardColor::RED, current_direction: Direction::CLOCKWISE, plus_twos: 0, } } pub fn new_game<'a>( player_states: Vec>, player_connections: Vec> ) -> GameState<'a, S> { let mut new_game = GameState::new_game_helper(player_states, player_connections); new_game.current_color = new_game.current_card.color; return new_game; } fn get_currently_held(&mut self) -> Vec { let mut currently_held = vec![]; for hand in &mut self.player_states { currently_held.append(&mut hand.cards); } return currently_held; } fn reset_deck(&mut self, currently_held: Vec) { self.trash.clear(); self.deck = GameState::::base_deck(); for current_cart in currently_held { self.deck.remove( self.deck .iter() .position(|x| *x == current_cart) .expect(&GAME_INTEGRITY_ERROR) ); } } fn base_deck() -> Vec { let mut deck: Deck = vec![]; for color in [ CardColor::BLACK, CardColor::BLUE, CardColor::GREEN, CardColor::RED, CardColor::YELLOW, ] { for value in [ CardValue::CHANGE_COLOR, CardValue::PLUS_FOUR, CardValue::ONE, CardValue::TWO, CardValue::THREE, CardValue::FOUR, CardValue::FIVE, CardValue::SIX, CardValue::SEVEN, CardValue::EIGHT, CardValue::NINE, CardValue::ZERO, CardValue::PLUS_TWO, CardValue::REVERSE, CardValue::SKIP, ] { if ![CardValue::CHANGE_COLOR, CardValue::PLUS_FOUR, CardValue::ZERO].contains(&value) && color != CardColor::BLACK { for _ in 0..2 { deck.push(Card { value: value, color: color }); } } else if value == CardValue::ZERO && color != CardColor::BLACK{ deck.push(Card { value: value, color: color }); } else if [CardValue::CHANGE_COLOR, CardValue::PLUS_FOUR].contains(&value) && color == CardColor::BLACK { for _ in 0..4 { deck.push(Card { value: value, color: color }); } } } } //CHANGE COLOR /* for _ in 0..3 {deck.push(Card {value : CardValue::CHANGE_COLOR, color : CardColor::BLACK, color_change : CardColor::BLACK})}; //PLUS FOUR for _ in 0..3 {deck.push(Card{ value : CardValue::PLUS_FOUR, color : CardColor::BLACK, color_change : CardColor::BLACK})}; //PLUS TWO for _ in 0..1 {deck.push(Card{ value : CardValue::PLUS_TWO, color : CardColor::RED, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::PLUS_TWO, color : CardColor::BLUE, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::PLUS_TWO, color : CardColor::GREEN, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::PLUS_TWO, color : CardColor::YELLOW, color_change : CardColor::BLACK})}; //REVERSE for _ in 0..1 {deck.push(Card{ value : CardValue::REVERSE, color : CardColor::RED, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::REVERSE, color : CardColor::BLUE, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::REVERSE, color : CardColor::GREEN, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::REVERSE, color : CardColor::YELLOW, color_change : CardColor::BLACK})}; //SKIP for _ in 0..1 {deck.push(Card{ value : CardValue::SKIP, color : CardColor::RED, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::SKIP, color : CardColor::BLUE, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::SKIP, color : CardColor::GREEN, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::SKIP, color : CardColor::YELLOW, color_change : CardColor::BLACK})}; //NINE for _ in 0..1 {deck.push(Card{ value : CardValue::NINE, color : CardColor::RED, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::NINE, color : CardColor::BLUE, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::NINE, color : CardColor::GREEN, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::NINE, color : CardColor::YELLOW, color_change : CardColor::BLACK})}; //EIGHT for _ in 0..1 {deck.push(Card{ value : CardValue::EIGHT, color : CardColor::RED, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::EIGHT, color : CardColor::BLUE, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::EIGHT, color : CardColor::GREEN, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::EIGHT, color : CardColor::YELLOW, color_change : CardColor::BLACK})}; //SEVEN for _ in 0..1 {deck.push(Card{ value : CardValue::SEVEN, color : CardColor::RED, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::SEVEN, color : CardColor::BLUE, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::SEVEN, color : CardColor::GREEN, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::SEVEN, color : CardColor::YELLOW, color_change : CardColor::BLACK})}; //SIX for _ in 0..1 {deck.push(Card{ value : CardValue::SIX, color : CardColor::RED, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::SIX, color : CardColor::BLUE, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::SIX, color : CardColor::GREEN, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::SIX, color : CardColor::YELLOW, color_change : CardColor::BLACK})}; //FIVE for _ in 0..1 {deck.push(Card{ value : CardValue::FIVE, color : CardColor::RED, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::FIVE, color : CardColor::BLUE, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::FIVE, color : CardColor::GREEN, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::FIVE, color : CardColor::YELLOW, color_change : CardColor::BLACK})}; //FOUR for _ in 0..1 {deck.push(Card{ value : CardValue::FOUR, color : CardColor::RED, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::FOUR, color : CardColor::BLUE, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::FOUR, color : CardColor::GREEN, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::FOUR, color : CardColor::YELLOW, color_change : CardColor::BLACK})}; //THREE for _ in 0..1 {deck.push(Card{ value : CardValue::THREE, color : CardColor::RED, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::THREE, color : CardColor::BLUE, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::THREE, color : CardColor::GREEN, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::THREE, color : CardColor::YELLOW, color_change : CardColor::BLACK})}; //TWO for _ in 0..1 {deck.push(Card{ value : CardValue::TWO, color : CardColor::RED, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::TWO, color : CardColor::BLUE, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::TWO, color : CardColor::GREEN, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::TWO, color : CardColor::YELLOW, color_change : CardColor::BLACK})}; //ONE for _ in 0..1 {deck.push(Card{ value : CardValue::ONE, color : CardColor::RED, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::ONE, color : CardColor::BLUE, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::ONE, color : CardColor::GREEN, color_change : CardColor::BLACK})}; for _ in 0..1 {deck.push(Card{ value : CardValue::ONE, color : CardColor::YELLOW, color_change : CardColor::BLACK})}; //ZERO deck.push(Card{ value : CardValue::ZERO, color : CardColor::RED, color_change : CardColor::BLACK}); deck.push(Card{ value : CardValue::ZERO, color : CardColor::BLUE, color_change : CardColor::BLACK}); deck.push(Card{ value : CardValue::ZERO, color : CardColor::GREEN, color_change : CardColor::BLACK}); deck.push(Card{ value : CardValue::ZERO, color : CardColor::YELLOW, color_change : CardColor::BLACK}); */ return deck; } fn get_cards(&mut self, count: u32) -> Vec { let mut cards_drawn = vec![]; for _ in 0..count { let mut rng = rand::thread_rng(); let n: usize = rng.gen_range(0..self.deck.len()); cards_drawn.push(self.deck.remove(n)); } cards_drawn } fn draw(&mut self, player_name: &str, count: u32) -> Vec { if self.deck.len() <= (count as usize) { let currently_held = self.get_currently_held(); self.reset_deck(currently_held); } let mut cards_drawn = self.get_cards(count); for player in &mut self.player_states { if player.player_name == player_name { player.cards.append(&mut cards_drawn); } } cards_drawn } } #[cfg(test)] mod tests { use std::{collections::{HashSet, VecDeque}, iter::Skip}; use super::*; fn get_card_set() -> Vec{ let mut set = HashSet::new(); let mut unique_vec = vec![]; GameState::>::base_deck().into_iter().for_each(|c| { set.insert(c); }); set.into_iter().for_each(|c| unique_vec.push(c.to_owned())); unique_vec } fn get_card(card_value : CardValue, card_color : CardColor) -> Card{ for card in get_card_set(){ if card_value == card.value && card_color == card.color { return card; } } return Card {value : CardValue::ZERO, color : CardColor::BLACK}; } fn get_test_gs<'a>() -> GameState<'a, VecDeque> { let fake_stream_detlef: VecDeque = VecDeque::new(); let fake_stream_dieter: VecDeque = VecDeque::new(); let fake_stream_doerte: VecDeque = VecDeque::new(); let player_states: Vec = vec![ PlayerState::new("detlef", vec![]), PlayerState::new("dieter", vec![]), PlayerState::new("dorte", vec![]) ]; let player_connections = vec![ PlayerConnection { player_name: "detlef", stream: fake_stream_detlef }, PlayerConnection { player_name: "dieter", stream: fake_stream_dieter }, PlayerConnection { player_name: "doerte", stream: fake_stream_doerte } ]; GameState::new_game(player_states, player_connections) } #[test] fn test_card_value_to_string() { let cv: CardValue = CardValue::NINE; assert_eq!(cv.to_string(), "NINE"); } #[test] fn test_card_color_to_string() { let cc: CardColor = CardColor::BLUE; assert_eq!(cc.to_string(), "BLUE"); } #[test] fn test_game_init() { let mut gs = get_test_gs(); gs.game_init(); for player_state in &mut gs.player_states { // println!("{:#?}", player_state.cards); assert_eq!(player_state.cards.len(), 7); } assert_eq!( gs.deck.len(), GameState::>::base_deck().len() - gs.player_states.len() * 7 ); } #[test] fn test_next_player_cw() { let mut gs = get_test_gs(); gs.current_direction = Direction::CLOCKWISE; gs.next_player(); assert_eq!(gs.current_turn, 1); } #[test] fn test_next_player_ccw() { let mut gs = get_test_gs(); gs.current_direction = Direction::COUNTER_CLOCKWISE; gs.next_player(); assert_eq!(gs.current_turn, 2); } #[test] fn test_has_any_moves_none(){ let mut gs = get_test_gs(); //no moves gs.current_card = Card {value : CardValue::TWO, color : CardColor::GREEN}; gs.current_color = CardColor::GREEN; let player = PlayerState::new("detlef", [get_card(CardValue::FOUR, CardColor::RED), get_card(CardValue::EIGHT, CardColor::YELLOW)].to_vec()); assert_eq!(gs.has_any_moves(player), false); } #[test] fn test_has_any_moves_some(){ let mut gs = get_test_gs(); //has moves gs.current_card = Card {value : CardValue::TWO, color : CardColor::GREEN}; gs.current_color = CardColor::GREEN; let player = PlayerState::new("detlef", [get_card(CardValue::FOUR, CardColor::RED), get_card(CardValue::EIGHT, CardColor::GREEN)].to_vec()); } #[test] fn test_check_if_legal_false(){ //illegal let current_card = Card {value : CardValue::TWO, color : CardColor::GREEN}; assert_eq!(GameState::>::check_if_legal(current_card, get_card(CardValue::FOUR, CardColor::RED), CardColor::GREEN), false); assert_eq!(GameState::>::check_if_legal(current_card, get_card(CardValue::EIGHT, CardColor::YELLOW), CardColor::GREEN), false); } #[test] fn test_add_to_trash(){ let mut gs = get_test_gs(); gs.add_to_trash(get_card(CardValue::ONE, CardColor::YELLOW)); assert_eq!(gs.trash, vec![get_card(CardValue::ONE, CardColor::YELLOW)]); } #[test] fn test_play_card_held(){ let mut gs = get_test_gs(); gs.player_states.get_mut(0).unwrap().cards.push(get_card(CardValue::NINE, CardColor::BLUE)); assert_eq!(GameState::>::play(gs.player_states.get_mut(0).unwrap(),get_card(CardValue::NINE, CardColor::BLUE)).unwrap(), get_card(CardValue::NINE, CardColor::BLUE)); } #[test] fn test_play_card_not_held(){ let mut gs = get_test_gs(); gs.player_states.get_mut(0).unwrap().cards.push(get_card(CardValue::NINE, CardColor::BLUE)); assert_eq!(GameState::>::play(gs.player_states.get_mut(0).unwrap(),get_card(CardValue::EIGHT, CardColor::BLUE)), Err("Card not held by player".to_owned())); } #[test] fn test_next_turn_green_two_to_red_two(){ let mut gs = get_test_gs(); gs.game_init(); gs.current_card = get_card(CardValue::TWO, CardColor::GREEN); gs.current_color = CardColor::GREEN; gs.player_states.get_mut(0).unwrap().cards.push(get_card(CardValue::TWO, CardColor::RED)); assert_eq!(gs.next_turn(get_card(CardValue::TWO, CardColor::RED)), TURN_RESULT::NEXT_TURN); assert_eq!(gs.current_color, CardColor::RED); assert_eq!(gs.current_card, get_card(CardValue::TWO, CardColor::RED)); assert_eq!(gs.plus_twos, 0); assert_eq!(gs.turns, 2); assert_eq!(gs.current_turn, 1); } #[test] fn test_next_turn_green_two_to_yellow_four(){ let mut gs = get_test_gs(); gs.game_init(); gs.current_card = get_card(CardValue::TWO, CardColor::GREEN); gs.current_color = CardColor::GREEN; gs.player_states.get_mut(0).unwrap().cards.push(get_card(CardValue::FOUR, CardColor::YELLOW)); assert_eq!(gs.next_turn(get_card(CardValue::FOUR, CardColor::YELLOW)), TURN_RESULT::REPEAT_TURN); assert_eq!(gs.current_color, CardColor::GREEN); assert_eq!(gs.current_card, get_card(CardValue::TWO, CardColor::GREEN)); assert_eq!(gs.turns, 1); assert_eq!(gs.current_turn, 0); } #[test] fn test_next_turn_green_two_to_green_skip(){ let mut gs = get_test_gs(); gs.game_init(); gs.current_card = get_card(CardValue::TWO, CardColor::GREEN); gs.current_color = CardColor::GREEN; gs.player_states.get_mut(0).unwrap().cards.push(get_card(CardValue::SKIP, CardColor::GREEN)); assert_eq!(gs.next_turn(get_card(CardValue::SKIP, CardColor::GREEN)), TURN_RESULT::NEXT_TURN); assert_eq!(gs.current_color, CardColor::GREEN); assert_eq!(gs.current_card, get_card(CardValue::SKIP, CardColor::GREEN)); assert_eq!(gs.turns, 2); assert_eq!(gs.current_turn, 2); } #[test] fn test_next_turn_green_two_to_plus_four(){ } #[test] fn test_next_turn_green_two_to_green_reverse(){ } #[test] fn test_next_turn_green_two_to_change_color(){ } }