示例#1
0
    def test_cards_of_same_suit_all_same_suit(self):
        from Game.Hand import Hand
        from Game.Card import Card

        hand = Hand()
        hand.append(Card(Card.Diamonds, Card.Jack))
        hand.append(Card(Card.Diamonds, Card.Queen))
        hand.append(Card(Card.Diamonds, Card.King))

        self.assertEqual(len(hand.cards_of_same_suit(Card.Diamonds)), 3)
示例#2
0
    def test_cards_of_same_suit_no_mathces(self):
        from Game.Hand import Hand
        from Game.Card import Card

        hand = Hand()
        hand.append(Card(Card.Diamonds, Card.Jack))
        hand.append(Card(Card.Diamonds, Card.Queen))
        hand.append(Card(Card.Diamonds, Card.Queen))

        self.assertEqual(
            hand.cards_of_same_suit(Card.Clubs, Card.Ace),
            [])
示例#3
0
    def test_cards_of_same_suit_1_greater_than(self):
        from Game.Hand import Hand
        from Game.Card import Card

        hand = Hand()
        hand.append(Card(Card.Diamonds, Card.Jack))
        hand.append(Card(Card.Diamonds, Card.Queen))
        card = Card(Card.Diamonds, Card.Ace)
        hand.append(card)

        self.assertEqual(
            hand.cards_of_same_suit(Card.Diamonds, Card.King)[0],
            card)
示例#4
0
    def __init__(self):

        super().__init__()

        for cardKey in Card.Values.keys():
            for suitKey in Card.Suits.keys():
                self.append(Card(suitKey, cardKey))
示例#5
0
 def testNonCardType(self):
     try:
         card = Card(1, 5)
     except:
         pass
     else:
         self.fail()
示例#6
0
    def __init__(self, game_controller, player):

        self.game = game_controller
        self.player = player
        self.opponent = self.game.get_other_player(self.player)
        self.window = Tk()
        self._player_cards = {}
        self._oppenent_cards = {}
        for i in range(5):
            self._player_cards[i] = GUICard()
            self._oppenent_cards[i] = GUICard()
        self._trump_card = GUICard()
        self._deck = GUICard()
        self._leader_card = GUICard()
        self._follower_card = GUICard()
        self._close_deck_button = None
        self._player_swap_trump_button = None
        self._player_points_label = None
        self._opponent_points_label = None
        self._trump_suit_label = None
        self._card_back = Card(Card.Back, 0)
        self.__build_play_space()
        # This feels hacky:
        self.game.on_event_callback_card_played = self.__callback_cards_played
        self._cheat_mode = False
示例#7
0
 def test_notinlist(self):
     try:
         card = Card("4", "5")
     except:
         pass
     else:
         self.fail()
示例#8
0
 def __init__(self):
     self.level_suit = ["Diamond", "Spade", "Heart", "Club"]
     self.level_value = [2, 3, 4, 5, 6, 7, 8, 9, 10, "Jack", "Queen", "King", "Ace"]
     self.lst_cards = []
     for i in self.level_value:
         for z in self.level_suit:
             card = Card(i, z)
             self.lst_cards += [card]
示例#9
0
    def test_available_marriages_no_marriages(self):
        from Game.Deck import Card
        from Game.Hand import Hand

        hand = Hand()
        hand.append(Card(Card.Diamonds, Card.Ten))
        hand.append(Card(Card.Diamonds, Card.King))
        hand.append(Card(Card.Clubs, Card.Ace))
        hand.append(Card(Card.Hearts, Card.King))
        hand.append(Card(Card.Clubs, Card.King))

        expected_marriage = []

        result, marriage = hand.available_marriages()

        self.assertEqual(result, False)
        self.assertEqual(expected_marriage, marriage)
示例#10
0
    def test_available_marriages_out_of_order(self):
        from Game.Deck import Card
        from Game.Hand import Hand

        hand = Hand()
        hand.append(Card(Card.Diamonds, Card.Jack))
        hand.append(Card(Card.Diamonds, Card.King))
        hand.append(Card(Card.Diamonds, Card.Ace))
        hand.append(Card(Card.Diamonds, Card.Ten))
        hand.append(Card(Card.Diamonds, Card.Queen))

        expected_marriage = [Card.Diamonds]

        result, marriage = hand.available_marriages()

        self.assertEqual(result, True)
        self.assertEqual(expected_marriage, marriage)
