Safe Haskell | Safe |
---|---|
Language | Haskell2010 |
Synopsis
- main :: IO ()
- selfplay :: GameSpec -> IO ()
- start :: (RandomGen g, Monad m, Strategies ps m) => GameSpec -> [Peeker m] -> ps -> g -> m (((EndGame, [State], [Move]), ps), g)
- createGame :: RandomGen g => GameSpec -> g -> (State, g)
- run :: (Monad m, Strategies ps m) => [Peeker m] -> [State] -> [Move] -> ps -> m ((EndGame, [State], [Move]), ps)
- prettyEndGame :: (EndGame, [State], [Move]) -> String
- isMoveValid :: PrivateView -> Move -> Bool
- checkEndGame :: PublicInfo -> Maybe EndGame
- help :: String
- class Strategies ps m
- class Monad m => Strategy p m where
- strategyName :: m p -> m String
- move :: [PrivateView] -> [Move] -> p -> m (Move, p)
- observe :: [PrivateView] -> [Move] -> p -> m ()
- data StrategyDict m s = SD {}
- mkSD :: (Monad m, Typeable s, Strategy s m) => String -> s -> StrategyDict m s
- type DynamicStrategy m = StrategyDict m Dynamic
- mkDS :: (Monad m, Typeable s, Strategy s m) => String -> s -> DynamicStrategy m
- mkDS' :: (Monad m, Typeable s) => StrategyDict m s -> DynamicStrategy m
- data Verbose p = Verbose {}
- type STDIO = Verbose Blind
- stdio :: Verbose Blind
- data Blind
- data ViaHandles = VH {}
- data Verbosity = V {}
- verbose :: Verbosity
- type Peeker m = State -> [Move] -> m ()
- peek :: Peeker IO
- data GameSpec = GS {
- numPlayers :: Int
- rule :: Rule
- defaultGS :: GameSpec
- data Rule = R {
- numBlackTokens :: Int
- funPlayerHand :: [Int]
- numColors :: Int
- prolong :: Bool
- earlyQuit :: Bool
- numMulticolors :: [Int]
- defaultRule :: Rule
- isRuleValid :: Rule -> Bool
- colors :: PublicInfo -> [Color]
- data Move
- type Index = Int
- data State = St {
- publicState :: PublicInfo
- pile :: [Card]
- hands :: [[Card]]
- data PrivateView = PV {
- publicView :: PublicInfo
- handsPV :: [[Card]]
- invisibleBag :: IntMap Int
- data PublicInfo = PI {}
- data Result
- data EndGame
- data Card = C {}
- data Color
- data Number
- type Marks = (Maybe Color, Maybe Number)
- type Possibilities = (Int, Int)
- cardToInt :: Card -> Int
- intToCard :: Int -> Card
- readsColorChar :: ReadS Color
- readsNumberChar :: ReadS Number
- isCritical :: PublicInfo -> Card -> Bool
- isUseless :: PublicInfo -> Card -> Bool
- bestPossibleRank :: PublicInfo -> Color -> Number
- achievedRank :: PublicInfo -> Color -> Number
- isPlayable :: PublicInfo -> Card -> Bool
- isHinted :: Marks -> Bool
- currentScore :: PublicInfo -> Int
- achievableScore :: PublicInfo -> Int
- isMoreObviouslyUseless :: PublicInfo -> Marks -> Bool
- isObviouslyUseless :: PublicInfo -> Possibilities -> Bool
- isDefinitelyUseless :: PrivateView -> Marks -> Possibilities -> Bool
- isMoreObviouslyPlayable :: PublicInfo -> Marks -> Bool
- isObviouslyPlayable :: PublicInfo -> Possibilities -> Bool
- isDefinitelyPlayable :: PrivateView -> Marks -> Possibilities -> Bool
- obviousChopss :: PublicInfo -> [Marks] -> [Possibilities] -> [[Index]]
- definiteChopss :: PrivateView -> [Marks] -> [Possibilities] -> [[Index]]
- isDoubleDrop :: PrivateView -> Result -> [Index] -> (Int, Int) -> Bool
- what'sUp :: Verbosity -> String -> [PrivateView] -> [Move] -> String
- what'sUp1 :: Verbosity -> PrivateView -> Move -> String
- ithPlayer :: Int -> Int -> String
- recentEvents :: (Int -> Int -> String) -> [PrivateView] -> [Move] -> String
- prettyPI :: PublicInfo -> String
- prettySt :: (Int -> Int -> String) -> State -> String
- ithPlayerFromTheLast :: Int -> Int -> String
- view :: State -> PrivateView
- replaceNth :: Int -> a -> [a] -> (a, [a])
- shuffle :: RandomGen g => [a] -> g -> ([a], g)
- showPossibilities :: a -> [a] -> Int -> [a]
- showColorPossibilities :: Int -> String
- showNumberPossibilities :: Int -> String
- showTrial :: (Int -> String) -> Int -> PrivateView -> Move -> String
Functions for Dealing Games
selfplay :: GameSpec -> IO () Source #
selfplay
starts selfplay with yourself:)
Also,
selfplay defaultGS{numPlayers=n}
(where 1<n<10) starts selfplay with youselves:D
start :: (RandomGen g, Monad m, Strategies ps m) => GameSpec -> [Peeker m] -> ps -> g -> m (((EndGame, [State], [Move]), ps), g) Source #
start
creates and runs a game. This is just the composition of createGame
and run
.
run :: (Monad m, Strategies ps m) => [Peeker m] -> [State] -> [Move] -> ps -> m ((EndGame, [State], [Move]), ps) Source #
prettyEndGame :: (EndGame, [State], [Move]) -> String Source #
prettyEndGame
can be used to pretty print the final situation.
isMoveValid :: PrivateView -> Move -> Bool Source #
isMoveValid
can be used to check if the candidate Move is compliant to the rule under the current situation. Each player can decide it based on the current PrivateView
(without knowing the full state).
checkEndGame :: PublicInfo -> Maybe EndGame Source #
Datatypes
The Class of Strategies
class Strategies ps m Source #
The Strategies
class defines the list of Strategy
s. If all the strategies have the same type, one can use the list instance.
I (Susumu) guess that in most cases one can use Dynamic
in order to force the same type, but just in case, the tuple instance is also provided. (Also, the tuple instance should be more handy.)
The strategies are used in order, cyclically.
The number of strategies need not be the same as numPlayers
, though the latter should be a divisor of the former.
For normal play, they should be the same.
If only one strategy is provided, that means selfplay, though this is not desired because all the hidden info can be memorized. (In order to avoid such cheating, the same strategy should be repeated.)
If there are twice as many strategies as numPlayers
, the game will be "Pair Hanabi", like "Pair Go" or "Pair Golf" or whatever. (Maybe this is also interesting.)
runARound, broadcast
Instances
(Strategy p m, Monad m) => Strategies [p] m Source # | |
(Strategies p1 m, Strategies p2 m, Monad m) => Strategies (p1, p2) m Source # | |
class Monad m => Strategy p m where Source #
The Strategy
class is exactly the interface that
AI researchers defining their algorithms have to care about.
strategyName :: m p -> m String Source #
strategyName
is just the name of the strategy. The designer of the instance should choose one.
:: [PrivateView] | The history of |
-> [Move] | The history of |
-> p | The strategy's current state. This can be isomorphic to |
-> m (Move, p) |
|
move
is the heart of the strategy. It takes the history of observations and moves, and selects a Move
.
Because the full history is available, your algorithm can be stateless, but still there is the option to design it in the stateful manner.
:: [PrivateView] | The history of |
-> [Move] | The history of |
-> p | The strategy's current state. This can be isomorphic to |
-> m () |
observe
is called during other players' turns. It allows (mainly) human players to think while waiting.
It is arguable whether algorithms running on the same machine may think during other players' turn, especially when the game is timed.
Instances
MonadIO m => Strategy ViaHandles m Source # | |
Defined in Game.Hanabi strategyName :: m ViaHandles -> m String Source # move :: [PrivateView] -> [Move] -> ViaHandles -> m (Move, ViaHandles) Source # observe :: [PrivateView] -> [Move] -> ViaHandles -> m () Source # | |
MonadIO m => Strategy Blind m Source # | |
Defined in Game.Hanabi | |
(Strategy p m, MonadIO m) => Strategy (Verbose p) m Source # | |
Defined in Game.Hanabi | |
Monad m => Strategy (StrategyDict m s) m Source # | |
Defined in Game.Hanabi strategyName :: m (StrategyDict m s) -> m String Source # move :: [PrivateView] -> [Move] -> StrategyDict m s -> m (Move, StrategyDict m s) Source # observe :: [PrivateView] -> [Move] -> StrategyDict m s -> m () Source # |
data StrategyDict m s Source #
StrategyDict
is a dictionary implementation of class Strategy
. It can be used instead if you like.
Instances
Monad m => Strategy (StrategyDict m s) m Source # | |
Defined in Game.Hanabi strategyName :: m (StrategyDict m s) -> m String Source # move :: [PrivateView] -> [Move] -> StrategyDict m s -> m (Move, StrategyDict m s) Source # observe :: [PrivateView] -> [Move] -> StrategyDict m s -> m () Source # |
type DynamicStrategy m = StrategyDict m Dynamic Source #
mkDS' :: (Monad m, Typeable s) => StrategyDict m s -> DynamicStrategy m Source #
Verbose makes a player verbose. It is useful to monitor the viewpoint of a specific player.
data ViaHandles Source #
Instances
MonadIO m => Strategy ViaHandles m Source # | |
Defined in Game.Hanabi strategyName :: m ViaHandles -> m String Source # move :: [PrivateView] -> [Move] -> ViaHandles -> m (Move, ViaHandles) Source # observe :: [PrivateView] -> [Move] -> ViaHandles -> m () Source # |
V | |
|
Instances
Audience
The Game Specification
GS | |
|
Instances
Eq GameSpec Source # | |
Read GameSpec Source # | |
Show GameSpec Source # | |
Generic GameSpec Source # | |
type Rep GameSpec Source # | |
Defined in Game.Hanabi type Rep GameSpec = D1 (MetaData "GameSpec" "Game.Hanabi" "hanabi-dealer-0.7.0.0-CKB1SX6TOC550tfN00OZr5" False) (C1 (MetaCons "GS" PrefixI True) (S1 (MetaSel (Just "numPlayers") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Int) :*: S1 (MetaSel (Just "rule") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Rule))) |
Rule
is the datatype representing the game variants.
- Minor remark
- When adopting Variant 4, that is, the rule of continuing even after a round after the pile is exhausted, there can be a situation where a player cannot choose any valid move, because she has no card and there is no hint token. This can happen, after one player (who has no critical card) repeats discarding, and other players repeat hinting each other, consuming hint tokens. Seemingly, the rule book does not state what happens in such a case, but I (Susumu) believe the game should end as failure, then, because
- This situation can easily be made, and easily be avoided;
- If deadline is set up, this should cause time out;
- When Variant 4 is adopted, the game must end with either the perfect game or failure.
See also the definition of checkEndGame
.
R | |
|
Instances
Eq Rule Source # | |
Read Rule Source # | |
Show Rule Source # | |
Generic Rule Source # | |
type Rep Rule Source # | |
Defined in Game.Hanabi type Rep Rule = D1 (MetaData "Rule" "Game.Hanabi" "hanabi-dealer-0.7.0.0-CKB1SX6TOC550tfN00OZr5" False) (C1 (MetaCons "R" PrefixI True) ((S1 (MetaSel (Just "numBlackTokens") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Int) :*: (S1 (MetaSel (Just "funPlayerHand") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 [Int]) :*: S1 (MetaSel (Just "numColors") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Int))) :*: (S1 (MetaSel (Just "prolong") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Bool) :*: (S1 (MetaSel (Just "earlyQuit") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Bool) :*: S1 (MetaSel (Just "numMulticolors") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 [Int]))))) |
defaultRule :: Rule Source #
defaultRule
is the normal rule from the rule book of the original card game Hanabi.
isRuleValid :: Rule -> Bool Source #
colors :: PublicInfo -> [Color] Source #
The Game State and Interaction History
Drop | drop the card (0-origin) |
Play | play the card (0-origin) |
Hint Int (Either Color Number) | give hint to the ith next player |
Instances
Eq Move Source # | |
Read Move Source # | |
Show Move Source # | |
Generic Move Source # | |
type Rep Move Source # | |
Defined in Game.Hanabi type Rep Move = D1 (MetaData "Move" "Game.Hanabi" "hanabi-dealer-0.7.0.0-CKB1SX6TOC550tfN00OZr5" False) (C1 (MetaCons "Drop" PrefixI True) (S1 (MetaSel (Just "index") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Index)) :+: (C1 (MetaCons "Play" PrefixI True) (S1 (MetaSel (Just "index") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Index)) :+: C1 (MetaCons "Hint" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Int) :*: S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 (Either Color Number))))) |
State consists of all the information of the current game state, including public info, private info, and the hidden deck.
St | |
|
Instances
Eq State Source # | |
Read State Source # | |
Show State Source # | |
Generic State Source # | |
type Rep State Source # | |
Defined in Game.Hanabi type Rep State = D1 (MetaData "State" "Game.Hanabi" "hanabi-dealer-0.7.0.0-CKB1SX6TOC550tfN00OZr5" False) (C1 (MetaCons "St" PrefixI True) (S1 (MetaSel (Just "publicState") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 PublicInfo) :*: (S1 (MetaSel (Just "pile") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 [Card]) :*: S1 (MetaSel (Just "hands") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 [[Card]])))) |
data PrivateView Source #
PrivateView is the info that is available to the player that has head
.hands
PV | |
|
Instances
data PublicInfo Source #
PublicInfo is the info that is available to all players.
PI | |
|
Instances
Result
is the result of the last move.
Instances
Eq Result Source # | |
Read Result Source # | |
Show Result Source # | |
Generic Result Source # | |
type Rep Result Source # | |
Defined in Game.Hanabi type Rep Result = D1 (MetaData "Result" "Game.Hanabi" "hanabi-dealer-0.7.0.0-CKB1SX6TOC550tfN00OZr5" False) ((C1 (MetaCons "None" PrefixI False) (U1 :: Type -> Type) :+: C1 (MetaCons "Discard" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Card))) :+: (C1 (MetaCons "Success" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Card)) :+: C1 (MetaCons "Fail" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Card)))) |
EndGame
represents the game score, along with the info of how the game ended.
It is not just Int
in order to distinguish Failure
(disaster / no life) from
(not playing any card), though Soso
0
does not look more attractive than Soso
0Failure
.
Instances
Eq EndGame Source # | |
Read EndGame Source # | |
Show EndGame Source # | |
Generic EndGame Source # | |
type Rep EndGame Source # | |
Defined in Game.Hanabi type Rep EndGame = D1 (MetaData "EndGame" "Game.Hanabi" "hanabi-dealer-0.7.0.0-CKB1SX6TOC550tfN00OZr5" False) (C1 (MetaCons "Failure" PrefixI False) (U1 :: Type -> Type) :+: (C1 (MetaCons "Soso" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Int)) :+: C1 (MetaCons "Perfect" PrefixI False) (U1 :: Type -> Type))) |
The Cards
Instances
Eq Card Source # | |
Read Card Source # | |
Show Card Source # | |
Generic Card Source # | |
type Rep Card Source # | |
Defined in Game.Hanabi type Rep Card = D1 (MetaData "Card" "Game.Hanabi" "hanabi-dealer-0.7.0.0-CKB1SX6TOC550tfN00OZr5" False) (C1 (MetaCons "C" PrefixI True) (S1 (MetaSel (Just "color") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Color) :*: S1 (MetaSel (Just "number") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Number))) |
Instances
Bounded Color Source # | |
Enum Color Source # | |
Eq Color Source # | |
Read Color Source # | |
Show Color Source # | |
Generic Color Source # | |
type Rep Color Source # | |
Defined in Game.Hanabi type Rep Color = D1 (MetaData "Color" "Game.Hanabi" "hanabi-dealer-0.7.0.0-CKB1SX6TOC550tfN00OZr5" False) ((C1 (MetaCons "White" PrefixI False) (U1 :: Type -> Type) :+: (C1 (MetaCons "Yellow" PrefixI False) (U1 :: Type -> Type) :+: C1 (MetaCons "Red" PrefixI False) (U1 :: Type -> Type))) :+: (C1 (MetaCons "Green" PrefixI False) (U1 :: Type -> Type) :+: (C1 (MetaCons "Blue" PrefixI False) (U1 :: Type -> Type) :+: C1 (MetaCons "Multicolor" PrefixI False) (U1 :: Type -> Type)))) |
Instances
Bounded Number Source # | |
Enum Number Source # | |
Defined in Game.Hanabi | |
Eq Number Source # | |
Ord Number Source # | |
Read Number Source # | |
Show Number Source # | |
Generic Number Source # | |
type Rep Number Source # | |
Defined in Game.Hanabi type Rep Number = D1 (MetaData "Number" "Game.Hanabi" "hanabi-dealer-0.7.0.0-CKB1SX6TOC550tfN00OZr5" False) ((C1 (MetaCons "Empty" PrefixI False) (U1 :: Type -> Type) :+: (C1 (MetaCons "K1" PrefixI False) (U1 :: Type -> Type) :+: C1 (MetaCons "K2" PrefixI False) (U1 :: Type -> Type))) :+: (C1 (MetaCons "K3" PrefixI False) (U1 :: Type -> Type) :+: (C1 (MetaCons "K4" PrefixI False) (U1 :: Type -> Type) :+: C1 (MetaCons "K5" PrefixI False) (U1 :: Type -> Type)))) |
type Marks = (Maybe Color, Maybe Number) Source #
Marks
is the type synonym representing the hint trace of a card.
type Possibilities = (Int, Int) Source #
Utilities
Hints
isCritical :: PublicInfo -> Card -> Bool Source #
A critical card is a useful card and the last card that has not been dropped.
Unmarked critical card on the chop should be marked.
isUseless :: PublicInfo -> Card -> Bool Source #
isUseless pi card means either the card is already played or it is above the bestPossibleRank.
bestPossibleRank :: PublicInfo -> Color -> Number Source #
the best achievable rank for each color.
achievedRank :: PublicInfo -> Color -> Number Source #
isPlayable :: PublicInfo -> Card -> Bool Source #
currentScore :: PublicInfo -> Int Source #
achievableScore :: PublicInfo -> Int Source #
isMoreObviouslyUseless :: PublicInfo -> Marks -> Bool Source #
isMoreObviouslyUseless
looks at the publicly available current info and decides if the card is surely useless.
isObviouslyUseless :: PublicInfo -> Possibilities -> Bool Source #
isDefinitelyUseless :: PrivateView -> Marks -> Possibilities -> Bool Source #
isMoreObviouslyPlayable :: PublicInfo -> Marks -> Bool Source #
isMoreObviouslyPlayable
looks at the publicly available current info and decides if the card is surely playable.
isObviouslyPlayable :: PublicInfo -> Possibilities -> Bool Source #
In addition to isMoreObviouslyPlayable
, isObviouslyPlayable
also looks into the color/number possibilities of the card and decides if the card is surely playable.
isDefinitelyPlayable :: PrivateView -> Marks -> Possibilities -> Bool Source #
In addition to isObviouslyPlayable
, isDefinitelyPlayable
also looks at other players' hand and decides if the card is surely playable.
obviousChopss :: PublicInfo -> [Marks] -> [Possibilities] -> [[Index]] Source #
definiteChopss :: PrivateView -> [Marks] -> [Possibilities] -> [[Index]] Source #
In addition to choppiri
, definiteChopss
and obviousChopss
consider isDefinitelyUseless
and isObviouslyUseless
respectively. Since "from which card to drop among obviously-useless cards" depends on conventions, cards with the same uselessness are wrapped in a list within the ordered list.
isDoubleDrop :: PrivateView -> Result -> [Index] -> (Int, Int) -> Bool Source #
Minor ones
recentEvents :: (Int -> Int -> String) -> [PrivateView] -> [Move] -> String Source #
prettyPI :: PublicInfo -> String Source #
view :: State -> PrivateView Source #
replaceNth :: Int -> a -> [a] -> (a, [a]) Source #
showPossibilities :: a -> [a] -> Int -> [a] Source #
showColorPossibilities :: Int -> String Source #
showNumberPossibilities :: Int -> String Source #