75 lines
1.8 KiB
Haskell
75 lines
1.8 KiB
Haskell
module KoiKoi where
|
|
|
|
import CCard
|
|
import Data.Bits (popCount, (.&.))
|
|
import System.Random (randomRIO)
|
|
|
|
type Points = Int
|
|
|
|
data Player = Player {
|
|
hand :: Pack
|
|
, captured :: Pack
|
|
, scored :: [Yaku]
|
|
}
|
|
|
|
data State = State {
|
|
players :: (Player, Player)
|
|
, river :: Pack
|
|
, deck :: [ Card ]
|
|
, month :: Flower
|
|
, turn :: Bool
|
|
}
|
|
|
|
data Yaku =
|
|
Goko
|
|
| Shiko
|
|
| AmeShiko
|
|
| Sanko
|
|
| InoShikaCho
|
|
| Tane
|
|
| Akatan
|
|
| Aotan
|
|
| Tan
|
|
| Kasu
|
|
| TsukimiZake
|
|
| HanamiZake
|
|
|
|
yakus :: [ Pack -> Maybe (Yaku, Points) ]
|
|
yakus = [
|
|
(\p -> lightsYaku (popCount p) (p `contains` RainMan)) . (lights .&.)
|
|
, is inoshikacho InoShikaCho
|
|
, moreThan 4 animals Tane
|
|
, is poetry Akatan
|
|
, is blue Aotan
|
|
, moreThan 4 ribbons Tan
|
|
, moreThan 9 plain Kasu
|
|
, is (set [SakeCup, FullMoon]) TsukimiZake
|
|
, is (set [SakeCup, CampCurtain]) HanamiZake
|
|
]
|
|
where
|
|
lightsYaku 5 _ = Just (Goko, 10)
|
|
lightsYaku 4 hasRainMan = if hasRainMan then Just (AmeShiko, 7) else Just (Shiko, 8)
|
|
lightsYaku n hasRainMan = if not hasRainMan && n > 2 then Just (Sanko, 8) else Nothing
|
|
moreThan points set yaku =
|
|
threshold yaku . (\x -> x - points) . popCount . (set .&.)
|
|
threshold yaku n
|
|
| n > 0 = Just (yaku, n)
|
|
| otherwise = Nothing
|
|
is set yaku pack = if set == pack then Just (yaku, 5) else Nothing
|
|
|
|
shuffle :: [a] -> IO [a]
|
|
shuffle l =
|
|
aux (length l) l
|
|
where
|
|
aux n [] = return []
|
|
aux n [a] = return [a]
|
|
aux n l = do
|
|
cut <- randomRIO (0, n - 1)
|
|
let (top, bottom) = splitAt cut l
|
|
shuffledTop <- aux cut top
|
|
shuffledBottom <- aux (n - cut) bottom
|
|
reorder <- randomRIO (False, True)
|
|
return $ if reorder
|
|
then shuffledTop ++ shuffledBottom
|
|
else shuffledBottom ++ shuffledTop
|