示例#11
0
class TestCard(TestCase):
    def setUp(self):
        self.card = Card("4", "♠")
        self.other1 = Card("3", "♦")
        self.other3 = Card("5", "♣")
        self.other4 = Card("4", "♥")
        self.other2 = Card("4", "♦")

    #בודקת האם הוא מגדיר את הערכים נכון
    def testValue(self):
        self.assertTrue("4" == self.card.value)

    #בודק האם הוא מגדיר את הסוג נכון
    def testSuits(self):
        self.assertTrue("♠" == self.card.suit)

    #בודק שהוא מעלה value error כאשר הערכים הם לא ברשימת ערכים
    def testNonCardType(self):
        try:
            card = Card(1, 5)
        except:
            pass
        else:
            self.fail()
#מתדוה הבודקת כאשר הtype הוא סטרינג והוא לא ברשימה

    def test_notinlist(self):
        try:
            card = Card("4", "5")
        except:
            pass
        else:
            self.fail()

    #בודק ש__ge__ מחזיק true כאשר הערך יותר גדול
    def testge1(self):
        self.assertTrue(self.card > (self.other2))

    # בודק ש__ge__ מחזיר true כאשר הערך שווה והסוג גדול יותר
    def testge2(self):
        self.assertTrue(self.card > (self.other1))

    # בודק ש__ge__ מחזיר false כאשר הערך יותר קטן
    def testge3(self):
        self.assertFalse(self.card > (self.other3))

    # בודק ש__ge__ מחזיר true כאשר הערך יותר גדול
    def testge4(self):
        self.assertFalse(self.card > (self.other4))

    #פונקציה הבודקת את הrepr
    def testRepr(self):
        self.assertTrue("4♠" == self.card.__repr__())
示例#12
0
 def test_set_Hand1(self):
     dcards = DeckOfCards()
     dcards.deckcards.clear()
     card = Card("4", "♣")
     for i in range(0, 4):
         dcards.deckcards.append(card)
     self.player.cards.clear()
     try:
         self.player.setHand(dcards)
     except:
         pass
     else:
         self.fail()
示例#13
0
 def encode_played(played: Card):
     m, i = played.get_raw()
     return (m - 1) * 4 + i
