number of changes, added testing

This commit is contained in:
mux 2024-08-25 23:58:56 +02:00
parent 7400786b4c
commit 7f99c65f0a
6 changed files with 475 additions and 183 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
/target
Cargo.lock
.vs-code
launch.json

View File

@ -1,3 +1,4 @@
pub mod uno_logic;
pub mod uno_protocol;
pub mod uno_tcp;
// pub mod uno_logic::tests;

View File

@ -1,2 +1,3 @@
mod uno_server;
fn main() {
}

View File

@ -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<Card>,
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<PlayerState<'a>>,
pub player_connections : Vec<PlayerConnection<'a>>,
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<PlayerState<'a>>,
pub player_connections: Vec<PlayerConnection<'a, S>>,
pub current_color: CardColors,
pub current_direction: Direction,
plus_twos: u32,
}
type Deck = Vec<Card>;
// 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<Card>) -> PlayerState{
pub fn new(player_name: &str, cards: Vec<Card>) -> 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<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 GameState<'_>{
fn cards_left(player : &PlayerState) -> usize{
impl<S> 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<PlayerState> = 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::<S>::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<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 {
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 : 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::<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::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::<S>
::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::<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{
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::<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{
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::<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{
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::<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.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>>) -> 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<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: 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<PlayerState<'a>>, player_connections: Vec<PlayerConnection<'a>>) -> GameState<'a>{
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.clone();
new_game.current_color = new_game.current_card.color;
return new_game;
}
fn get_currently_held(&mut self) -> Vec<Card>{
fn get_currently_held(&mut self) -> Vec<Card> {
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<Card>) -> 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));
fn reset_deck(&mut self, currently_held: Vec<Card>) {
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)
);
}
return vec![];
}
fn base_deck()-> Vec<Card>{
let mut deck : Deck = vec![];
fn base_deck() -> Vec<Card> {
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].contains(&value) {
for _ in 0..1 {deck.push(Card{value : value.clone(), color : color.clone()})};
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<Card>{
fn get_cards(&mut self, count: u32) -> Vec<Card> {
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<Card>{
if self.deck.len() <= count as usize{
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);
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<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 : 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};
}
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: 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::<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 : 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::<VecDeque<u8>>::check_if_legal(current_card, get_card(CardValue::FOUR, CardColors::RED), CardColors::GREEN), false);
assert_eq!(GameState::<VecDeque<u8>>::check_if_legal(current_card, get_card(CardValue::EIGHT, CardColors::YELLOW), CardColors::GREEN), false);
}
}

18
src/uno_server.rs Normal file
View File

@ -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));
}
}

View File

@ -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<PlayerConnection<'a>, 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});
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){
//
// }