Parcourir la source

serialization of piles

master
flavis il y a 6 ans
Parent
révision
1c3f85b9a6
9 fichiers modifiés avec 125 ajouts et 10 suppressions
  1. +1
    -0
      package.yaml
  2. +4
    -0
      skat.cabal
  3. +0
    -1
      src/Skat.hs
  4. +5
    -0
      src/Skat/AI/Online.hs
  5. +15
    -4
      src/Skat/Card.hs
  6. +2
    -2
      src/Skat/Matches.hs
  7. +52
    -1
      src/Skat/Pile.hs
  8. +7
    -1
      src/Skat/Preperation.hs
  9. +39
    -1
      src/Skat/Utils.hs

+ 1
- 0
package.yaml Voir le fichier

@@ -34,6 +34,7 @@ dependencies:
- containers
- case-insensitive
- vector
- transformers

library:
source-dirs: src


+ 4
- 0
skat.cabal Voir le fichier

@@ -4,7 +4,7 @@ cabal-version: 1.12
--
-- see: https://github.com/sol/hpack
--
-- hash: a181979e99bc6631140cc5973d1714c0b5aa021f74c72938c0ee7ab47b581cf2

name: skat
version: 0.1.0.7
@@ -62,6 +62,7 @@ library
, random
, split
, text
, transformers
, vector
, websockets
default-language: Haskell2010
@@ -88,6 +89,7 @@ executable skat-exe
, skat
, split
, text
, transformers
, vector
, websockets
default-language: Haskell2010
@@ -114,6 +116,7 @@ test-suite skat-test
, skat
, split
, text
, transformers
, vector
, websockets
default-language: Haskell2010

+ 0
- 1
src/Skat.hs Voir le fichier

@@ -23,7 +23,6 @@ data SkatEnv = SkatEnv { piles :: Piles
, currentHand :: Hand }
deriving Show

type Trick = (CardS Owner, CardS Owner, CardS Owner)
type Skat = StateT SkatEnv (WriterT [Trick] IO)

runSkat :: Skat a -> SkatEnv -> IO (a, SkatEnv, [Trick])


+ 5
- 0
src/Skat/AI/Online.hs Voir le fichier

@@ -95,6 +95,8 @@ instance Communicator c => Bidder (PrepOnline c) where
liftIO $ send (prepConnection p) (BS.unpack $ encode $ GameResultsQuery res)
onGame p game sglPlayer = do
liftIO $ send (prepConnection p) (BS.unpack $ encode $ GameStartQuery game sglPlayer)
onNoGame p = do
liftIO $ send (prepConnection p) (BS.unpack $ encode $ NoGameQuery)

type Online a m = ReaderT (OnlineEnv a) m

@@ -139,6 +141,7 @@ data Query = ChooseQuery [Card] [CardS Played]
| CardsQuery [Card]
| BidEvent (Maybe Bid) Hand Hand
| ResponseEvent Bool Hand Hand
| NoGameQuery

newtype ChosenResponse = ChosenResponse Card
newtype BidResponse = BidResponse Int
@@ -183,6 +186,8 @@ instance ToJSON Query where
, "response" .= response
, "reizer" .= show reizer
, "gereizter" .= show gereizter ]
toJSON NoGameQuery =
object [ "query" .= ("no_game" :: String) ]

instance FromJSON ChosenResponse where
parseJSON = withObject "ChosenResponse" $ \v -> ChosenResponse


+ 15
- 4
src/Skat/Card.hs Voir le fichier

@@ -29,7 +29,7 @@ data Type = Seven
| Ten
| Ace
| Jack
deriving (Eq, Ord, Show, Enum, Read)
deriving (Eq, Ord, Show, Enum, Read, Bounded)

data NullType = NSeven
| NEight
@@ -39,7 +39,7 @@ data NullType = NSeven
| NQueen
| NKing
| NAce
deriving (Eq, Ord, Show, Enum, Read)
deriving (Eq, Ord, Show, Enum, Read, Bounded)

instance Countable Type Int where
count Ace = 11
@@ -53,7 +53,7 @@ data Colour = Diamonds
| Hearts
| Spades
| Clubs
deriving (Eq, Ord, Show, Enum, Read)
deriving (Eq, Ord, Show, Enum, Read, Bounded)

