2019-10-16 18:53:27 +02:00
|
|
|
{-# LANGUAGE NamedFieldPuns #-}
|
2018-05-11 12:31:53 +02:00
|
|
|
module Game (
|
2019-08-24 23:29:40 +02:00
|
|
|
export
|
2018-05-11 12:31:53 +02:00
|
|
|
, new
|
2018-05-15 18:21:07 +02:00
|
|
|
, play
|
2018-05-11 12:31:53 +02:00
|
|
|
) where
|
2018-04-11 13:25:24 +02:00
|
|
|
|
2019-10-17 18:58:39 +02:00
|
|
|
import qualified App (T, server, update)
|
2019-08-24 23:29:40 +02:00
|
|
|
import Control.Monad.Except (runExceptT, throwError)
|
|
|
|
import Control.Monad.Reader (lift)
|
|
|
|
import Control.Monad.Writer (runWriterT)
|
2019-10-17 18:58:39 +02:00
|
|
|
import qualified Crypto.Saltine.Class as Saltine (IsEncoding(..))
|
|
|
|
import Crypto.Saltine.Core.SecretBox (newNonce, secretbox)
|
2019-10-16 18:53:27 +02:00
|
|
|
import Crypto.Saltine.Core.Sign (signDetached)
|
2019-10-17 18:58:39 +02:00
|
|
|
import Data.Aeson (ToJSON, encode)
|
|
|
|
import Data.ByteString (ByteString)
|
|
|
|
import Data.ByteString.Lazy (toStrict)
|
|
|
|
import Data.Map (Map)
|
|
|
|
import qualified Hanafuda (Pack)
|
|
|
|
import Hanafuda.KoiKoi (Game, GameID, Mode(..), Player, PlayerID, Players)
|
2019-08-24 23:29:40 +02:00
|
|
|
import qualified Hanafuda.KoiKoi as KoiKoi (
|
2019-10-16 18:53:27 +02:00
|
|
|
Action, Game(..), Move(..), play, new
|
2019-08-24 23:29:40 +02:00
|
|
|
)
|
2019-10-16 18:53:27 +02:00
|
|
|
import Hanafuda.Message (PrivateState(..), PublicGame(..), PublicPlayer(..), PublicState(..))
|
2019-10-17 18:58:39 +02:00
|
|
|
import qualified Hanafuda.Player as Player (Player(..), Players(..), get, next)
|
|
|
|
import Keys (T(..), secret)
|
|
|
|
import qualified Server (T(..), register)
|
2019-08-24 23:29:40 +02:00
|
|
|
|
|
|
|
new :: (PlayerID, PlayerID) -> App.T GameID
|
|
|
|
new (for, to) =
|
|
|
|
Server.register <$> (lift $ KoiKoi.new (for, to) WholeYear) >>= App.update
|
|
|
|
|
2019-10-17 18:58:39 +02:00
|
|
|
exportPlayers :: Game -> Map PlayerID Player
|
|
|
|
exportPlayers game =
|
|
|
|
let (Player.Players players) = KoiKoi.players game in
|
|
|
|
players
|
|
|
|
|
2019-10-17 19:50:21 +02:00
|
|
|
privateState :: PlayerID -> Game -> PrivateState
|
|
|
|
privateState playerID game = PrivateState {
|
2019-10-17 18:58:39 +02:00
|
|
|
opponentHand = getHand opponentID players
|
|
|
|
, deck = KoiKoi.deck game
|
|
|
|
}
|
|
|
|
where
|
|
|
|
players = KoiKoi.players game
|
|
|
|
opponentID = Player.next players playerID
|
|
|
|
|
|
|
|
getHand :: PlayerID -> Players -> Hanafuda.Pack
|
|
|
|
getHand playerID = Player.hand . (Player.get playerID)
|
|
|
|
|
|
|
|
publicPlayer :: Player -> PublicPlayer
|
|
|
|
publicPlayer player = PublicPlayer {
|
|
|
|
meld = Player.meld player
|
|
|
|
, yakus = Player.yakus player
|
|
|
|
}
|
2019-10-16 18:53:27 +02:00
|
|
|
|
2019-10-17 19:50:21 +02:00
|
|
|
publicState :: Game -> PublicState
|
|
|
|
publicState game = PublicState {
|
2019-10-16 18:53:27 +02:00
|
|
|
mode = KoiKoi.mode game
|
|
|
|
, scores = KoiKoi.scores game
|
|
|
|
, month = KoiKoi.month game
|
2019-10-17 18:58:39 +02:00
|
|
|
, players = publicPlayer <$> exportPlayers game
|
2019-10-16 18:53:27 +02:00
|
|
|
, playing = KoiKoi.playing game
|
|
|
|
, winning = KoiKoi.winning game
|
|
|
|
, oyake = KoiKoi.oyake game
|
|
|
|
, river = KoiKoi.river game
|
|
|
|
, step = KoiKoi.step game
|
|
|
|
, trick = KoiKoi.trick game
|
2019-10-17 19:25:35 +02:00
|
|
|
, turns = 24 - length (KoiKoi.deck game)
|
2019-10-16 18:53:27 +02:00
|
|
|
, rounds = KoiKoi.rounds game
|
2019-08-24 23:29:40 +02:00
|
|
|
}
|
2019-10-16 18:53:27 +02:00
|
|
|
|
|
|
|
export :: PlayerID -> Game -> App.T PublicGame
|
|
|
|
export playerID game = do
|
2019-10-17 18:58:39 +02:00
|
|
|
Keys.T {encrypt, sign} <- Server.keys <$> App.server
|
|
|
|
n <- lift newNonce
|
2019-10-16 18:53:27 +02:00
|
|
|
return $ PublicGame {
|
2019-10-17 18:58:39 +02:00
|
|
|
nonce = Saltine.encode n
|
|
|
|
, playerHand = getHand playerID (KoiKoi.players game)
|
2019-10-17 19:50:21 +02:00
|
|
|
, private = secretbox encrypt n $ toJSON private
|
|
|
|
, public
|
|
|
|
, publicSignature = signDetached (secret sign) $ toJSON public
|
2019-10-16 18:53:27 +02:00
|
|
|
}
|
2018-05-11 12:31:53 +02:00
|
|
|
where
|
2019-10-17 19:50:21 +02:00
|
|
|
public = publicState game
|
|
|
|
private = privateState playerID game
|
2019-10-17 18:58:39 +02:00
|
|
|
toJSON :: ToJSON a => a -> ByteString
|
|
|
|
toJSON = toStrict . encode
|
2018-05-15 18:21:07 +02:00
|
|
|
|
2019-08-24 23:29:40 +02:00
|
|
|
play :: PlayerID -> KoiKoi.Move -> Game -> App.T (Either String Game, [KoiKoi.Action])
|
|
|
|
play playerID move game = lift . runWriterT . runExceptT $
|
2019-10-17 18:58:39 +02:00
|
|
|
if KoiKoi.playing game == playerID
|
2019-08-24 23:29:40 +02:00
|
|
|
then KoiKoi.play move game
|
|
|
|
else throwError "Not your turn"
|