diff --git a/src/plugin/action/advance.rs b/src/plugin/action/advance.rs index f93bd75..182f2fb 100644 --- a/src/plugin/action/advance.rs +++ b/src/plugin/action/advance.rs @@ -84,7 +84,7 @@ impl Advance { last_card = Some(card); - card.perform(state, remaining_cards.clone())?; + card.perform(state, remaining_cards.clone(), self.distance)?; player = state.clone_current_player(); } _ => Err(HUIError::new_err("Card cannot be played on this field"))?, diff --git a/src/plugin/action/card.rs b/src/plugin/action/card.rs index 0000573..3cb8fe2 100644 --- a/src/plugin/action/card.rs +++ b/src/plugin/action/card.rs @@ -55,6 +55,7 @@ impl Card { current: &mut Hare, other: &mut Hare, remaining_cards: Vec, + advance_distance: usize, ) -> Result<(), PyErr> { match self { Card::FallBack => { @@ -97,28 +98,45 @@ impl Card { )); } - if let (Some(current_last_move), Some(other_last_move)) = - (¤t.last_move, &other.last_move) + let mut current_ok: bool = true; + if let Some(current_last_move) = ¤t.last_move { - if let (Action::Advance(current_advance), Action::Advance(other_advance)) = - (¤t_last_move.action, &other_last_move.action) + if let Action::Advance(current_advance) = ¤t_last_move.action + { + if current_advance.cards.contains(&Card::SwapCarrots) + && state.board.track[current.position - advance_distance] == Field::Hare + { + current_ok = false; + } + } + } + + let mut other_ok: bool = true; + if let Some(other_last_move) = &other.last_move + { + if let Action::Advance(other_advance) = &other_last_move.action { - if current_advance.cards.contains(&Card::SwapCarrots) - || other_advance.cards.contains(&Card::SwapCarrots) + if other_advance.cards.contains(&Card::SwapCarrots) + && state.board.track[other.position] == Field::Hare { - return Err(HUIError::new_err( - "You can only play this card if the last similar swap card was not used in one of the last two turns", - )); + other_ok = false; } } } + + if !current_ok || !other_ok { + return Err(HUIError::new_err( + "You can only play this card if the last similar swap card was not used in one of the last two turns", + )); + } + swap(&mut current.carrots, &mut other.carrots); } } Ok(()) } - pub fn perform(&self, state: &mut GameState, remaining_cards: Vec) -> Result<(), PyErr> { + pub fn perform(&self, state: &mut GameState, remaining_cards: Vec, advance_distance: usize) -> Result<(), PyErr> { let mut current = state.clone_current_player(); let mut other = state.clone_other_player(); @@ -139,7 +157,7 @@ impl Card { .position(|card| card == self) .ok_or_else(|| HUIError::new_err("Card not owned"))?; - self.play(state, &mut current, &mut other, remaining_cards)?; + self.play(state, &mut current, &mut other, remaining_cards, advance_distance)?; current.cards.remove(index); @@ -149,3 +167,15 @@ impl Card { Ok(()) } } + +impl std::fmt::Display for Card { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + + match self { + Card::FallBack => write!(f, "Fallback Card"), + Card::HurryAhead => write!(f, "HurryAhead Card"), + Card::EatSalad => write!(f, "EatSalad Card"), + Card::SwapCarrots => write!(f, "SwapCarrot Card"), + } + } +} diff --git a/src/plugin/test/card_test.rs b/src/plugin/test/card_test.rs index fbd6d06..d332416 100644 --- a/src/plugin/test/card_test.rs +++ b/src/plugin/test/card_test.rs @@ -12,22 +12,25 @@ mod tests { fn create_test_game_state() -> GameState { let board = Board::new(vec![ Field::Start, - Field::Position1, + Field::Carrots, Field::Position2, Field::Hare, + Field::Position1, + Field::Market, + Field::Carrots, + Field::Hare, + Field::Carrots, Field::Hedgehog, Field::Salad, - Field::Hare, - Field::Position1, Field::Goal, ]); let player_one = Hare::new( TeamEnum::One, Some(vec![Card::FallBack, Card::EatSalad, Card::SwapCarrots]), - Some(60), + Some(30), Some(3), None, - Some(6), + Some(7), ); let player_two = Hare::new( TeamEnum::Two, @@ -45,7 +48,7 @@ mod tests { let mut state = create_test_game_state(); let fallback_card = Card::FallBack; assert!(fallback_card - .perform(&mut state, vec![Card::EatSalad, Card::SwapCarrots]) + .perform(&mut state, vec![Card::EatSalad, Card::SwapCarrots], 0) .is_ok()); let current_player = state.clone_current_player(); assert_eq!(current_player.position, 2); @@ -56,9 +59,9 @@ mod tests { let mut state = create_test_game_state(); state.turn = 1; let hurry_ahead_card: Card = Card::HurryAhead; - assert!(hurry_ahead_card.perform(&mut state, vec![]).is_ok()); + assert!(hurry_ahead_card.perform(&mut state, vec![], 0).is_ok()); let current_player = state.clone_current_player(); - assert_eq!(current_player.position, 7); + assert_eq!(current_player.position, 8); } #[test] @@ -66,57 +69,117 @@ mod tests { let mut state = create_test_game_state(); let eat_salad_card = Card::EatSalad; assert!(eat_salad_card - .perform(&mut state, vec![Card::FallBack, Card::SwapCarrots]) + .perform(&mut state, vec![Card::FallBack, Card::SwapCarrots], 0) .is_ok()); let current_player = state.clone_current_player(); assert_eq!(current_player.salads, 2); } #[test] - fn test_swapcarrots_card() { + fn test_swapcarrots_card_general() { let mut state = create_test_game_state(); + + // modify player one let mut player_one = state.clone_current_player(); - let mut player_two = state.clone_other_player(); - player_one.position = 3; - player_two.position = 2; + player_one.last_move = Some(Move { + action: Action::Advance(Advance { + distance: 2, + cards: vec![], + }), + }); + state.update_player(player_one); + + // modify player two + let mut player_two = state.clone_other_player(); + player_two.last_move = Some(Move { + action: Action::Advance(Advance { + distance: 3, + cards: vec![], + }), + }); + state.update_player(player_two); + // test card let swap_carrots_card = Card::SwapCarrots; assert!(swap_carrots_card - .perform(&mut state, vec![Card::FallBack, Card::EatSalad]) + .perform(&mut state, vec![Card::FallBack, Card::EatSalad], 1) .is_ok()); let current_player = state.clone_current_player(); let other_player = state.clone_other_player(); assert_eq!(current_player.carrots, 60); - assert_eq!(other_player.carrots, 60); + assert_eq!(other_player.carrots, 30); } #[test] - fn test_swapcarrots_card_already_occurred_last_two_rounds() { + fn test_swapcarrots_card_bought_last_two_rounds() { let mut state = create_test_game_state(); + + // modify player one let mut player_one = state.clone_current_player(); - let mut player_two = state.clone_other_player(); - player_one.position = 3; - player_two.position = 2; player_one.last_move = Some(Move { action: Action::Advance(Advance { distance: 1, cards: vec![Card::SwapCarrots], }), }); + + state.update_player(player_one); + + // modify player two + let mut player_two = state.clone_other_player(); player_two.last_move = Some(Move { action: Action::Advance(Advance { - distance: 1, - cards: vec![Card::SwapCarrots], + distance: 3, + cards: vec![], }), }); + + state.update_player(player_two); + + // test card + let swap_carrots_card = Card::SwapCarrots; + assert!(swap_carrots_card + .perform(&mut state, vec![Card::FallBack, Card::EatSalad], 2) + .is_ok()); + let current_player = state.clone_current_player(); + let other_player = state.clone_other_player(); + assert_eq!(current_player.carrots, 60); + assert_eq!(other_player.carrots, 30); + } + + #[test] + fn test_swapcarrots_card_played_last_two_rounds() { + let mut state = create_test_game_state(); + + // modify player one + let mut player_one = state.clone_current_player(); + player_one.last_move = Some(Move { + action: Action::Advance(Advance { + distance: 2, + cards: vec![], + }), + }); + state.update_player(player_one); + + // modify player two + let mut player_two = state.clone_other_player(); + player_two.last_move = Some(Move { + action: Action::Advance(Advance { + distance: 3, + cards: vec![Card::SwapCarrots], + }), + }); + state.update_player(player_two); + // test card let swap_carrots_card = Card::SwapCarrots; - let result = swap_carrots_card.perform(&mut state, vec![Card::FallBack, Card::EatSalad]); - assert!(result.is_err()); + assert!(swap_carrots_card + .perform(&mut state, vec![Card::FallBack, Card::EatSalad], 1) + .is_err()); } #[test] @@ -124,7 +187,7 @@ mod tests { let mut state = create_test_game_state(); state.turn = 1; let card_not_owned = Card::FallBack; - let result = card_not_owned.perform(&mut state, vec![Card::HurryAhead]); + let result = card_not_owned.perform(&mut state, vec![Card::HurryAhead], 0); assert!(result.is_err()); } @@ -135,7 +198,7 @@ mod tests { let mut current_player = state.clone_current_player(); current_player.position = 1; state.update_player(current_player); - let result = card.perform(&mut state, vec![Card::EatSalad, Card::SwapCarrots]); + let result = card.perform(&mut state, vec![Card::EatSalad, Card::SwapCarrots], 0); assert!(result.is_err()); } @@ -144,7 +207,7 @@ mod tests { let mut state = create_test_game_state(); let invalid_card = Card::FallBack; state.board.track.clear(); - let result = invalid_card.perform(&mut state, vec![Card::EatSalad, Card::SwapCarrots]); + let result = invalid_card.perform(&mut state, vec![Card::EatSalad, Card::SwapCarrots], 0); assert!(result.is_err()); } @@ -156,7 +219,7 @@ mod tests { current_player.salads = 0; current_player.cards = vec![card]; state.update_player(current_player); - let result = card.perform(&mut state, vec![]); + let result = card.perform(&mut state, vec![], 0); assert!(result.is_err()); } }