Uno/src/uno_logic.rs

836 lines
31 KiB
Rust

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<Card>,
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<PlayerState<'a>>,
pub player_connections: Vec<PlayerConnection<'a, S>>,
pub current_color: CardColor,
pub current_direction: Direction,
plus_twos: u32,
}
type Deck = Vec<Card>;
// 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<Card>) -> PlayerState {
PlayerState {
player_name: player_name,
cards: cards,
said_uno: false,
}
}
}
impl PlayerConnection<'_, TcpStream> {
pub fn register_player<'a>(
mut stream: TcpStream
) -> Result<PlayerConnection<'a, TcpStream>, 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::<Vec<_>>()[1],
stream: stream,
});
}
}
impl<S> 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::<S>::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<Card, String> {
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::<S>::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::<S>
::play(
player.get_mut(self.current_turn as usize).expect(&GAME_INTEGRITY_ERROR),
card_to_be_played
)
.expect(&GAME_INTEGRITY_ERROR)
);
}
if
!GameState::<S>::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::<S>
::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::<S>::cards_left(
player.get(self.current_turn as usize).expect(&GAME_INTEGRITY_ERROR)
) == 1
{
self.add_to_trash(
GameState::<S>
::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::<S>
::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<PlayerState<'a>>,
player_connections: Vec<PlayerConnection<'a, S>>
) -> GameState<'a, S> {
GameState {
turns: 0,
current_turn: 0,
deck: GameState::<S>::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<PlayerState<'a>>,
player_connections: Vec<PlayerConnection<'a, S>>
) -> 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<Card> {
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<Card>) {
self.trash.clear();
self.deck = GameState::<S>::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<Card> {
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<Card> {
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<Card> {
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<Card>{
let mut set = HashSet::new();
let mut unique_vec = vec![];
GameState::<VecDeque<u8>>::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<u8>> {
let fake_stream_detlef: VecDeque<u8> = VecDeque::new();
let fake_stream_dieter: VecDeque<u8> = VecDeque::new();
let fake_stream_doerte: VecDeque<u8> = VecDeque::new();
let player_states: Vec<PlayerState> = 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::<VecDeque<u8>>::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::<VecDeque<u8>>::check_if_legal(current_card, get_card(CardValue::FOUR, CardColor::RED), CardColor::GREEN), false);
assert_eq!(GameState::<VecDeque<u8>>::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::<VecDeque<u8>>::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::<VecDeque<u8>>::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(){
}
}