data Trump = TrumpColour Colour
| Jacks
@@ -65,7 +65,7 @@ data TurnColour = TurnColour Colour
deriving (Show, Eq)

data Card = Card Type Colour
deriving (Eq, Show, Ord, Read)
deriving (Eq, Show, Ord, Read, Bounded)

getType :: Card -> Type
getType (Card t _) = t
@@ -117,6 +117,17 @@ instance Countable (S.Set Card) Int where
instance NFData Card where
rnf (Card t c) = t `seq` c `seq` ()

base64table :: [Char]
base64table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

class Serialize c a where
serialize :: a -> c
deserialize :: c -> Maybe a

instance Serialize Char Card where
serialize card = base64table !! fromEnum card
deserialize char = base64table `indexOf` char >>= safeToEnum

equals :: TurnColour -> Maybe TurnColour -> Bool
equals col (Just x) = col == x
equals col Nothing = True


+ 2
- 2
src/Skat/Matches.hs Voir le fichier

@@ -33,10 +33,10 @@ match prepEnv = do
let res = getResults
(game skatEnv)
sglPlayer
(Skat.piles skatEnv)
(Skat.Preperation.piles prepEnv)
(Skat.piles finished)
publishGameResults res (bidders prepEnv)
return $ Just $ Match (Skat.piles skatEnv) res tricks sglPlayer
return $ Just $ Match (Skat.Preperation.piles prepEnv) res tricks sglPlayer
Nothing -> putStrLn "no one wanted to play" >> return Nothing

-- | predefined card distribution for testing purposes


+ 52
- 1
src/Skat/Pile.hs Voir le fichier

@@ -6,6 +6,9 @@

module Skat.Pile where

import Control.Monad.State
import Control.Monad.Trans.Maybe

import Prelude hiding (lookup)
import qualified Data.Map.Strict as M
import qualified Data.Vector as V
@@ -15,6 +18,8 @@ import Data.Maybe
import Data.Aeson
import Control.Exception
import Data.List (delete)
import Text.Read (readMaybe)
import Debug.Trace

import Skat.Card
import Skat.Utils
@@ -41,7 +46,7 @@ instance ToJSON p => ToJSON (CardS p) where
object ["card" .= card, "pile" .= pile]

data Hand = Hand1 | Hand2 | Hand3
deriving (Show, Eq, Ord, Read)
deriving (Show, Eq, Ord, Read, Enum, Bounded)

toInt :: Hand -> Int
toInt Hand1 = 1
@@ -61,12 +66,33 @@ prev Hand3 = Hand2
data Owner = P Hand | S
deriving (Show, Eq, Ord, Read)

instance Enum Owner where
fromEnum (P hand) = fromEnum hand
fromEnum S = 3
toEnum 0 = P Hand1
toEnum 1 = P Hand2
toEnum 2 = P Hand3
toEnum 3 = S

instance Bounded Owner where
maxBound = S
minBound = P Hand1

instance ToJSON Owner where
toJSON (P hand) = object ["owner" .= show hand]
toJSON S = object ["owner" .= ("skat" :: String) ]

instance Serialize String (CardS Owner) where
serialize (CardS card owner) = show (fromEnum owner) ++ [serialize card]
deserialize str = (flip evalState) str $ runMaybeT $ do
owner <- pop >>= MaybeT . return . (>>= safeToEnum) . readMaybe . (:[])
card <- pop >>= MaybeT . return . deserialize
return $ CardS card owner

type Played = Owner -- TODO: remove

type Trick = (CardS Owner, CardS Owner, CardS Owner)

