Use player names in two-player briscola

Classic briscola has no partnerships: its "teams" are just the two
players, but the UI labelled them Team A/Team B.

- add is_individual_game() and GameView::player_name_for_team() to the
  model;
- the briscola table HUD reads "Alice 0 — 0 Bob (target 61)" and the
  seat panels drop the Team badge for two-player games;
- the deal summary and game-over screen name the sides and the winner;
- the waiting room and join preview hide the Team badge.

briscola a quattro and scopone keep their team labels, and the match
history table is unchanged.
This commit is contained in:
2026-10-06 17:37:55 +08:00
parent 6222e38da3
commit b821274f0b
5 changed files with 121 additions and 27 deletions
+44
View File
@@ -229,6 +229,18 @@ pub struct GameView {
pub last_deal: Option<DealSummary>,
}
impl GameView {
/// Display name of the player on team `team` ("A"/"B"), for games
/// without partnerships; falls back to the team label itself.
pub fn player_name_for_team(&self, team: &str) -> String {
self.players
.iter()
.find(|p| p.team == team)
.map(|p| p.name.clone())
.unwrap_or_else(|| team.to_string())
}
}
#[derive(Debug, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
#[allow(dead_code)]
@@ -663,6 +675,13 @@ pub fn is_briscola(game_type: &str) -> bool {
game_type == "briscola" || game_type == "briscola_a_quattro"
}
/// Whether a game is played by two individuals rather than partnerships
/// (classic two-player briscola): team labels and team messages are
/// replaced by the players' names.
pub fn is_individual_game(game_type: &str) -> bool {
game_type == "briscola"
}
/// Human-readable suit name for a one-letter code (`D` -> "denari").
pub fn suit_name(suit: &str) -> String {
match suit {
@@ -1174,6 +1193,31 @@ mod tests {
assert_eq!("?", suit_name("?"));
}
#[test]
fn is_individual_game_only_matches_two_player_briscola() {
assert!(is_individual_game("briscola"));
assert!(!is_individual_game("briscola_a_quattro"));
assert!(!is_individual_game("scopone_scientifico"));
}
#[test]
fn player_name_for_team_resolves_names() {
let g: GameView = serde_json::from_value(json!({
"id": "b1",
"game_type": "briscola",
"phase": "playing",
"players": [
{"sub": "alice", "name": "Alice", "seat": 0, "team": "A"},
{"sub": "bob", "name": "Bob", "seat": 1, "team": "B"},
],
}))
.unwrap();
assert_eq!("Alice", g.player_name_for_team("A"));
assert_eq!("Bob", g.player_name_for_team("B"));
// Unknown labels fall back to the label itself.
assert_eq!("C", g.player_name_for_team("C"));
}
#[test]
fn fallback_game_types_cover_the_registered_games() {
let types = fallback_game_types();