Skip to content

Commit

Permalink
Address CR
Browse files Browse the repository at this point in the history
  • Loading branch information
arunsrinivas20 committed Jan 15, 2025
1 parent 48c8713 commit 80032b1
Show file tree
Hide file tree
Showing 44 changed files with 642 additions and 1,239 deletions.
107 changes: 92 additions & 15 deletions core/src/game_state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,15 +194,18 @@ impl Deref for GameState {
mod tests {
use crate::settings::{
AdvancementPolicy, FriendSelection, FriendSelectionPolicy, GameMode, GameModeSettings,
KittyTheftPolicy,
KittyTheftPolicy, BackToTwoSetting,
};

use shengji_mechanics::player::Player;
use shengji_mechanics::types::{cards, Card, Number, PlayerID, Rank, FULL_DECK};
use shengji_mechanics::types::{cards, Card, Number, PlayerID, Rank, FULL_DECK, Trump, Suit};

use crate::game_state::{initialize_phase::InitializePhase, play_phase::PlayPhase};
use crate::message::MessageVariant;

use shengji_mechanics::trick::{PlayCards, TractorRequirements, ThrowEvaluationPolicy, Trick, TrickDrawPolicy};
use shengji_mechanics::hands::Hands;

const R2: Rank = Rank::Number(Number::Two);
const R3: Rank = Rank::Number(Number::Three);
const R4: Rank = Rank::Number(Number::Four);
Expand All @@ -218,6 +221,31 @@ mod tests {
const RA: Rank = Rank::Number(Number::Ace);
const RNT: Rank = Rank::NoTrump;

const P1: PlayerID = PlayerID(0);
const P2: PlayerID = PlayerID(1);
const P3: PlayerID = PlayerID(2);
const P4: PlayerID = PlayerID(3);

macro_rules! pc {
($id:expr, $hands:expr, $cards:expr) => {
PlayCards {
id: $id,
hands: $hands,
cards: $cards,
trick_draw_policy: TrickDrawPolicy::NoProtections,
throw_eval_policy: ThrowEvaluationPolicy::All,
format_hint: None,
hide_throw_halting_player: false,
tractor_requirements: TractorRequirements::default(),
}
};
}

const JACK_TRUMP: Trump = Trump::Standard {
number: Number::Jack,
suit: Suit::Spades,
};

fn init_players() -> Vec<Player> {
vec![
Player {
Expand Down Expand Up @@ -289,7 +317,8 @@ mod tests {
(PlayerID(0), starting_rank),
advance_policy,
RNT,
false,
None,
BackToTwoSetting::Disabled,
);
let ranks = p.iter().map(|pp| pp.rank()).collect::<Vec<Rank>>();
assert_eq!(
Expand Down Expand Up @@ -341,7 +370,8 @@ mod tests {
(PlayerID(0), starting_rank),
advance_policy,
RA,
false,
None,
BackToTwoSetting::Disabled,
);
let ranks = p.iter().map(|pp| pp.rank()).collect::<Vec<Rank>>();
assert_eq!(
Expand Down Expand Up @@ -414,7 +444,8 @@ mod tests {
(PlayerID(0), starting_rank),
advance_policy,
RNT,
false,
None,
BackToTwoSetting::Disabled,
);
let ranks = p.iter().map(|pp| pp.rank()).collect::<Vec<Rank>>();
assert_eq!(
Expand Down Expand Up @@ -482,7 +513,8 @@ mod tests {
(PlayerID(0), p0_rank),
advance_policy,
RNT,
false,
None,
BackToTwoSetting::Disabled,
);
let ranks = p.iter().map(|pp| pp.rank()).collect::<Vec<Rank>>();
assert_eq!(
Expand All @@ -509,7 +541,8 @@ mod tests {
(PlayerID(0), p0_rank),
AdvancementPolicy::Unrestricted,
RNT,
false,
None,
BackToTwoSetting::Disabled,
);
let ranks = p.iter().map(|pp| pp.rank()).collect::<Vec<Rank>>();
assert_eq!(ranks, vec![R4, R2, RNT, R2],);
Expand All @@ -527,7 +560,8 @@ mod tests {
(PlayerID(0), p0_rank),
AdvancementPolicy::Unrestricted,
RNT,
false,
None,
BackToTwoSetting::Disabled,
);
let ranks = p.iter().map(|pp| pp.rank()).collect::<Vec<Rank>>();
assert_eq!(ranks, vec![R3, R2, R3, R2],);
Expand All @@ -547,7 +581,8 @@ mod tests {
(PlayerID(0), R5),
AdvancementPolicy::Unrestricted,
RNT,
false,
None,
BackToTwoSetting::Disabled,
);
for p in &players {
assert_eq!(p.rank(), Rank::Number(Number::Four));
Expand All @@ -563,7 +598,8 @@ mod tests {
(PlayerID(0), Rank::Number(Number::Ace)),
AdvancementPolicy::DefendPoints,
RNT,
false,
None,
BackToTwoSetting::Disabled,
);
for p in &players {
assert_eq!(p.rank(), R5);
Expand All @@ -580,7 +616,8 @@ mod tests {
(PlayerID(0), RA),
AdvancementPolicy::DefendPoints,
RNT,
false,
None,
BackToTwoSetting::Disabled,
);
for p in &players {
if p.id == PlayerID(0) || p.id == PlayerID(2) {
Expand All @@ -601,7 +638,8 @@ mod tests {
(PlayerID(0), Rank::Number(Number::Ace)),
AdvancementPolicy::DefendPoints,
RNT,
false,
None,
BackToTwoSetting::Disabled,
);

for p in &players {
Expand All @@ -615,7 +653,19 @@ mod tests {

#[test]
fn test_jack_variation_landlord_loses() {
use cards::*;

let mut players = init_players();
let mut hands = Hands::new(vec![P1, P2, P3, P4]);
hands.add(P1, vec![S_2]).unwrap();
hands.add(P2, vec![S_J]).unwrap();
hands.add(P3, vec![S_2]).unwrap();
hands.add(P4, vec![S_3]).unwrap();
let mut trick = Trick::new(JACK_TRUMP, vec![P1, P2, P3, P4]);
trick.play_cards(pc!(P1, &mut hands, &[S_2])).unwrap();
trick.play_cards(pc!(P2, &mut hands, &[S_J])).unwrap();
trick.play_cards(pc!(P3, &mut hands, &[S_2])).unwrap();
trick.play_cards(pc!(P4, &mut hands, &[S_3])).unwrap();

// Neither side levels up, but the non-landlord team wins the final trick with
// a single jack
Expand All @@ -628,7 +678,8 @@ mod tests {
(PlayerID(0), Rank::Number(Number::Jack)),
AdvancementPolicy::DefendPoints,
RNT,
true,
Some(trick),
BackToTwoSetting::SingleJack,
);

for p in &players {
Expand All @@ -638,7 +689,19 @@ mod tests {

#[test]
fn test_jack_variation_landlord_advances_multiple() {
use cards::*;

let mut players = init_players();
let mut hands = Hands::new(vec![P1, P2, P3, P4]);
hands.add(P1, vec![S_2]).unwrap();
hands.add(P2, vec![S_J]).unwrap();
hands.add(P3, vec![S_2]).unwrap();
hands.add(P4, vec![S_3]).unwrap();
let mut trick = Trick::new(JACK_TRUMP, vec![P1, P2, P3, P4]);
trick.play_cards(pc!(P1, &mut hands, &[S_2])).unwrap();
trick.play_cards(pc!(P2, &mut hands, &[S_J])).unwrap();
trick.play_cards(pc!(P3, &mut hands, &[S_2])).unwrap();
trick.play_cards(pc!(P4, &mut hands, &[S_3])).unwrap();

// The landlord team defends, but the non-landlord team wins the final trick with
// a single jack
Expand All @@ -651,7 +714,8 @@ mod tests {
(PlayerID(0), Rank::Number(Number::Jack)),
AdvancementPolicy::DefendPoints,
RNT,
true,
Some(trick),
BackToTwoSetting::SingleJack,
);

for p in &players {
Expand All @@ -665,7 +729,19 @@ mod tests {

#[test]
fn test_jack_variation_non_landlord_advances() {
use cards::*;

let mut players = init_players();
let mut hands = Hands::new(vec![P1, P2, P3, P4]);
hands.add(P1, vec![S_2]).unwrap();
hands.add(P2, vec![S_J]).unwrap();
hands.add(P3, vec![S_2]).unwrap();
hands.add(P4, vec![S_3]).unwrap();
let mut trick = Trick::new(JACK_TRUMP, vec![P1, P2, P3, P4]);
trick.play_cards(pc!(P1, &mut hands, &[S_2])).unwrap();
trick.play_cards(pc!(P2, &mut hands, &[S_J])).unwrap();
trick.play_cards(pc!(P3, &mut hands, &[S_2])).unwrap();
trick.play_cards(pc!(P4, &mut hands, &[S_3])).unwrap();

// The non-landlord team advances and they win the final trick with
// a single jack
Expand All @@ -678,7 +754,8 @@ mod tests {
(PlayerID(0), Rank::Number(Number::Jack)),
AdvancementPolicy::DefendPoints,
RNT,
true,
Some(trick),
BackToTwoSetting::SingleJack,
);

for p in &players {
Expand Down
79 changes: 40 additions & 39 deletions core/src/game_state/play_phase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ use shengji_mechanics::hands::Hands;
use shengji_mechanics::player::Player;
use shengji_mechanics::scoring::{compute_level_deltas, next_threshold_reachable, GameScoreResult};
use shengji_mechanics::trick::{PlayCards, PlayCardsMessage, Trick, TrickEnded, TrickUnit, PlayedCards};
use shengji_mechanics::types::{Card, PlayerID, Rank, Trump, Number};
use shengji_mechanics::types::{Card, PlayerID, Rank, Trump};

use crate::message::MessageVariant;
use crate::settings::{
AdvancementPolicy, GameMode, KittyPenalty, MultipleJoinPolicy, PlayTakebackPolicy,
PropagatedState, ThrowPenalty,
PropagatedState, ThrowPenalty, BackToTwoSetting,
};

use crate::game_state::initialize_phase::InitializePhase;
Expand Down Expand Up @@ -238,8 +238,6 @@ impl PlayPhase {
failed_throw_size,
} = self.trick.complete()?;

println!("{:?}", self.trick.played_cards());

let kitty_multipler = match self.propagated.kitty_penalty {
KittyPenalty::Times => 2 * largest_trick_unit_size,
KittyPenalty::Power => 2usize.pow(largest_trick_unit_size as u32),
Expand Down Expand Up @@ -362,10 +360,13 @@ impl PlayPhase {
landlord: (PlayerID, Rank),
advancement_policy: AdvancementPolicy,
max_rank: Rank,
lost_on_single_jack: bool,
last_trick: Option<Trick>,
jack_variation: BackToTwoSetting,
) -> Vec<MessageVariant> {
let mut msgs = vec![];

let should_go_back_to_two = Self::check_jacks_last_trick(last_trick, jack_variation, landlords_team, landlord.1);

let result = players
.map(|player| {
let is_defending = landlords_team.contains(&player.id);
Expand All @@ -376,10 +377,7 @@ impl PlayPhase {
};
let mut num_advances = 0;
let mut was_blocked = false;
// If the landlord team lost the final trick with a single jack, then they will go back to Rank 2,
// regardless of whether or not they successfully defended or not. If they successfully defended,
// then the level bumps will still apply.
if is_defending && lost_on_single_jack {
if is_defending && should_go_back_to_two {
player.reset_rank();
};
let initial_rank = player.rank();
Expand Down Expand Up @@ -455,6 +453,37 @@ impl PlayPhase {
msgs
}

pub fn check_jacks_last_trick<'a>(
last_trick: Option<Trick>,
jack_variation: BackToTwoSetting,
landlords_team: &'a [PlayerID],
landlord_rank: Rank) -> bool {
if !jack_variation.is_applicable(landlord_rank) {
return false
}

let last_trick = last_trick.unwrap();
let TrickEnded {
winner: winner_pid,
..
} = last_trick.complete().unwrap();

// In any jack variation, the rule can only applies if the non-landord team wins the
// last trick
if landlords_team.contains(&winner_pid) {
return false
}

let lt_played_cards = last_trick.played_cards();
let PlayedCards {
cards,
..
} = lt_played_cards.iter().find(|pc| pc.id == winner_pid).unwrap();

// In the jack variation, the last trick must be won with a single (trump) jack
return jack_variation.compute(cards);
}

pub fn calculate_points(&self) -> (isize, isize) {
let mut non_landlords_points: isize = self
.points
Expand Down Expand Up @@ -568,7 +597,8 @@ impl PlayPhase {
(self.landlord, self.propagated.players[landlord_idx].level),
propagated.advancement_policy,
*propagated.max_rank,
self.check_jacks_last_trick(),
self.last_trick.clone(),
self.propagated.jack_variation,
));

let mut idx = (landlord_idx + 1) % propagated.players.len();
Expand Down Expand Up @@ -631,35 +661,6 @@ impl PlayPhase {
Ok((InitializePhase::from_propagated(propagated), msgs))
}

fn check_jacks_last_trick(&self) -> bool {
// When playing with the jacks variation, the trump number has to be Jack, so we can
// return early otherwise
if !(self.propagated.jack_variation && self.trump.number() == Some(Number::Jack)) {
return false
}

let last_trick = self.last_trick.clone().unwrap();
let TrickEnded {
winner: winner_pid,
..
} = last_trick.complete().unwrap();

// In the jack variation, the rule can only applies if the non-landord team wins the
// last trick
if self.landlords_team.contains(&winner_pid) {
return false
}

let lt_played_cards = last_trick.played_cards();
let PlayedCards {
cards,
..
} = lt_played_cards.iter().find(|pc| pc.id == winner_pid).unwrap();

// In the jack variation, the last trick must be won with a single (trump) jack
return cards.len() == 1 && cards[0].number() == Some(Number::Jack);
}

pub fn destructively_redact_for_player(&mut self, player: PlayerID) {
if self.propagated.hide_landlord_points {
for (k, v) in self.points.iter_mut() {
Expand Down
4 changes: 2 additions & 2 deletions core/src/interactive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::settings::{
AdvancementPolicy, FirstLandlordSelectionPolicy, FriendSelection, FriendSelectionPolicy,
GameModeSettings, GameShadowingPolicy, GameStartPolicy, GameVisibility, KittyBidPolicy,
KittyPenalty, KittyTheftPolicy, MultipleJoinPolicy, PlayTakebackPolicy, PropagatedState,
ThrowPenalty,
ThrowPenalty, BackToTwoSetting,
};
pub struct InteractiveGame {
state: GameState,
Expand Down Expand Up @@ -461,7 +461,7 @@ pub enum Action {
SetGameStartPolicy(GameStartPolicy),
SetShouldRevealKittyAtEndOfGame(bool),
SetHideThrowHaltingPlayer(bool),
SetJackVariation(bool),
SetJackVariation(BackToTwoSetting),
SetTractorRequirements(TractorRequirements),
SetGameVisibility(GameVisibility),
StartGame,
Expand Down
Loading

0 comments on commit 80032b1

Please sign in to comment.