//! A populated `GroundView`, built for the coverage gate. //! //! Mid-DARVO, mid-GROUND, scored — **not** a fresh deal. Most of the //! fields this gate exists to cover are empty at deal time, and a coverage //! test run against a state where the fields are absent is the same lie in //! a different costume (CB-WP-0011 T01). //! //! Built directly rather than projected from a `GroundState`. The //! projection's own hiding rules are already asserted by //! `games_ground::view` and by `cb-play`'s //! `the_inspector_never_widens_the_projection`; re-asserting them here //! would be a duplicated fact that drifts. What *this* crate must not do //! is invent a hand it was never given, and that is what the renderer test //! checks — with `hand: None` supplied deliberately. use std::collections::BTreeMap; use cb_kernel::PlayerId; use games_ground::view::{GroundView, OutcomeView, PlayerView, ProblemView, SelectionView}; use games_ground::{ Action, Coalition, DarvoStage, DarvoTarget, GroundChoice, GroundMode, Pair, Relation, RoundStep, ScoringMode, Selection, SolutionCard, Suit, SupportResponse, }; pub fn seats() -> (PlayerId, PlayerId, PlayerId) { (PlayerId(0), PlayerId(1), PlayerId(2)) } /// The fixture, seen by `viewer` (`None` for a spectator). pub fn view(viewer: Option) -> GroundView { let (p1, p2, p3) = seats(); let card = |suit| SolutionCard { suit }; let mut players = BTreeMap::new(); for (id, stress, protection, darvo, ready, lifted, blame) in [ (p1, 5u8, 2u8, DarvoStage::Reverse, true, true, vec![p3]), (p2, 1, 0, DarvoStage::Off, false, false, vec![]), (p3, 0, 0, DarvoStage::Deny, true, false, vec![]), ] { let own = viewer == Some(id); players.insert( id, PlayerView { stress, freedom_ready: ready, freedom_gate_lifted: lifted, darvo, protection, blame_from: blame, hand: own.then(|| vec![card(Suit::Clarify), card(Suit::Boundary)]), hand_size: 2, }, ); } let mut problems = BTreeMap::new(); problems.insert(1, ProblemView::FaceDown); // CB-WP-0043: a third Problem so all three H2 scopes are drawn — // global (1), personal (6) and bond (7). Two would leave one // placement rule unexercised and the coverage probe unsatisfiable. problems.insert(6, ProblemView::FaceDown); problems.insert( 7, ProblemView::FaceUp { suit: Suit::Change, value: 6, denied: true, claimed_by: Some(p2), protected_this_round: true, }, ); GroundView { viewer, round: 3, lead: p2, step: RoundStep::Select, mode: ScoringMode::BondedCoalitions, scenario: "SCN_03".into(), players, relations: BTreeMap::from([ (Pair::new(p1, p2), Relation::Rivalry), (Pair::new(p2, p3), Relation::Bond), ]), problems, config: games_ground::config::Configuration::default(), focus: BTreeMap::from([(p1, p3)]), selections: BTreeMap::from([ ( p1, SelectionView::Shown(Selection { action: Action::Attack, target: Some(p2), problem: Some(7), }), ), (p2, SelectionView::Hidden), // CB-WP-0034: P3 offered P2 their Support, revealed. The // fixture now carries the case the report was about, so the // coverage probe for `support_responses` can name a SEAT // rather than a response with nobody attached to it. ( p3, SelectionView::Shown(Selection { action: Action::Support, target: Some(p2), problem: None, }), ), ]), // CB-WP-0043: the fixture carries H2 markers, so the scoped // layout is exercised — a fixture with none would leave the new // placement untested and the row layout would always be taken. problem_markers: BTreeMap::from([ ( 1, games_ground::view::ProblemMarker { owner: None, scope: Some(games_ground::edition::StressScope::Global), }, ), ( 6, games_ground::view::ProblemMarker { owner: Some(p1), scope: Some(games_ground::edition::StressScope::Personal), }, ), ( 7, games_ground::view::ProblemMarker { owner: Some(p2), scope: Some(games_ground::edition::StressScope::Bond), }, ), ]), ground_modes: BTreeMap::from([(p3, GroundMode::Gr)]), ground_choices: BTreeMap::from([(p3, GroundChoice::ProtectProblem { problem: 7 })]), support_responses: BTreeMap::from([(p2, SupportResponse::AcceptBond)]), darvo_targets: BTreeMap::from([( p3, DarvoTarget { problem: Some(1), player: Some(p2), }, )]), solution_deck_len: 17, solution_discard: vec![card(Suit::Repair), card(Suit::Change)], outcome: Some(OutcomeView { total: 9, threshold: 12, group_success: false, personal: BTreeMap::from([(p1, 3), (p2, -1), (p3, 0)]), coalitions: vec![Coalition { members: vec![p2, p3], score: 4, }], mastery: Some(1), winners: vec![p1], }), } }