用haskell写一个21点游戏。
时间: 2023-08-31 09:19:13 浏览: 143
### 回答1:
这是一个Haskell实现的21点游戏代码示例:
```
import System.Random
import Control.Monad
data Suit = Clubs | Diamonds | Hearts | Spades
deriving (Eq, Show, Enum)
data Rank = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten
| Jack | Queen | King | Ace
deriving (Eq, Show, Enum, Ord)
data Card = Card Rank Suit
deriving (Eq, Show)
type Deck = [Card]
deck :: Deck
deck = [Card rank suit | suit <- [Clubs .. Spades], rank <- [Two .. Ace]]
drawCard :: Deck -> IO (Card, Deck)
drawCard deck = do
index <- randomRIO (0, length deck - 1)
let card = deck !! index
newDeck = take index deck ++ drop (index + 1) deck
return (card, newDeck)
rankValue :: Rank -> Int
rankValue rank = case rank of
Jack -> 10
Queen -> 10
King -> 10
Ace -> 11
_ -> fromEnum rank + 2
totalValue :: [Card] -> Int
totalValue = sum . map (rankValue . rank)
where rank (Card r _) = r
playGame :: Deck -> Int -> IO ()
playGame deck playerTotal = do
putStrLn $ "Current Total: " ++ show playerTotal
if playerTotal > 21
then putStrLn "Bust! You lose."
else do
putStrLn "Draw another card? (y/n)"
response <- getLine
if response == "n"
then do
putStrLn $ "Your final total is " ++ show playerTotal ++ "."
if playerTotal == 21
then putStrLn "You win!"
else putStrLn "You lose."
else do
(card, newDeck) <- drawCard deck
let newTotal = playerTotal + rankValue (rank card)
putStrLn $ "Drew the " ++ show card ++ "."
playGame newDeck newTotal
main :: IO ()
main = do
putStrLn "Welcome to 21!"
(card1, newDeck1) <- drawCard deck
putStrLn $ "Drew the " ++ show card1 ++ "."
(card2, newDeck2) <- drawCard newDeck1
putStrLn $ "Drew the " ++ show card2 ++ "."
let playerTotal = rankValue (rank card1) + rankValue (rank card2)
playGame newDeck2 playerTotal
```
这个代码实现了21点游戏的基本逻辑,您可以进行一些修改以满足您的需求。
### 回答2:
Haskell 是一种函数式编程语言,非常适合用来编写游戏。下面是一个用 Haskell 编写的 21 点游戏的实现示例。
首先,我们需要定义一些类型来表示牌和玩家的手牌:
```haskell
data Suit = Spades | Hearts | Diamonds | Clubs
data Rank = Ace | Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten | Jack | Queen | King
type Card = (Rank, Suit)
type Hand = [Card]
```
然后,我们可以编写一些辅助函数来处理牌和手牌:
```haskell
-- 得到一副新的、洗过的纸牌扑克牌
deck :: [Card]
deck = [(r, s) | r <- [Ace, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King]
, s <- [Spades, Hearts, Diamonds, Clubs]]
-- 根据牌面点数计算牌的点数(A 计 11 点,J、Q、K 计 10 点,其他按牌面点数计算)
value :: Card -> Int
value (r, _) = case r of
Ace -> 11
King -> 10
Queen -> 10
Jack -> 10
_ -> fromEnum r + 1
-- 计算手牌的点数(包括 A 还可以计为 1 点的情况)
handValue :: Hand -> Int
handValue hand = if sum (map value hand) > 21 && Ace `elem` (map fst hand)
then sum (map (\(r, _) -> if r == Ace then 1 else value (r, undefined)) hand)
else sum (map value hand)
-- 判断手牌是否爆牌
isBusted :: Hand -> Bool
isBusted hand = handValue hand > 21
```
接下来,我们可以编写主要的游戏逻辑函数:
```haskell
-- 发牌(从牌堆中取出一张牌并加入到手牌中)
deal :: Hand -> [Card] -> (Hand, [Card])
deal hand [] = error "No more cards!"
deal hand (c:cs) = (c:hand, cs)
-- 判断是否达到最佳点数(即 21 点)
bestHand :: Hand -> Bool
bestHand hand = handValue hand == 21
-- 游戏轮流进行,玩家决定是否继续要牌,直到停止或爆牌
playGame :: Hand -> [Card] -> IO ()
playGame hand cards = do
let currentValue = handValue hand
putStrLn ("当前点数: " ++ show currentValue)
if isBusted hand
then putStrLn "爆牌,游戏结束!"
else if bestHand hand
then putStrLn "达到最佳点数,游戏结束!"
else do
putStr "是否要牌?(y/n): "
choice <- getLine
if choice == "y"
then do
let (newHand, newCards) = deal hand cards
putStrLn ("发牌: " ++ show (head newCards))
playGame newHand newCards
else putStrLn "停止要牌,游戏结束!"
```
最后,我们可以编写一个启动函数,让玩家可以开始游戏:
```haskell
startGame :: IO ()
startGame = do
let (hand, remainingCards) = deal [] deck
putStrLn ("发牌: " ++ show (head remainingCards))
playGame hand remainingCards
main :: IO ()
main = startGame
```
这样,你就可以运行该 Haskell 程序,并通过键盘输入来玩 21 点游戏了。
阅读全文