示例#14
0
class IOHelpers:

    deck_closed_key = -1
    my_points_to_victory_key = -2
    my_unearned_points_key = -3
    opponents_points_to_victory_key = -4
    opponents_unearned_points_key = -5
    match_points_on_offer_to_me_key = -6
    match_points_on_offer_to_opponent_key = -7

    # Make a static list of actions for performance. These should be used for reference only and not passed to the game engine
    d_marriage = Marriage(None, Card(Card.Diamonds, Card.Queen),
                          Card(Card.Diamonds, Card.King))
    s_marriage = Marriage(None, Card(Card.Spades, Card.Queen),
                          Card(Card.Spades, Card.King))
    h_marriage = Marriage(None, Card(Card.Hearts, Card.Queen),
                          Card(Card.Hearts, Card.King))
    c_marriage = Marriage(None, Card(Card.Clubs, Card.Queen),
                          Card(Card.Clubs, Card.King))

    output_actions = {}
    # Cards
    output_actions[0] = Action(card=Card(Card.Diamonds, Card.Jack),
                               marriage=None,
                               swap_trump=False,
                               close_deck=False)
    output_actions[1] = Action(card=Card(Card.Diamonds, Card.Queen),
                               marriage=None,
                               swap_trump=False,
                               close_deck=False)
    output_actions[2] = Action(card=Card(Card.Diamonds, Card.King),
                               marriage=None,
                               swap_trump=False,
                               close_deck=False)
    output_actions[3] = Action(card=Card(Card.Diamonds, Card.Ten),
                               marriage=None,
                               swap_trump=False,
                               close_deck=False)
    output_actions[4] = Action(card=Card(Card.Diamonds, Card.Ace),
                               marriage=None,
                               swap_trump=False,
                               close_deck=False)
    output_actions[5] = Action(card=Card(Card.Spades, Card.Jack),
                               marriage=None,
                               swap_trump=False,
                               close_deck=False)
    output_actions[6] = Action(card=Card(Card.Spades, Card.Queen),
                               marriage=None,
                               swap_trump=False,
                               close_deck=False)
    output_actions[7] = Action(card=Card(Card.Spades, Card.King),
                               marriage=None,
                               swap_trump=False,
                               close_deck=False)
    output_actions[8] = Action(card=Card(Card.Spades, Card.Ten),
                               marriage=None,
                               swap_trump=False,
                               close_deck=False)
    output_actions[9] = Action(card=Card(Card.Spades, Card.Ace),
                               marriage=None,
                               swap_trump=False,
                               close_deck=False)
    output_actions[10] = Action(card=Card(Card.Hearts, Card.Jack),
                                marriage=None,
                                swap_trump=False,
                                close_deck=False)
    output_actions[11] = Action(card=Card(Card.Hearts, Card.Queen),
                                marriage=None,
                                swap_trump=False,
                                close_deck=False)
    output_actions[12] = Action(card=Card(Card.Hearts, Card.King),
                                marriage=None,
                                swap_trump=False,
                                close_deck=False)
    output_actions[13] = Action(card=Card(Card.Hearts, Card.Ten),
                                marriage=None,
                                swap_trump=False,
                                close_deck=False)
    output_actions[14] = Action(card=Card(Card.Hearts, Card.Ace),
                                marriage=None,
                                swap_trump=False,
                                close_deck=False)
    output_actions[15] = Action(card=Card(Card.Clubs, Card.Jack),
                                marriage=None,
                                swap_trump=False,
                                close_deck=False)
    output_actions[16] = Action(card=Card(Card.Clubs, Card.Queen),
                                marriage=None,
                                swap_trump=False,
                                close_deck=False)
    output_actions[17] = Action(card=Card(Card.Clubs, Card.King),
                                marriage=None,
                                swap_trump=False,
                                close_deck=False)
    output_actions[18] = Action(card=Card(Card.Clubs, Card.Ten),
                                marriage=None,
                                swap_trump=False,
                                close_deck=False)
    output_actions[19] = Action(card=Card(Card.Clubs, Card.Ace),
                                marriage=None,
                                swap_trump=False,
                                close_deck=False)
    # Marriages
    output_actions[20] = Action(card=Card(Card.Diamonds, Card.Queen),
                                marriage=d_marriage,
                                swap_trump=False,
                                close_deck=False)
    output_actions[21] = Action(card=Card(Card.Diamonds, Card.King),
                                marriage=d_marriage,
                                swap_trump=False,
                                close_deck=False)
    output_actions[22] = Action(card=Card(Card.Spades, Card.Queen),
                                marriage=s_marriage,
                                swap_trump=False,
                                close_deck=False)
    output_actions[23] = Action(card=Card(Card.Spades, Card.King),
                                marriage=s_marriage,
                                swap_trump=False,
                                close_deck=False)
    output_actions[24] = Action(card=Card(Card.Hearts, Card.Queen),
                                marriage=h_marriage,
                                swap_trump=False,
                                close_deck=False)
    output_actions[25] = Action(card=Card(Card.Hearts, Card.King),
                                marriage=h_marriage,
                                swap_trump=False,
                                close_deck=False)
    output_actions[26] = Action(card=Card(Card.Clubs, Card.Queen),
                                marriage=c_marriage,
                                swap_trump=False,
                                close_deck=False)
    output_actions[27] = Action(card=Card(Card.Clubs, Card.King),
                                marriage=c_marriage,
                                swap_trump=False,
                                close_deck=False)
    #Special Actions
    output_actions[28] = Action(card=None,
                                marriage=None,
                                swap_trump=True,
                                close_deck=False)
    output_actions[29] = Action(card=None,
                                marriage=None,
                                swap_trump=False,
                                close_deck=True)

    @staticmethod
    def card_key(suit, value):
        # Build a unique int for quicker indexing (hopefully?)]
        # maybe build these upfront for performance?
        # e.g. 0 * 20 + 11 for Ace of spades
        # 1 * 20 + 2 = 22 for Jack of clubs
        return suit * 20 + value

    @staticmethod
    def create_input_from_game_state(game, player):

        # Make a flat vector of cards each with a state?
        # Make a convolution grd?
        # Make something else
        #
        #   I have:
        #       20 cards
        #           1 trump card
        #           up to 5 in a players hand
        #           up to 18 won by a player
        #           up to 5 that I know are in the opponents hand
        #           Deck closed
        #           Which marriages could be available
        #           Un-beatable cards (?)
        #
        # Option 1:
        #   Vector for each of the 20 cards:
        #       Value           (int) ??
        #       Suit            (int) ??
        #       my hand         (binary)
        #       their hand      (binary)
        #       won by me       (binary)
        #       won by them     (binary)
        #       Is trump        (binary)
        #
        #   Trump suit          (int)
        #   Deck is closed      (binary)
        #   My pts to victory   (int)
        #   My unearned pts     (int)
        #   Opp pts to victory  (int)
        #   Opp unearned pts    (int)
        #
        #                       20 * 6 + 6 = 126 inputs. Not too bad

        inputs = {}

        for suit in [Card.Diamonds, Card.Clubs, Card.Spades, Card.Hearts]:
            for value in Card.Values.keys():
                inputs[IOHelpers.card_key(suit,
                                          value)] = CardInput(suit, value)

        for card in player.hand:
            card_input = inputs[IOHelpers.card_key(card.suit, card.value)]
            card_input.in_my_hand = True

        # for card in game.get_other_player(player).hand - would be cheating!! Would be an interesting test, though!
        # As is, this handles cases where we know unequivocally that they have part of a marriage or the last 5 cards of the deck
        for card in player.opponent_hand:
            card_input = inputs[IOHelpers.card_key(card.suit, card.value)]
            card_input.in_opponent_hand = True

        for card in player.cards_won:
            card_input = inputs[IOHelpers.card_key(card.suit, card.value)]
            card_input.won_by_me = True

        for card in player.opponent_cards_won:
            card_input = inputs[IOHelpers.card_key(card.suit, card.value)]
            card_input.won_by_opponent = True

        lead_card = game.leading_card
        if lead_card is not None:
            inputs[IOHelpers.card_key(lead_card.suit,
                                      lead_card.value)].is_leading_card = True

        inputs[IOHelpers.deck_closed_key] = 1 if game.deck_closed else 0
        inputs[
            IOHelpers.
            my_points_to_victory_key] = game.match_point_limit - player.game_points
        inputs[IOHelpers.my_unearned_points_key] = 0
        inputs[
            IOHelpers.
            opponents_points_to_victory_key] = game.match_point_limit - player.opponent_game_points
        inputs[IOHelpers.opponents_unearned_points_key] = 0
        inputs[IOHelpers.match_points_on_offer_to_me_key] = 0
        inputs[IOHelpers.match_points_on_offer_to_opponent_key] = 0

        # I now have all the data I need. Now to convert it into something useful.
        # Flat vector is simplest. Or do some clever CNN?

        # Simple flat vector to start with...
        return IOHelpers.__create_flat_tensor(inputs, game)

    @staticmethod
    def __create_flat_tensor(inputs, game):
        # (With performance in mind, it'd be better to create the tensor elements directly instead of using a list but hey...)
        input_vector = []
        for item in inputs.values():
            if type(item) is CardInput:
                input_vector.append(item.suit / 3)  #Normalise suit value
                input_vector.append(
                    item.value / game.game_point_limit
                )  #Normalise card value to fraction of a game
                input_vector.append(item.in_my_hand)
                input_vector.append(item.in_opponent_hand)
                input_vector.append(item.won_by_me)
                input_vector.append(item.won_by_opponent)
                input_vector.append(item.is_leading_card)

        input_vector.append(inputs[IOHelpers.deck_closed_key])
        input_vector.append(inputs[IOHelpers.my_points_to_victory_key] /
                            game.game_point_limit)
        input_vector.append(inputs[IOHelpers.opponents_points_to_victory_key] /
                            game.game_point_limit)

        # input_vector.append(inputs[IOHelpers.my_unearned_points_key] / game.game_point_limit)
        # input_vector.append(inputs[IOHelpers.opponents_unearned_points_key] / game.game_point_limit)
        # input_vector.append(inputs[IOHelpers.match_points_on_offer_to_me_key])
        # input_vector.append(inputs[IOHelpers.match_points_on_offer_to_opponent_key])

        return torch.tensor(input_vector, dtype=torch.float)

    @staticmethod
    def check_action_legal(i, legal_actions):
        is_legal = False
        return_action = None

        output_action = IOHelpers.output_actions[i]
        for action in legal_actions:
            if output_action == action:
                is_legal = True
                return_action = action
                break

        return is_legal, return_action

    @staticmethod
    def get_index_for_action(action):
        for i, output_action in IOHelpers.output_actions.items():
            if action == output_action:
                return i

    @staticmethod
    def get_random_legal_action(game, player):
        player.evaluate_legal_actions(game.leading_card)
        action = random.choice(player.legal_actions)
        i = IOHelpers.get_index_for_action(action)
        return torch.tensor([i], dtype=torch.long), action

    @staticmethod
    def get_legal_actions(game, player):
        player.evaluate_legal_actions(game.leading_card)
        legal_moves = []
        legal_actions = []
        for i, item in enumerate(IOHelpers.output_actions):
            is_legal, action = IOHelpers.check_action_legal(
                i, player.legal_actions)
            legal_moves.append(is_legal)
            legal_actions.append(action)
        return torch.tensor(legal_moves, dtype=torch.bool), legal_actions

    # Pick an action based on values. Ignore illegal moves
    # convert it into an actual action
    @staticmethod
    def policy(q_values, game, player):

        legal_mask, legal_actions = IOHelpers.get_legal_actions(game, player)

        # set all illegal moves to a quality value of -100
        # this is more than a little hacky but in reality filters out illegal moves sufficiently
        q_values[~legal_mask] = -100

        _, indices = q_values.max(0)

        selected_action = legal_actions[indices]
        selected_action_id = indices.unsqueeze(0)

        if selected_action is None:
            raise Exception('No valid action found')

        return selected_action_id, selected_action

    # 3D policy implementation
    @staticmethod
    def policy_batch(q_values, legal_mask):

        # this is hack as hell but works.
        q_values[~legal_mask] = -100
        return q_values.max(1)[0].detach()
