module KoiKoi where import CCard import Data.Bits (popCount, (.&.), shift, testBit) import Data.Map (Map, empty, insert, unionWith) data Yaku = Goko | Shiko | AmeShiko | Sanko | InoShikaCho | Tane | Akatan | Aotan | Tan | Kasu | TsukimiZake | HanamiZake | TsukiFuda deriving (Show) type Points = Int type Score = Pack -> Maybe (Yaku, Points) data Player = Player { hand :: Pack , captured :: Pack , scored :: Map Yaku Points } data State = State { players :: (Player, Player) , river :: Pack , deck :: [ Card ] , month :: Flower , turn :: Bool } has :: Pack -> (Yaku, Points) -> (Pack, Score) has pack points = (pack, \p -> if p == pack then Just points else Nothing) moreThan :: Int -> Pack -> Yaku -> (Pack, Score) moreThan count pack yaku = (pack, (\n -> if n > 0 then Just (yaku, n) else Nothing) . ($count) . (-) . popCount) hikari :: (Pack, Score) hikari = (lights, \p -> rate (popCount p) (p `contains` RainMan)) where rate 5 _ = Just (Goko, 10) rate 4 hasRainMan = if hasRainMan then Just (AmeShiko, 7) else Just (Shiko, 8) rate n hasRainMan = if not hasRainMan && n > 2 then Just (Sanko, 5) else Nothing tsukiFuda :: Flower -> (Pack, Score) tsukiFuda flower = has (0xf `shift` (fromEnum flower * 4)) (TsukiFuda, 8) index :: (Pack, Score) -> Map Card [Score] index (pack, score) = foldl (\map card -> if testBit pack $ fromEnum card then insert card [score . (.&.) pack] map else map ) empty cards yakus :: Map Card [Score] yakus = foldl (\map -> unionWith (++) map . index) empty [ hikari , has inoshikacho (InoShikaCho, 5) , moreThan 4 animals Tane , has poetry (Akatan, 5) , has blue (Aotan, 5) , moreThan 4 ribbons Tan , moreThan 9 plain Kasu , has (set [SakeCup, FullMoon]) (TsukimiZake, 5) , has (set [SakeCup, CampCurtain]) (HanamiZake, 5) ]