data Piles = Piles { _hand1 :: [CardS Owner]
, _hand2 :: [CardS Owner]
, _hand3 :: [CardS Owner]
@@ -185,3 +211,28 @@ distribute cards = emptyPiles hand1 hand2 hand3 skt
hand1 = concatMap (!! 0) [round1, round2, round3]
hand2 = concatMap (!! 1) [round1, round2, round3]
hand3 = concatMap (!! 2) [round1, round2, round3]

instance Serialize String Piles where
serialize piles = sers (_hand1 piles) ++ sers (_hand2 piles) ++ sers (_hand3 piles)
++ sers (_skat piles)
where sers cards = map (serialize . toCard) cards
deserialize str = (flip evalState) str $ runMaybeT $ do
hand1 <- takeG 10 >>= mapM deser
hand2 <- takeG 10 >>= mapM deser
hand3 <- takeG 10 >>= mapM deser
skat <- takeG 2 >>= mapM deser
return $ emptyPiles hand1 hand2 hand3 skat
where deser char = MaybeT $ return $ deserialize char

instance Serialize String [Trick] where
serialize [] = ""
serialize ((c1, c2, c3):tricks) = serialize c1 ++ serialize c2 ++ serialize c3
++ serialize tricks
deserialize str = (flip evalState) str $ runMaybeT $ reverse <$> go []
where go acc = do
empty <- isEmpty
if empty then return acc else do
card1 <- takeG 2 >>= MaybeT . return . deserialize
card2 <- takeG 2 >>= MaybeT . return . deserialize
card3 <- takeG 2 >>= MaybeT . return . deserialize
go ((card1, card2, card3):acc)

+ 7
- 1
src/Skat/Preperation.hs Voir le fichier

@@ -40,6 +40,8 @@ class Bidder a where
onGame _ _ _ = return ()
onResult :: MonadIO m => a -> Result -> m ()
onResult _ _ = return ()
onNoGame :: MonadIO m => a -> m ()
onNoGame _ = return ()

-- | trick to allow heterogenous bidder list
data BD = forall b. (Show b, Bidder b) => BD b
@@ -60,6 +62,7 @@ instance Bidder BD where
onResult (BD b) = onResult b
onBid (BD b) = onBid b
onResponse (BD b) = onResponse b
onNoGame (BD b) = onNoGame b

data Bidders = Bidders BD BD BD
deriving Show
@@ -88,7 +91,7 @@ runPreperation = do
publishBid bid finalWinner finalWinner
case bid of
Just val -> (Just . (finalWinner,)) <$> initGame finalWinner val
Nothing -> return Nothing
Nothing -> publishNoGame >> return Nothing
else (Just . (finalWinner,)) <$> initGame finalWinner finalBid

runBidding :: Bid -> BD -> BD -> Preperation (Hand, Bid)
@@ -160,6 +163,9 @@ publishBid bid reizer gereizter = mapBidders (\b -> onBid b bid reizer gereizter
publishResponse :: Bool -> Hand -> Hand -> Preperation ()
publishResponse response reizer gereizter = mapBidders (\b -> onResponse b response reizer gereizter)

publishNoGame :: Preperation ()
publishNoGame = mapBidders onNoGame

mapBidders :: (BD -> Preperation ()) -> Preperation ()
mapBidders f = do
bds <- asks bidders


+ 39
- 1
src/Skat/Utils.hs Voir le fichier

@@ -1,7 +1,12 @@
{-# LANGUAGE ScopedTypeVariables #-}

module Skat.Utils where

import Control.Monad.State
import Control.Monad.Trans.Maybe

import System.Random
import Text.Read
import Text.Read hiding (get, lift)
import qualified Data.ByteString.Char8 as B (ByteString, unpack, pack)
import qualified Data.Text as T (Text, unpack, pack)
import Data.List (foldl')
@@ -57,3 +62,36 @@ instance Stringy B.ByteString where
instance Stringy T.Text where
toString = T.unpack
fromString = T.pack

indexOf :: Eq a => [a] -> a -> Maybe Int
indexOf [] _ = Nothing
indexOf (x:xs) item
| x == item = Just 0
| otherwise = (1+) <$> xs `indexOf` item

type Generator c = MaybeT (State [c])

pop :: Generator c c
pop = do
cs <- get
if null cs then mzero else put (tail cs) >> return (head cs)

isEmpty :: Generator c Bool
isEmpty = get >>= return . null

takeG :: Int -> Generator c [c]
takeG n = do
cs <- lift get
if length cs >= n
then do
put (drop n cs)
return (take n cs)
else mzero

-- forall is needed to allow scoped type variables
safeToEnum :: forall a. (Enum a, Bounded a) => Int -> Maybe a
safeToEnum n
| maxN < n || minN > n = Nothing
| otherwise = Just $ toEnum n
where maxN = fromEnum (maxBound :: a)
minN = fromEnum (minBound :: a)

Chargement…
Annuler
Enregistrer