mirror of
https://github.com/Vale54321/schafkop-neu.git
synced 2025-12-13 10:39:33 +01:00
add gamemode adn basic winning card methode
This commit is contained in:
1
schafkopf-logic/.gitignore
vendored
1
schafkopf-logic/.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
target
|
target
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
|
shell.nix
|
||||||
@@ -10,6 +10,6 @@ pub struct Card {
|
|||||||
|
|
||||||
impl fmt::Display for Card {
|
impl fmt::Display for Card {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{} {}", self.rank, self.suit)
|
write!(f, "{} {}", self.suit, self.rank)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
135
schafkopf-logic/src/gamemode.rs
Normal file
135
schafkopf-logic/src/gamemode.rs
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
use crate::deck::{Card, Suit, Rank};
|
||||||
|
|
||||||
|
pub enum Gamemode {
|
||||||
|
Sauspiel(Suit),
|
||||||
|
Solo(Suit),
|
||||||
|
Wenz(Suit),
|
||||||
|
Geier(Suit),
|
||||||
|
Bettel,
|
||||||
|
Ramsch
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Gamemode {
|
||||||
|
pub fn winning_card<'a>(&self, cards: [&'a Card; 4]) -> &'a Card {
|
||||||
|
match self {
|
||||||
|
Gamemode::Sauspiel(_) | Gamemode::Ramsch | Gamemode::Bettel =>
|
||||||
|
winner_for_trump(Suit::Herz, cards),
|
||||||
|
Gamemode::Solo(solo_suit) => winner_for_trump(*solo_suit, cards),
|
||||||
|
_ => cards[0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn winner_for_trump<'a>(trump_suit: Suit, cards: [&'a Card; 4]) -> &'a Card {
|
||||||
|
if cards.iter().any(|&c| is_trump(c, trump_suit)) {
|
||||||
|
// Highest trump wins
|
||||||
|
let winner_idx = cards
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|&(_, &c)| is_trump(c, trump_suit))
|
||||||
|
.max_by_key(|&(_, &c)| trump_strength(c, trump_suit))
|
||||||
|
.map(|(i, _)| i)
|
||||||
|
.unwrap_or(0);
|
||||||
|
cards[winner_idx]
|
||||||
|
} else {
|
||||||
|
// No trump: highest of the led suit wins
|
||||||
|
let first_suit = cards[0].suit;
|
||||||
|
let winner_idx = cards
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|&(_, &c)| c.suit == first_suit)
|
||||||
|
.max_by_key(|&(_, &c)| non_trump_strength(c.rank))
|
||||||
|
.map(|(i, _)| i)
|
||||||
|
.unwrap_or(0);
|
||||||
|
cards[winner_idx]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A card is trump in Sauspiel if it's an Ober, an Unter, or of the trump suit.
|
||||||
|
fn is_trump(card: &Card, trump_suit: Suit) -> bool {
|
||||||
|
card.rank == Rank::Ober || card.rank == Rank::Unter || card.suit == trump_suit
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trump strength according to Schafkopf:
|
||||||
|
// Obers: Eichel > Gras > Herz > Schell
|
||||||
|
// Unters: Eichel > Gras > Herz > Schell
|
||||||
|
// Then trump suit cards: A > 10 > K > 9 > 8 > 7
|
||||||
|
fn trump_strength(card: &Card, trump_suit: Suit) -> u16 {
|
||||||
|
match card.rank {
|
||||||
|
Rank::Ober => 300 + ober_unter_suit_strength(card.suit),
|
||||||
|
Rank::Unter => 200 + ober_unter_suit_strength(card.suit),
|
||||||
|
_ if card.suit == trump_suit => 100 + non_trump_strength(card.rank) as u16,
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Suit precedence for Obers/Unters: Eichel > Gras > Herz > Schell
|
||||||
|
fn ober_unter_suit_strength(s: Suit) -> u16 {
|
||||||
|
match s {
|
||||||
|
Suit::Eichel => 4,
|
||||||
|
Suit::Gras => 3,
|
||||||
|
Suit::Herz => 2,
|
||||||
|
Suit::Schell => 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-trump (following suit) strength: A > 10 > K > 9 > 8 > 7
|
||||||
|
fn non_trump_strength(rank: Rank) -> u8 {
|
||||||
|
match rank {
|
||||||
|
Rank::Ass => 6,
|
||||||
|
Rank::Zehn => 5,
|
||||||
|
Rank::Koenig => 4,
|
||||||
|
Rank::Neun => 3,
|
||||||
|
Rank::Acht => 2,
|
||||||
|
Rank::Sieben => 1,
|
||||||
|
_ => 0, // Ober/Unter are trumps, handled elsewhere
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::deck::{Card, Suit, Rank};
|
||||||
|
|
||||||
|
fn card(suit: Suit, rank: Rank) -> Card {
|
||||||
|
Card { suit, rank }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sauspiel_trump_beats_non_trump() {
|
||||||
|
// In Sauspiel, trumps are all Obers, all Unters, and Herz.
|
||||||
|
let c0 = card(Suit::Eichel, Rank::Ass); // lead (non-trump)
|
||||||
|
let c1 = card(Suit::Gras, Rank::Ober); // trump (Ober)
|
||||||
|
let c2 = card(Suit::Herz, Rank::Zehn); // trump (Herz suit)
|
||||||
|
let c3 = card(Suit::Gras, Rank::Ass); // non-trump
|
||||||
|
|
||||||
|
let winner = Gamemode::Sauspiel(Suit::Eichel).winning_card([&c0, &c1, &c2, &c3]);
|
||||||
|
// Ober beats Herz trumps due to higher trump tier
|
||||||
|
assert_eq!(winner, &c1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sauspiel_follow_suit_highest_non_trump_when_no_trumps() {
|
||||||
|
// No Obers/Unters and no Herz => follow led suit, highest wins (A > 10 > K > 9 > 8 > 7)
|
||||||
|
let c0 = card(Suit::Eichel, Rank::Koenig); // lead
|
||||||
|
let c1 = card(Suit::Gras, Rank::Ass);
|
||||||
|
let c2 = card(Suit::Eichel, Rank::Ass); // same suit as lead, highest
|
||||||
|
let c3 = card(Suit::Schell, Rank::Zehn);
|
||||||
|
|
||||||
|
let winner = Gamemode::Sauspiel(Suit::Gras).winning_card([&c0, &c1, &c2, &c3]);
|
||||||
|
assert_eq!(winner, &c2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn solo_uses_declared_suit_as_trump() {
|
||||||
|
// In Solo(Gras), trumps are all Obers, all Unters, and all Gras.
|
||||||
|
// Avoid Obers/Unters to focus on the solo suit behaving as trump.
|
||||||
|
let c0 = card(Suit::Herz, Rank::Koenig); // lead
|
||||||
|
let c1 = card(Suit::Gras, Rank::Zehn); // trump (solo suit)
|
||||||
|
let c2 = card(Suit::Eichel, Rank::Ass);
|
||||||
|
let c3 = card(Suit::Schell, Rank::Ass);
|
||||||
|
|
||||||
|
let winner = Gamemode::Solo(Suit::Gras).winning_card([&c0, &c1, &c2, &c3]);
|
||||||
|
assert_eq!(winner, &c1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
mod deck;
|
mod deck;
|
||||||
use deck::Deck;
|
mod gamemode;
|
||||||
|
|
||||||
|
use deck::{Deck, Suit, Card, Rank};
|
||||||
|
use gamemode::Gamemode;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut deck = Deck::new();
|
let mut deck = Deck::new();
|
||||||
@@ -26,4 +29,23 @@ fn main() {
|
|||||||
for card in hand4.iter() {
|
for card in hand4.iter() {
|
||||||
println!("{}", card)
|
println!("{}", card)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mode = Gamemode::Solo(Suit::Gras);
|
||||||
|
|
||||||
|
//let trick: [&Card; 4] = [&hand1[0], &hand2[0], &hand3[0], &hand4[0]];
|
||||||
|
let c1 = Card { suit: Suit::Schell, rank: Rank::Zehn };
|
||||||
|
let c2 = Card { suit: Suit::Schell, rank: Rank::Ass };
|
||||||
|
let c3 = Card { suit: Suit::Schell, rank: Rank::Unter };
|
||||||
|
let c4 = Card { suit: Suit::Gras, rank: Rank::Sieben };
|
||||||
|
|
||||||
|
let trick: [&Card; 4] = [&c1, &c2, &c3, &c4];
|
||||||
|
|
||||||
|
|
||||||
|
for card in trick.iter() {
|
||||||
|
println!("{}", card)
|
||||||
|
}
|
||||||
|
println!("\n");
|
||||||
|
|
||||||
|
let winner = mode.winning_card(trick);
|
||||||
|
println!("\nWinning card: {}", winner);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user