示例#15
0
 def __init__(self):
     self._cards = []
     for m in Const.cards:
         for i in range(len(Const.cards[m])):
             self._cards.append(Card(m, i))
示例#16
0
    def play(player: Player, board: Board, my_score: Score, opp_score: Score):
        for card in player._cards:
            m, _ = card.get()
            if len(board._board[m]) > 0:
                index = player._cards.index(card)
                return player.play(index)

        cards = copy.deepcopy(player._cards)
        cards.sort()
        recurrent_score = []
        my_jum = sum(Calculator.calculate(my_score))
        opp_jum = sum(Calculator.calculate(opp_score))
        appeared_card = []
        for t in Const.types:
            appeared_card.extend(my_score.get(t))
            appeared_card.extend(opp_score.get(t))
        appeared_card.sort()

        for i, card in enumerate(cards):
            score = 0
            if (i != 0 and cards[i]._month == cards[i - 1]._month) or (
                    i != len(cards) - 1
                    and cards[i]._month == cards[i + 1]._month):
                score += 100
            if card._month in [5, 7, 10, 12]:
                score += 1
            ms = copy.deepcopy(my_score)
            os = copy.deepcopy(opp_score)

            scored_cards = []
            for idx in range(4):
                scored_cards.append(Card(card._month, idx))
            os.add(cards)
            updated_opp_jum = sum(Calculator.calculate(os))

            if opp_jum < Const.go_score <= updated_opp_jum:
                score -= 1000
            elif updated_opp_jum > opp_jum:
                score -= 100

            potential_score = []
            for idx in range(4):
                potential_score.append(Card(card._month, idx))
            ms.add(cards)
            updated_my_jum = sum(Calculator.calculate(ms))

            if my_jum < updated_my_jum:
                score -= 10 * (21 - (2 * len(player._cards)))

            temp = 30
            for appeared in appeared_card:
                m, _ = appeared.get()
                if m == card._month:
                    temp = 0
            score += temp
            recurrent_score.append(score)

        m = max(recurrent_score)
        selected = [i for i, v in enumerate(recurrent_score) if v == m]
        selected = selected[random.randint(0, len(selected) - 1)]
        card = cards[selected]
        index = player.find_index(card._month, card._index)

        return player.play(index)
