|
|
|
@@ -2,7 +2,7 @@ |
|
|
|
|
|
|
|
module Skat.Bidding ( |
|
|
|
biddingScore, Game(..), Modifier(..), isHand, getTrump, Result(..), |
|
|
|
getResults, isOuvert, isSchwarz |
|
|
|
getResults, isOuvert, isSchwarz, Bid, checkGame, HideGame(..) |
|
|
|
) where |
|
|
|
|
|
|
|
import Data.Aeson hiding (Null, Result) |
|
|
|
@@ -13,6 +13,8 @@ import Data.Ord (Down(..)) |
|
|
|
import Control.Monad |
|
|
|
import Skat.Pile |
|
|
|
|
|
|
|
type Bid = Int |
|
|
|
|
|
|
|
-- | different game types |
|
|
|
data Game = Colour Colour Modifier |
|
|
|
| Grand Modifier |
|
|
|
@@ -22,6 +24,9 @@ data Game = Colour Colour Modifier |
|
|
|
| NullOuvertHand |
|
|
|
deriving (Show, Eq) |
|
|
|
|
|
|
|
newtype HideGame = HideGame Game |
|
|
|
deriving (Show, Eq) |
|
|
|
|
|
|
|
instance ToJSON Game where |
|
|
|
toJSON (Grand mod) = |
|
|
|
object ["game" .= ("grand" :: String), "modifier" .= show mod] |
|
|
|
@@ -32,6 +37,13 @@ instance ToJSON Game where |
|
|
|
toJSON NullOuvert = object ["game" .= ("nullouvert" :: String)] |
|
|
|
toJSON NullOuvertHand = object ["game" .= ("nullouverthand" :: String)] |
|
|
|
|
|
|
|
instance ToJSON HideGame where |
|
|
|
toJSON (HideGame (Grand mod)) = |
|
|
|
object ["game" .= ("grand" :: String), "modifier" .= prettyShow mod] |
|
|
|
toJSON (HideGame (Colour col mod)) = |
|
|
|
object ["game" .= ("colour" :: String), "modifier" .= prettyShow mod, "colour" .= show col] |
|
|
|
toJSON (HideGame game) = toJSON game |
|
|
|
|
|
|
|
instance FromJSON Game where |
|
|
|
parseJSON = withObject "Game" $ \v -> do |
|
|
|
gamekind <- v .: "game" |
|
|
|
@@ -56,7 +68,7 @@ data Modifier = Einfach |
|
|
|
| Hand |
|
|
|
| HandSchneider |
|
|
|
| HandSchneiderAngesagt |
|
|
|
| HandSchneiderSchwarz |
|
|
|
| HandSchwarz |
|
|
|
| HandSchneiderAngesagtSchwarz |
|
|
|
| HandSchwarzAngesagt |
|
|
|
| Ouvert |
|
|
|
@@ -76,11 +88,26 @@ instance FromJSON Modifier where |
|
|
|
_ -> return Hand |
|
|
|
else return Einfach |
|
|
|
|
|
|
|
isHand :: Modifier -> Bool |
|
|
|
isHand Einfach = False |
|
|
|
isHand Schneider = False |
|
|
|
isHand Schwarz = False |
|
|
|
isHand _ = True |
|
|
|
prettyShow :: Modifier -> String |
|
|
|
prettyShow Schneider = show Einfach |
|
|
|
prettyShow Schwarz = show Einfach |
|
|
|
prettyShow HandSchneider = show Hand |
|
|
|
prettyShow HandSchwarz = show Hand |
|
|
|
prettyShow HandSchneiderAngesagtSchwarz = show HandSchneiderAngesagt |
|
|
|
prettyShow mod = show mod |
|
|
|
|
|
|
|
isHand :: Game -> Bool |
|
|
|
isHand NullHand = True |
|
|
|
isHand NullOuvertHand = True |
|
|
|
isHand (Colour _ mod) = modIsHand mod |
|
|
|
isHand (Grand mod) = modIsHand mod |
|
|
|
isHand _ = False |
|
|
|
|
|
|
|
modIsHand :: Modifier -> Bool |
|
|
|
modIsHand Einfach = False |
|
|
|
modIsHand Schneider = False |
|
|
|
modIsHand Schwarz = False |
|
|
|
modIsHand _ = True |
|
|
|
|
|
|
|
isOuvert :: Game -> Bool |
|
|
|
isOuvert NullOuvert = True |
|
|
|
@@ -89,6 +116,17 @@ isOuvert (Grand Ouvert) = True |
|
|
|
isOuvert (Colour _ Ouvert) = True |
|
|
|
isOuvert _ = False |
|
|
|
|
|
|
|
baseFactor :: Game -> Int |
|
|
|
baseFactor (Grand _) = 24 |
|
|
|
baseFactor (Colour Clubs _) = 12 |
|
|
|
baseFactor (Colour Spades _) = 11 |
|
|
|
baseFactor (Colour Hearts _) = 10 |
|
|
|
baseFactor (Colour Diamonds _) = 9 |
|
|
|
baseFactor Null = 23 |
|
|
|
baseFactor NullHand = 35 |
|
|
|
baseFactor NullOuvert = 46 |
|
|
|
baseFactor NullOuvertHand = 59 |
|
|
|
|
|
|
|
-- | calculate the value of a game with given cards |
|
|
|
biddingScore :: HasCard c => Game -> [c] -> Int |
|
|
|
biddingScore game@(Grand mod) cards = (spitzen game cards + modifierFactor mod) * 24 |
|
|
|
@@ -96,10 +134,7 @@ biddingScore game@(Colour Clubs mod) cards = (spitzen game cards + modifierFa |
|
|
|
biddingScore game@(Colour Spades mod) cards = (spitzen game cards + modifierFactor mod) * 11 |
|
|
|
biddingScore game@(Colour Hearts mod) cards = (spitzen game cards + modifierFactor mod) * 10 |
|
|
|
biddingScore game@(Colour Diamonds mod) cards = (spitzen game cards + modifierFactor mod) * 9 |
|
|
|
biddingScore Null _ = 23 |
|
|
|
biddingScore NullHand _ = 35 |
|
|
|
biddingScore NullOuvert _ = 46 |
|
|
|
biddingScore NullOuvertHand _ = 59 |
|
|
|
biddingScore game _ = baseFactor game |
|
|
|
|
|
|
|
-- | calculate the modifier based on the game kind |
|
|
|
modifierFactor :: Modifier -> Int |
|
|
|
@@ -109,7 +144,7 @@ modifierFactor Schwarz = 3 |
|
|
|
modifierFactor Hand = 2 |
|
|
|
modifierFactor HandSchneider = 3 |
|
|
|
modifierFactor HandSchneiderAngesagt = 4 |
|
|
|
modifierFactor HandSchneiderSchwarz = 4 |
|
|
|
modifierFactor HandSchwarz = 4 |
|
|
|
modifierFactor HandSchneiderAngesagtSchwarz = 5 |
|
|
|
modifierFactor HandSchwarzAngesagt = 6 |
|
|
|
modifierFactor Ouvert = 7 |
|
|
|
@@ -173,16 +208,36 @@ hasWon (Grand mod) ps = let (b, mod') = meetsCall mod ps |
|
|
|
meetsCall :: Modifier -> Piles -> (Bool, Modifier) |
|
|
|
meetsCall Hand ps = case wonByPoints ps of |
|
|
|
(b, Schneider) -> (b, HandSchneider) |
|
|
|
(b, Schwarz) -> (b, HandSchneiderSchwarz) |
|
|
|
(b, Schwarz) -> (b, HandSchwarz) |
|
|
|
(b, Einfach) -> (b, Hand) |
|
|
|
meetsCall Schneider ps = case wonByPoints ps of |
|
|
|
(b, Schneider) -> (b, Schneider) |
|
|
|
(b, Schwarz) -> (b, Schwarz) |
|
|
|
(b, Einfach) -> (False, Schneider) |
|
|
|
meetsCall Schwarz ps = case wonByPoints ps of |
|
|
|
(b, Schneider) -> (False, Schwarz) |
|
|
|
(b, Schwarz) -> (b, Schwarz) |
|
|
|
(b, Einfach) -> (False, Schwarz) |
|
|
|
meetsCall HandSchneider ps = case wonByPoints ps of |
|
|
|
(b, Schneider) -> (b, HandSchneider) |
|
|
|
(b, Schwarz) -> (b, HandSchwarz) |
|
|
|
(b, Einfach) -> (False, HandSchneider) |
|
|
|
meetsCall HandSchneiderAngesagt ps = case wonByPoints ps of |
|
|
|
(b, Schneider) -> (b, HandSchneiderAngesagt) |
|
|
|
(b, Schwarz) -> (b, HandSchneiderAngesagtSchwarz) |
|
|
|
(b, Einfach) -> (False, HandSchneiderAngesagt) |
|
|
|
meetsCall HandSchwarz ps = case wonByPoints ps of |
|
|
|
(b, Schneider) -> (False, HandSchwarz) |
|
|
|
(b, Schwarz) -> (b, HandSchwarz) |
|
|
|
(b, Einfach) -> (False, HandSchwarz) |
|
|
|
meetsCall HandSchwarzAngesagt ps = case wonByPoints ps of |
|
|
|
(b, Schneider) -> (False, HandSchwarzAngesagt) |
|
|
|
(b, Schwarz) -> (b, HandSchwarzAngesagt) |
|
|
|
(b, Einfach) -> (False, HandSchwarzAngesagt) |
|
|
|
meetsCall Ouvert ps = case wonByPoints ps of |
|
|
|
(b, Schneider) -> (False, Ouvert) |
|
|
|
(b, Schwarz) -> (b, Ouvert) |
|
|
|
(b, Einfach) -> (False, Ouvert) |
|
|
|
meetsCall _ ps = wonByPoints ps |
|
|
|
|
|
|
|
wonByPoints :: Piles -> (Bool, Modifier) |
|
|
|
@@ -195,10 +250,33 @@ wonByPoints ps |
|
|
|
where (sgl, _) = count ps :: (Int, Int) |
|
|
|
|
|
|
|
-- | get result of game |
|
|
|
getResults :: Game -> Hand -> Piles -> Piles -> Result |
|
|
|
getResults game sglPlayer before after = Result afterGame score sglPoints teamPoints |
|
|
|
where (won, afterGame) = hasWon game after |
|
|
|
hand = skatCards before ++ (map toCard $ handCards sglPlayer before) |
|
|
|
getResults :: Game -> Bid -> Hand -> Piles -> Piles -> Result |
|
|
|
getResults game bid sglPlayer before after = case checkGame bid hand game of |
|
|
|
Just game' -> let (won, afterGame) = hasWon game' after |
|
|
|
gameScore = biddingScore afterGame hand |
|
|
|
score = if won then gameScore else (-2) * gameScore |
|
|
|
in Result afterGame score sglPoints teamPoints |
|
|
|
Nothing -> let gameScore = baseFactor game * ceiling (fromIntegral bid / fromIntegral (baseFactor game)) |
|
|
|
score = (-2) * gameScore |
|
|
|
in Result game score sglPoints teamPoints |
|
|
|
where hand = skatCards before ++ (map toCard $ handCards sglPlayer before) |
|
|
|
(sglPoints, teamPoints) = count after |
|
|
|
gameScore = biddingScore afterGame hand |
|
|
|
score = if won then gameScore else (-2) * gameScore |
|
|
|
|
|
|
|
checkGame :: HasCard c => Bid -> [c] -> Game -> Maybe Game |
|
|
|
checkGame bid cards game@(Colour col mod) |
|
|
|
| biddingScore game cards >= bid = Just game |
|
|
|
| otherwise = upgrade mod >>= \mod' -> checkGame bid cards (Colour col mod') |
|
|
|
checkGame bid cards game@(Grand mod) |
|
|
|
| biddingScore game cards >= bid = Just game |
|
|
|
| otherwise = upgrade mod >>= \mod' -> checkGame bid cards (Grand mod') |
|
|
|
checkGame bid cards game |
|
|
|
| biddingScore game cards >= bid = Just game |
|
|
|
| otherwise = Nothing |
|
|
|
|
|
|
|
upgrade :: Modifier -> Maybe Modifier |
|
|
|
upgrade Einfach = Just Schneider |
|
|
|
upgrade Schneider = Just Schwarz |
|
|
|
upgrade Hand = Just HandSchneider |
|
|
|
upgrade HandSchneider = Just HandSchwarz |
|
|
|
upgrade HandSchneiderAngesagt = Just HandSchneiderAngesagtSchwarz |
|
|
|
upgrade _ = Nothing |