2
\$\begingroup\$

King of the Cards

Code available here!

In this King of the Hill challenge, you must write a bot that can play Crazy Eights. This is a card game often played by children, in which the objective is to empty your hand.

How to Play

The game of Crazy Eights is deceptively simple. At the beginning of the game, each player gets dealt a hand of cards (in this case eight), with the remaining cards placed in the middle of the table as the draw pile. The top card is then placed face up and serves as the beginning of the discard pile. Then, each player can discard one card per turn if that card has a matching suit or rank with the top card on the discard pile. They may also play an 8, which allows them to change the effective suit of the 8 and therefore the suit the next player must follow. The played card then becomes the top card. If the player does not have any matching cards, they must draw from the draw pile until they get a matching card and play that. If they exhaust the draw pile, play passes to the next player. Players may draw at any time, even if they have playable cards (which does not count as a turn).

For example, if 6♣ is played, the next player:

  • Can play a 6 of any suit
  • Can play any club
  • Can play an 8 (and then must declare a suit)
  • Can draw and continue their turn.

If the draw pile runs out, then the discard pile (except for the top card) is shuffled and becomes the new draw pile.

The game ends once a player runs out of cards, in which case they are declared the winner. (This differs from normal Crazy Eights, and is included to make this game a bit simpler.)

Bots

Bots must be written in Python. Bots will have access to the kotc module, which supplies these classes:

  • KOTCBot, which bots must extend
  • Card, which represents a card
  • Suit and Rank, enums representing the suit and value of a card

Bots must implement a play method, which takes as input a Card representing the top card on the discard pile. This method must return a Card within that bot's hand. If the returned Card is not in the bot's hand that bot is disqualified. (I will leave a comment on it with information about the state of the game when it happened.) However, if the Card is an Eight then only the rank will be checked against the bot's hand. If the bot has no playable cards in its hand, the play method will NOT be called and the controller will automatically draw cards on behalf of the bot and add them to its hand. The bot should NEVER modify its hand! This will be done by the controller. The play method may also return None or False, which will cause its turn to be skipped.

Bots will compete against each other in matches of two, in an elimination-style tournament bracket. The winner will advance onwards, and the loser will be executed eliminated.

API

KOTCBot

This class is the actual bot.

Methods and properties: (Do NOT override any of these in your bot)

  • draw: When called, this function draws a card from the pile and adds it to the bot's hand. It also returns the card drawn.
  • hand: This property is a list of Cards representing the bot's hand.
  • arena: This property is the KOTCArena instance the bot is playing in.

KOTCArena

This class is accessible through the arena property of the Bot. It has three functions available to the bots:

  • handSizes: Returns a list of the lengths of the hands of the other bots
  • discardSize: Returns the size of the discard pile
  • drawSize: Returns the size of the draw pile

Card

The Card class represents a card, and takes a Suit and Rank when constructed. This class must be returned by the bot's play method. Its suit and rank can be accessed through their respective properties.

  • all: This classmethod takes no parameters and returns a 52-item list of all possible card combinations.

Note: All enumeration members are UPPERCASE.

Suit

Members of this enum:

  • CLUBS
  • DIAMONDS
  • SPADES
  • HEARTS

Rank

Members of this enum:

  • ACE
  • KING
  • QUEEN
  • JACK
  • TWO through TEN

Example Bot

This bot just plays any available card, without using eights.

import kotc

class ExampleBot(kotc.KOTCBot):
  def play(self, discard):
    for card in self.hand:
      if card.suit == discard.suit or card.rank == discard.rank:
        return card
\$\endgroup\$
12
  • 1
    \$\begingroup\$ You could instead run bots in rounds of three or four at a time. I think a tournament bracket relies on a lot of luuck. \$\endgroup\$
    – emanresu A
    May 17, 2022 at 20:08
  • \$\begingroup\$ @emanresuA I intend to run each game multiple times to fix this. \$\endgroup\$
    – Ginger
    May 17, 2022 at 20:11
  • 1
    \$\begingroup\$ "Players may draw at any time"; what will happen if we run out of cards, even discarded before? For example, I write while True: self.draw()? \$\endgroup\$
    – tsh
    May 18, 2022 at 3:01
  • 1
    \$\begingroup\$ Could you post the code for running a simulation of the KOTC? I would like to test things out on my own, as well as solve the ambiguities, such as the actual code of your enums. Finally, for convenience, could you add a function that returns a list of all 52 possible cards? \$\endgroup\$
    – Ryan Fu
    May 19, 2022 at 0:39
  • 1
    \$\begingroup\$ Is the simulation going to use an actual 52 card deck with 52 unique cards in it or does it just give me a random card whenever I draw one? \$\endgroup\$
    – treterelda
    May 19, 2022 at 13:47

1 Answer 1

3
\$\begingroup\$

BasicBot

import kotc
from random import shuffle
class BasicBot(kotc.KOTCBot):
  shuffle(self.hand)
  def play(self, discard):
    for card in self.hand:
      if (card.rank == kotc.Rank.EIGHT):
        playables = 0
        for card2 in self.hand:
          if card.suit == discard.suit or card.rank == discard.rank:
            playables+=1
        if playables<2:
          return card2

      if card.suit == discard.suit or card.rank == discard.rank:
        return card
    for card in self.hand:
        if card.suit == discard.suit or card.rank == discard.rank:
            return card

I think this will work. Pretty much ExampleBot, except it will play an eight if it has less than two other cards it can play. Currently doesn't prioritize playing a specific suit (that's next on my list of goals) but it still should be better than BasicBot.

\$\endgroup\$
7
  • \$\begingroup\$ How would I declare a suit? I don't know if that's working right now. \$\endgroup\$
    – Romanp
    May 17, 2022 at 20:13
  • 2
    \$\begingroup\$ I edited it for you. \$\endgroup\$
    – Ginger
    May 17, 2022 at 20:19
  • 2
    \$\begingroup\$ I don't think this works as is, because random.shuffle shuffles the list in place and returns None \$\endgroup\$
    – gsitcia
    May 17, 2022 at 21:41
  • 3
    \$\begingroup\$ You want for card in shuffle(self.hand) or self.hand: if you want to shuffle your hand in the for statement. Or simply call shuffle(self.hand) in the line before for card in self.hand). \$\endgroup\$
    – Noodle9
    May 17, 2022 at 22:09
  • \$\begingroup\$ Have you tested ExampleBot vs BasicBot? \$\endgroup\$
    – Romanp
    May 18, 2022 at 23:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.