示例#17
0
 def setUp(self):
     self.card = Card("4", "♠")
     self.other1 = Card("3", "♦")
     self.other3 = Card("5", "♣")
     self.other4 = Card("4", "♥")
     self.other2 = Card("4", "♦")
示例#18
0
 def __init__(self):
     self._cards = [
         Card(rank, suit) for suit in self.SUITS for rank in self.RANKS
     ]
示例#19
0
 def test_add_card2(self):
     card = Card("4", "♣")
     amount = self.player.cardamount
     self.player.addCard(card)
     self.assertTrue(amount + 1 == self.player.cardamount)
     self.assertIn(card, self.player.cards)
示例#20
0
 def give_cards(self, musik):
     for card in musik:
         self.players[self.round.current_player].set_card_in_hand(
             Card(card["filename"].split('/').pop()[:-4], card["rank"], card["suit"], card["value"]))
示例#21
0
 def startCards(self):
     for i in self.values:
         for j in self.suits:
             card = Card(i, j)
             self.deckcards.append(card)
示例#22
0
	def getOptions(hand, piles, requiredPoints):

		options = []
		typeOptions = []
		# options.append([]) # we need to give the option of doing nothing
		inPiles = {}
		notInPiles = {}
		wilds = {}
		# first let's split the cards we have in our hand into two different parts,
		# the cards that are in piles on the table, and the cards that aren't
		for handPile in hand.getTypes():
			# see if this is in piles
			if handPile == 'R' or handPile == '2':
				wilds[handPile] = hand.getCardCount(handPile)
			elif handPile in piles:
				inPiles[handPile] = hand.getCardCount(handPile)
			else:
				notInPiles[handPile] = hand.getCardCount(handPile)

		# now, have we already laid down the required amount?
		canLay = len(piles) > 0

		if canLay == True:
			# there are piles already on the table, do we have any we can lay down?
			if(len(inPiles) > 0):
				# sweet, we have some cards in our hand that are on the table, we can lay them down
				# give the option to lay down only one type, or all if more than one
				# TODO: give all options (if three cardTypes can be laid down, give options: [1], [2], [3], [1,2], [1,3], [2,3], [1,2,3])
				for cardType, count in inPiles.iteritems():
					options.append([cardType])
					typeOptions.append(cardType)
			# any clean stuff?
			for cardType,count in notInPiles.iteritems():
				if count > 2:
					options.append([cardType])
					typeOptions.append(cardType)
			# now dirty
			# if 'R' in notInPiles or '2' in notInPiles:
			# 	# find sets of two and add wilds to them.
			# 	for cardType,count in notInPiles.iteritems():
			# 		if count == 2

			# can we sprinkle the wilds in?
			for cardType,count in wilds.iteritems():
				typeOptions.append(cardType)
			if len(typeOptions) >= 2:
				for i in range(2, len(typeOptions)+1):
					for x in itertools.combinations(typeOptions, i):
						option = list(x)
						if AIPlayer.isJustWilds(option):
							continue
						options.append(option)
		else:
			# we have to have enough points to lay down
			# first gather clean options
			cleanPoints = 0
			cleanOptions = []
			for cardType,count in notInPiles.iteritems():
				if count > 2 and cardType != 'R' and cardType != '2':
					cleanPoints += Card.getPoints(cardType, count)
					cleanOptions.append(cardType)

			# now gather dirty options



			if cleanPoints >= requiredPoints:
				canLay = True
				# cool, so we can lay down cleanly, let's add these to the options
				for cardType in preOptions:
					options.append([cardType])
					typeOptions.append(cardType)
			else:
				# still not enough points, do we have any wilds?
				if 'R' in notInPiles:
					points += Card.getPoints('R', notInPiles['R'])
				if '2' in notInPiles:
					points += Card.getPoints('2', notInPiles['R'])
				if points >= requiredPoints:
					canLay = True

			# can we lay now?




		# beforeLayOptions = []

		# # get options and points
		# cleanPoints = 0
		# cleanOptions = []
		# for cardType,count in notInPiles.iteritems():
		# 	if count > 2 and cardType != 'R' and cardType != '2':
		# 		cleanPoints += Card.getPoints(cardType, count)
		# 		cleanOptions.append(cardType)

		# if canLay == False:
		# 	if cleanPoints > requiredPoints:
		# 		# okay, so we haven't laid down, but we have enough cleanPoints to lay down
		# 		options.append(cleanOptions)
		# 		canLay = true
		# 	else:
		# 		# okay, we can't lay down cleanly, but do we have enough to lay down dirty?
		# 		if 'R' in notInPiles or '2' in notInPiles:
		# 			# we have wilds... iterate over cleanOptions
		# else:
		# 	# there are piles already on the table, we can put what we have into them
		# 	if(len(inPiles) > 0):
		# 		# yes, we have some cards in our hand that are on the table, we can lay them down
		# 		for cardType, count in inPiles.iteritems():
		# 			options.append(cardType)


		options.append([]) # we need to give the option of doing nothing

		print "number of options", len(options)
		print options
		for i in range(0,len(options)):
			print "option " + `i+1`
			for card in options[i]:
				print card+": "+`hand.getCardCount(card)`
			print ""