From 7f99c65f0a493a77bfaf1440853774c8c9dd3c8e Mon Sep 17 00:00:00 2001 From: mux Date: Sun, 25 Aug 2024 23:58:56 +0200 Subject: [PATCH] number of changes, added testing --- .gitignore | 1 + src/lib.rs | 3 +- src/main.rs | 1 + src/uno_logic.rs | 592 ++++++++++++++++++++++++++++++++++------------ src/uno_server.rs | 18 ++ src/uno_tcp.rs | 43 +--- 6 files changed, 475 insertions(+), 183 deletions(-) create mode 100644 src/uno_server.rs diff --git a/.gitignore b/.gitignore index 0024e1e..0f75a5b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target Cargo.lock .vs-code +launch.json diff --git a/src/lib.rs b/src/lib.rs index 8ffcde7..d457dca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ pub mod uno_logic; pub mod uno_protocol; -pub mod uno_tcp; \ No newline at end of file +pub mod uno_tcp; +// pub mod uno_logic::tests; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index f79c691..698df63 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,2 +1,3 @@ +mod uno_server; fn main() { } diff --git a/src/uno_logic.rs b/src/uno_logic.rs index 90bf831..98a4911 100644 --- a/src/uno_logic.rs +++ b/src/uno_logic.rs @@ -1,14 +1,15 @@ extern crate rand; -use std::{ - io::{ BufReader, BufWriter }, net::TcpStream, usize, vec -}; +use std::{ io::{ Read, Write }, net::TcpStream }; use rand::Rng; -const GAME_INTEGRITY_ERROR : &'static str = "game integrity compromised"; - +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, @@ -28,6 +29,9 @@ pub enum CardValue { } #[derive(Clone)] +#[derive(Debug)] +#[derive(Eq)] +#[derive(Hash)] pub enum CardColors { RED, BLUE, @@ -41,65 +45,67 @@ pub enum Direction { COUNTER_CLOCKWISE, } -pub enum TURN_RESULT{ +pub enum TURN_RESULT { NEXT_TURN, REPEAT_TURN, - GAME_OVER + GAME_OVER, } #[derive(Clone)] pub struct PlayerState<'a> { pub player_name: &'a str, pub cards: Vec, - pub said_uno : bool, + pub said_uno: bool, } -pub struct PlayerConnection<'a>{ - pub player_name : &'a str, - pub stream : TcpStream, +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: CardColors, } -pub struct GameState<'a>{ - 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 : CardColors, - pub current_direction : Direction, - plus_twos : u32, +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: CardColors, + pub current_direction: Direction, + plus_twos: u32, } type Deck = Vec; // PartialEq trait implements -impl PartialEq for CardValue{ +impl PartialEq for CardValue { fn eq(&self, other: &Self) -> bool { core::mem::discriminant(self) == core::mem::discriminant(other) } } -impl PartialEq for CardColors{ +impl PartialEq for CardColors { fn eq(&self, other: &Self) -> bool { core::mem::discriminant(self) == core::mem::discriminant(other) } } -impl PartialEq for Direction{ +impl PartialEq for Direction { fn eq(&self, other: &Self) -> bool { core::mem::discriminant(self) == core::mem::discriminant(other) } } -impl PartialEq for Card{ +impl PartialEq for Card { fn eq(&self, other: &Self) -> bool { self.value == other.value && self.color == other.color } @@ -109,7 +115,7 @@ impl PartialEq for Card{ impl Clone for Card { fn clone(&self) -> Self { - Self {value: self.value.clone(), color: self.color.clone()} + Self { value: self.value.clone(), color: self.color.clone() } } } @@ -122,7 +128,7 @@ impl Copy for CardValue {} //struct implementations impl CardValue { - pub fn to_string<'a>(self) -> &'a str{ + pub fn to_string<'a>(self) -> &'a str { match self { CardValue::PLUS_FOUR => "PLUS_FOUR", CardValue::CHANGE_COLOR => "CHANGE_COLOR", @@ -138,237 +144,410 @@ impl CardValue { CardValue::SIX => "SIX", CardValue::SEVEN => "SEVEN", CardValue::EIGHT => "EIGHT", - CardValue::NINE => "NINE" + CardValue::NINE => "NINE", } } } impl CardColors { - pub fn to_string<'a>(self) -> &'a str{ + pub fn to_string<'a>(self) -> &'a str { match self { CardColors::BLACK => "BLACK", CardColors::BLUE => "BLUE", CardColors::GREEN => "GREEN", CardColors::YELLOW => "YELLOW", - CardColors::RED => "RED" + CardColors::RED => "RED", } } } impl PlayerState<'_> { - pub fn new(player_name : &str, cards : Vec) -> PlayerState{ + pub fn new(player_name: &str, cards: Vec) -> PlayerState { PlayerState { player_name: player_name, cards: cards, - said_uno : false, + said_uno: false, } } } -impl PlayerConnection<'_> { - pub fn new(player_name : &str, stream : TcpStream) -> PlayerConnection{ - PlayerConnection { - player_name : player_name, - stream : stream +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<'_>{ - - fn cards_left(player : &PlayerState) -> usize{ +impl GameState<'_, S> where S: Read + Write { + fn cards_left(player: &PlayerState) -> usize { return player.cards.len(); } fn next_player(&mut self) { - if self.current_direction == Direction::CLOCKWISE{ - if self.current_turn+1 >= self.player_states.len() as u32{ - self.current_turn = 0; - return; + 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; } - self.current_turn +=1; - } - else { - if self.current_turn == 0{ - self.current_turn = (self.player_states.len()-1) as u32; - return; + Direction::COUNTER_CLOCKWISE => { + if self.current_turn == 0 { + self.current_turn = (self.player_states.len() -1) as u32; + return; + } + self.current_turn -= 1; } - self.current_turn -=1; } } - fn game_init(&mut self){ - let mut players : Vec = vec![]; - for player in &self.player_states{ - players.push(player.to_owned()); + fn game_init(&mut self) { + let players = self.player_states.clone(); + for player in players { + self.draw(player.player_name, 7); } - for mut player in &mut players{ - self.draw(&mut player, 7); - } - self.turns+=1; + self.turns += 1; } - fn has_any_moves(&self, player : PlayerState) -> bool{ - for card in player.cards{ - if GameState::check_if_legal(self.current_card.clone(), card, self.current_color.clone()){ + 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){ + 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 { + 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 : CardColors) -> bool{ - if card_to_be_played.color == CardColors::BLACK || card_to_be_played.color == current_color || card_to_be_played.value == current_card.value { + fn check_if_legal( + current_card: Card, + card_to_be_played: Card, + current_color: CardColors + ) -> bool { + if + card_to_be_played.color == CardColors::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{ - + 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()){ + 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), 1).get(0).expect(&GAME_INTEGRITY_ERROR).to_owned(), self.current_color){ + 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)); + 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){ + + 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{ + 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), 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.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.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{ + 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), 4); + self.draw( + player + .get_mut(self.current_turn as usize) + .expect(&GAME_INTEGRITY_ERROR).player_name, + 4 + ); } - if self.current_card.value == CardValue::SKIP{ + if self.current_card.value == CardValue::SKIP { self.next_player(); - self.turns+=1; - return TURN_RESULT::NEXT_TURN + 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; + 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{ + if card_to_be_played.value == CardValue::REVERSE { + if self.current_direction == Direction::CLOCKWISE { self.current_direction = Direction::COUNTER_CLOCKWISE; - } - else { + } 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{ + } 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.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.turns += 1; self.next_player(); return TURN_RESULT::NEXT_TURN; } - fn new_game_helper<'a>(player_states: Vec>, player_connections: Vec>) -> GameState<'a>{ - GameState{ - turns : 0, - current_turn : 0, - deck : GameState::base_deck(), - trash : vec![], - current_card : Card{ value : CardValue::ZERO, color : CardColors::RED}, - player_states : player_states.clone(), - player_connections : player_connections, - current_color : CardColors::RED, - current_direction : Direction::CLOCKWISE, - plus_twos : 0, + 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: CardColors::RED }, + player_states: player_states.clone(), + player_connections: player_connections, + current_color: CardColors::RED, + current_direction: Direction::CLOCKWISE, + plus_twos: 0, } } - pub fn new_game<'a>(player_states : Vec>, player_connections: Vec>) -> GameState<'a>{ + 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.clone(); + new_game.current_color = new_game.current_card.color; return new_game; } - fn get_currently_held(&mut self) -> Vec{ + fn get_currently_held(&mut self) -> Vec { let mut currently_held = vec![]; - for hand in &mut self.player_states{ + for hand in &mut self.player_states { currently_held.append(&mut hand.cards); } return currently_held; - } - - fn reset_deck(&mut self, currently_held : Vec) -> Deck{ - 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)); - } - return vec![]; } - fn base_deck()-> Vec{ - let mut deck : Deck = vec![]; + fn reset_deck(&mut self, currently_held: Vec) { + 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) + ); + } + } - for color in [CardColors::BLACK, CardColors::BLUE, CardColors::GREEN, CardColors::RED, CardColors::YELLOW]{ - for value in [CardValue::CHANGE_COLOR, CardValue::EIGHT, CardValue::FIVE, CardValue::FOUR, CardValue::NINE, CardValue::ONE, CardValue::PLUS_FOUR, CardValue::PLUS_TWO, CardValue::REVERSE, CardValue::SEVEN, CardValue::SIX, CardValue::SKIP, CardValue::THREE, CardValue::TWO, CardValue::ZERO]{ - if ![CardValue::CHANGE_COLOR, CardValue::PLUS_FOUR].contains(&value) { - for _ in 0..1 {deck.push(Card{value : value.clone(), color : color.clone()})}; + fn base_deck() -> Vec { + let mut deck: Deck = vec![]; + + for color in [ + CardColors::BLACK, + CardColors::BLUE, + CardColors::GREEN, + CardColors::RED, + CardColors::YELLOW, + ] { + for value in [ + CardValue::CHANGE_COLOR, + CardValue::EIGHT, + CardValue::FIVE, + CardValue::FOUR, + CardValue::NINE, + CardValue::ONE, + CardValue::PLUS_FOUR, + CardValue::PLUS_TWO, + CardValue::REVERSE, + CardValue::SEVEN, + CardValue::SIX, + CardValue::SKIP, + CardValue::THREE, + CardValue::TWO, + CardValue::ZERO, + ] { + if ![CardValue::CHANGE_COLOR, CardValue::PLUS_FOUR, CardValue::ZERO].contains(&value) && color != CardColors::BLACK { + for _ in 0..1 { + deck.push(Card { value: value, color: color }); + } + } else if value == CardValue::ZERO && color != CardColors::BLACK{ + deck.push(Card { value: value, color: color }); + } else { + for _ in 0..4 { + deck.push(Card { value: value, color: color }); + } } - else if value == CardValue::ZERO - { - deck.push(Card{value : value, color : color.clone()}); - } - else { - for _ in 0..4 {deck.push(Card {value : value.clone(), color : color.clone()})}; - } - } } //CHANGE COLOR @@ -441,28 +620,141 @@ impl GameState<'_>{ deck.push(Card{ value : CardValue::ZERO, color : CardColors::GREEN, color_change : CardColors::BLACK}); deck.push(Card{ value : CardValue::ZERO, color : CardColors::YELLOW, color_change : CardColors::BLACK}); */ - return deck; + return deck; } - fn get_cards(&mut self, count : u32) -> Vec{ + fn get_cards(&mut self, count: u32) -> Vec { let mut cards_drawn = vec![]; - for _ in 0..count{ + 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)); } - return cards_drawn + cards_drawn } - fn draw(&mut self, player : &mut PlayerState, count : u32) -> Vec{ - if self.deck.len() <= count as usize{ + 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); - player.cards.append(&mut cards_drawn); - return cards_drawn; + 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}; + + 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 : CardColors) -> Card{ + for card in get_card_set(){ + if card_value == card.value && card_color == card.color { + return card; + } + } + return Card {value : CardValue::ZERO, color : CardColors::BLACK}; + } -} \ No newline at end of file + 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: CardColors = CardColors::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 : CardColors::GREEN}; + let player = PlayerState::new("detlef", [get_card(CardValue::FOUR, CardColors::RED), get_card(CardValue::EIGHT, CardColors::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 : CardColors::GREEN}; + let player = PlayerState::new("detlef", [get_card(CardValue::FOUR, CardColors::RED), get_card(CardValue::EIGHT, CardColors::GREEN)].to_vec()); + } + + #[test] + fn test_check_if_legal_false(){ + //illegal + let mut gs = get_test_gs(); + let current_card = Card {value : CardValue::TWO, color : CardColors::GREEN}; + assert_eq!(GameState::>::check_if_legal(current_card, get_card(CardValue::FOUR, CardColors::RED), CardColors::GREEN), false); + assert_eq!(GameState::>::check_if_legal(current_card, get_card(CardValue::EIGHT, CardColors::YELLOW), CardColors::GREEN), false); + } +} diff --git a/src/uno_server.rs b/src/uno_server.rs new file mode 100644 index 0000000..13dd4b1 --- /dev/null +++ b/src/uno_server.rs @@ -0,0 +1,18 @@ +use std::net::{Incoming, TcpListener}; +use Uno::uno_logic::PlayerConnection; +use Uno::uno_tcp::{self, PlayerConfiguration}; + +fn create_owner<'a>(incoming_stream : &mut Incoming) -> PlayerConfiguration<'a>{ + Uno::uno_tcp::PlayerConfiguration::new(Uno::uno_logic::PlayerConnection::register_player(incoming_stream.next().unwrap().unwrap()).unwrap(), true) +} + +fn main(){ + let binding = TcpListener::bind("0.0.0.0:8000").unwrap(); + let mut stream = binding.incoming(); + let mut player_configurations = vec![]; + if player_configurations.len() == 0{ + player_configurations.push(create_owner(&mut stream)); + } + + +} \ No newline at end of file diff --git a/src/uno_tcp.rs b/src/uno_tcp.rs index 4b44fe4..c4ca83c 100644 --- a/src/uno_tcp.rs +++ b/src/uno_tcp.rs @@ -3,41 +3,20 @@ use std::{ net::TcpStream, }; -use crate::uno_logic::PlayerConnection; +use crate::uno_logic::{PlayerConnection, PlayerState}; -const PROTOCOL_ERROR_STRING: &str = "Client/Server protocol mismatch"; - -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}); +pub struct PlayerConfiguration<'a> { + pub player_connection : PlayerConnection<'a, TcpStream>, + pub is_owner : bool } +impl PlayerConfiguration<'_>{ + pub fn new<'a> (player_connection : PlayerConnection<'a, TcpStream>, is_owner : bool)-> PlayerConfiguration<'a> { + return PlayerConfiguration{player_connection : player_connection, is_owner : is_owner}; + } +} + + // fn register_player(player_name : &str, reader : BufReader, writer : BufWriter){ // // } \ No newline at end of file