Go Fish/Nim: Difference between revisions
m (Corrected a typo.) |
mNo edit summary |
||
Line 199: | Line 199: | ||
if answer == 1: break |
if answer == 1: break |
||
firstPlayer = firstPlayer.other()</lang> |
firstPlayer = firstPlayer.other()</lang> |
||
{{out}} |
|||
<pre> |
Revision as of 21:49, 8 January 2021
<lang Nim>import strutils, strformat import playing_cards
const
Human = 0 Computer = 1
type
Player = range[Human..Computer] SortedHand = array[Rank, set[Suit]] # Map card ranks to sets of suits in hand. Game = object deck: Deck # Current content of deck. hands: array[Player, SortedHand] # Player hands. bookCounts: array[Player, Natural] # Number of books. prevChoice: Rank # Previous choice done by computer.
const Quit = -1 # Special value used to indicate to quit.
- ---------------------------------------------------------------------------------------------------
template other(player: Player): Player = 1 - player
- ---------------------------------------------------------------------------------------------------
proc toSortedHand(hand: Hand): SortedHand =
## Convert a hand (which is as a sequence of cards) to a "SortedHand". for card in hand: result[card.rank].incl(card.suit)
- ---------------------------------------------------------------------------------------------------
proc `$`(hand: SortedHand): string =
## Return the representation of a "SortedHand". for rank, suits in hand: for suit in suits: result.addSep(" ") result.add $(rank: rank, suit: suit)
- ---------------------------------------------------------------------------------------------------
proc askQuestion(question: string; answers: openArray[string]): int =
## Ask a question and return the index in the possible answers. ## Return the value "Quit" if an end of file is encountered. try: while true: stdout.write question, ' ' let input = stdin.readLine() result = answers.find(input) if result >= 0: return echo "I don’t understand your answer" except EOFError: result = Quit
- ---------------------------------------------------------------------------------------------------
proc pronoun(player: Player): string {.inline.} =
## Return the pronoun to use according to the player. if player == Human: "You" else: "I"
- ---------------------------------------------------------------------------------------------------
proc checkBookCompleted(game: var Game; player: Player; rank: Rank) =
## Check if a book is completed. if game.hands[player][rank].len == 4: game.hands[player][rank] = {} inc game.bookCounts[player] echo &"{player.pronoun} completed the book for rank: {rank}"
- ---------------------------------------------------------------------------------------------------
proc findChoices(hand: SortedHand): seq[string] =
## Find the possible choices for ranks according to the "SortedHand". for rank, suits in hand: if suits.len != 0: result.add $rank
- ---------------------------------------------------------------------------------------------------
proc updateHands(game: var Game; player: Player; rank: Rank): Player =
## Update the hands after a player has asked for a rank.
let otherPlayer = player.other
# Search in other player hand. if game.hands[otherPlayer][rank].len != 0: # Transfer cards to player. var cards: seq[Card] for suit in game.hands[otherPlayer][rank]: cards.add (rank, suit) echo &"{player.pronoun} get: {cards}" game.hands[player][rank] = game.hands[player][rank] + game.hands[otherPlayer][rank] game.hands[otherPlayer][rank] = {} # Check if a book is completed. game.checkBookCompleted(player, rank) result = player
else: # No cards available. Draw a card from deck. echo "No luck." let card = game.deck.draw() if player == Human: echo "You draw the card: ", card else: echo "I draw a card" game.hands[player][card.rank].incl(card.suit) game.checkBookCompleted(player, card.rank) result = otherPlayer
- ---------------------------------------------------------------------------------------------------
proc humanPlay(game: var Game): Player =
## Process human turn.
echo "Your hand: ", game.hands[Human] var choices = game.hands[Human].findChoices() if choices.len == 0: # Special case if we have no cards in our hand. if game.deck.len == 0: return Computer # Nothing to do. let card = game.deck.draw() echo "You draw the card: ", card game.hands[Human][card.rank].incl(card.suit) choices = game.hands[Human].findChoices()
let choiceString = choices.join(", ") let answer = askQuestion(&"What is your choice ({choiceString})?", choices) if answer == Quit: echo "" quit("Quitting") let choice = parseEnum[Rank](choices[answer]) result = game.updateHands(Human, choice)
- ---------------------------------------------------------------------------------------------------
proc computerPlay(game: var Game): Player =
## Process computer turn.
# The simple (but not so bad) strategy used consists to choose the rank # immediately succeeding to the previous used rank (wrapping around if needed). var choice = game.prevChoice while true: choice = if choice == King: Ace else: succ(choice) if game.hands[Computer][choice].len != 0 or choice == game.prevChoice: break
if game.hands[Computer][choice].len == 0: # Special case if the computer has no cards in hand. if game.deck.len == 0: return Human # Nothing to do. let card = game.deck.draw() echo "I draw a card" game.hands[Computer][card.rank].incl(card.suit) choice = card.rank
game.prevChoice = choice echo "I want cards of rank: ", choice result = game.updateHands(Computer, choice)
- ---------------------------------------------------------------------------------------------------
proc playGame(firstPlayer: Player) =
## Play a game.
var game: Game game.deck = initDeck() game.deck.shuffle() let handSeqs = game.deck.deal(2, 9) game.hands = [handSeqs[Human].toSortedHand(), handSeqs[Computer].toSortedHand()] game.prevChoice = Ace
echo &"{firstPlayer.pronoun} play first.\n"
# Search for books before starting. for rank in Rank: game.checkBookCompleted(Human, rank) game.checkBookCompleted(Computer, rank)
# Play. var player = firstPlayer while game.bookCounts[Human] + game.bookCounts[Computer] != 13: echo &"Your books: {game.bookCounts[Human]} My books: {game.bookCounts[Computer]}" if player == Human: player = game.humanPlay() else: player = game.computerPlay() echo ""
if game.bookCounts[Human] > game.bookCounts[Computer]: echo &"You win with {game.bookCounts[Human]} books against {game.bookCounts[Computer]}" else: echo &"I win with {game.bookCounts[Computer]} books against {game.bookCounts[Human]}"
- ———————————————————————————————————————————————————————————————————————————————————————————————————
var firstPlayer: Player let answer = askQuestion("Who will play first ([h]uman/[c]omputer)?", ["h", "c"]) if answer == Quit:
echo "" quit("Quitting")
firstPlayer = Player(answer)
while true:
playGame(firstPlayer) let answer = askQuestion("Do you want to play another game ([y]es/[n]o)? ", ["y", "n"]) if answer == 1: break firstPlayer = firstPlayer.other()</lang>