Beispiel #1
0
    def clicked(self, button_name):
        if len(self.model.show_stats
               ) > 0:  # we are already showing stats, unshow
            self.model.show_stats = []
        else:
            num_games = str(len(self.model.times))
            best_time = "No Time Data Yet"
            avg_time = "No Time Data Yet"
            if len(self.model.times) > 0:
                best_time = format_secs(min(self.model.times))
                avg_time = format_secs(
                    sum(self.model.times) / len(self.model.times))

            message_box = planes.Plane(
                'message_box',
                pygame.Rect(left_margin, top_margin, 13 * WINDOW_WIDTH / 16,
                            (WINDOW_HEIGHT - 300)))
            message_box.image.fill((0, 0, 0))

            win_stats = "Game Stats \n" + "Number of Games: " + num_games + "\nBest time: " + best_time + "\nAverage time: " + avg_time

            message_texts = []
            lines = win_stats.split("\n")
            box_width = 13 * WINDOW_WIDTH / 16
            for line in lines:
                message_texts.append(
                    ScreenText(
                        line, line,
                        pygame.Rect(left_margin,
                                    top_margin + 60 * (lines.index(line) + 1),
                                    box_width, 45), FONT_BIG))

            #message_text.background_color = (255,0,0) #fixthis not transparent
            self.model.show_stats.append(message_box)
            self.model.show_stats += message_texts
Beispiel #2
0
    def __init__(self, model):
        ########################
        # GAME SCREEN ELEMENTS #
        ########################
        self.deck = []
        self.model = model

        #  make 81 unique cards, add to deck
        for color in COLORS:
            for shape in SHAPES:
                for number in NUMBERS:
                    for shade in SHADES:
                        card_to_add = Card(color + shape + shade + str(number),
                                           color, shape, number, shade)
                        self.deck.append(card_to_add)
                        card_to_add.image = pygame.image.load(
                            "img/" + card_to_add.name + ".png")

        self.actors = []

        self.in_play_cards = []
        self.clicked_cards = []
        self.out_of_play_cards = []

        self.sets_found = 0
        self.sets_wrong = 0  # should we take off points for these?
        self.hints_left = NUM_HINTS

        #### Elements of a game ####
        self.sets_found_label = ScreenText(
            "sets_found_label", "Sets: " + str(self.sets_found),
            pygame.Rect(3 * WINDOW_WIDTH / 4, 290, WINDOW_WIDTH / 4, 50),
            FONT_BIG)
        self.left_in_deck_label = ScreenText(
            "left_in_deck_label", "Deck: " + str(
                len(self.deck) -
                (len(self.in_play_cards) + len(self.out_of_play_cards))),
            pygame.Rect(3 * WINDOW_WIDTH / 4, 505, WINDOW_WIDTH / 4, 25),
            FONT_SMALL)
        if not AUTO_ADD3:
            self.add3_button = AddThreeCardsButton(
                "add_three_cards_button",
                pygame.Rect(
                    3 * WINDOW_WIDTH / 4 + (WINDOW_WIDTH / 4 - 200) / 2, 360,
                    100, 100), AddThreeCardsButton.clicked, self)
        if HINTS:
            self.hint_button = HintButton(
                "hint_button",
                pygame.Rect(
                    3 * WINDOW_WIDTH / 4 + (WINDOW_WIDTH / 4 - 200) / 2 + 100,
                    360, 100, 100), HintButton.clicked, self)
            self.hints_left_label = ScreenText(
                "hints_left_label", "Hints Remaining: " + str(self.hints_left),
                pygame.Rect(3 * WINDOW_WIDTH / 4, 475, WINDOW_WIDTH / 4, 25),
                FONT_SMALL)

        self.logo = planes.Plane(
            "setlogo", pygame.Rect(3 * WINDOW_WIDTH / 4, 50, 240, 162), False,
            False)
        self.logo.image = pygame.image.load("img/set.jpg")

        #### CATEGORIES ####
        self.gamebuttons = [self.logo]
        self.gamelabels = [self.sets_found_label, self.left_in_deck_label]
        if HINTS:
            self.gamebuttons.append(self.hint_button)
            self.gamelabels.append(self.hints_left_label)
        if not AUTO_ADD3:
            self.gamebuttons.append(self.add3_button)

        # start the game
        self.add_new_cards(12)
Beispiel #3
0
class Game():
    """
    A Game is a single game that ends when won, lost or cancelled
    """
    def __init__(self, model):
        ########################
        # GAME SCREEN ELEMENTS #
        ########################
        self.deck = []
        self.model = model

        #  make 81 unique cards, add to deck
        for color in COLORS:
            for shape in SHAPES:
                for number in NUMBERS:
                    for shade in SHADES:
                        card_to_add = Card(color + shape + shade + str(number),
                                           color, shape, number, shade)
                        self.deck.append(card_to_add)
                        card_to_add.image = pygame.image.load(
                            "img/" + card_to_add.name + ".png")

        self.actors = []

        self.in_play_cards = []
        self.clicked_cards = []
        self.out_of_play_cards = []

        self.sets_found = 0
        self.sets_wrong = 0  # should we take off points for these?
        self.hints_left = NUM_HINTS

        #### Elements of a game ####
        self.sets_found_label = ScreenText(
            "sets_found_label", "Sets: " + str(self.sets_found),
            pygame.Rect(3 * WINDOW_WIDTH / 4, 290, WINDOW_WIDTH / 4, 50),
            FONT_BIG)
        self.left_in_deck_label = ScreenText(
            "left_in_deck_label", "Deck: " + str(
                len(self.deck) -
                (len(self.in_play_cards) + len(self.out_of_play_cards))),
            pygame.Rect(3 * WINDOW_WIDTH / 4, 505, WINDOW_WIDTH / 4, 25),
            FONT_SMALL)
        if not AUTO_ADD3:
            self.add3_button = AddThreeCardsButton(
                "add_three_cards_button",
                pygame.Rect(
                    3 * WINDOW_WIDTH / 4 + (WINDOW_WIDTH / 4 - 200) / 2, 360,
                    100, 100), AddThreeCardsButton.clicked, self)
        if HINTS:
            self.hint_button = HintButton(
                "hint_button",
                pygame.Rect(
                    3 * WINDOW_WIDTH / 4 + (WINDOW_WIDTH / 4 - 200) / 2 + 100,
                    360, 100, 100), HintButton.clicked, self)
            self.hints_left_label = ScreenText(
                "hints_left_label", "Hints Remaining: " + str(self.hints_left),
                pygame.Rect(3 * WINDOW_WIDTH / 4, 475, WINDOW_WIDTH / 4, 25),
                FONT_SMALL)

        self.logo = planes.Plane(
            "setlogo", pygame.Rect(3 * WINDOW_WIDTH / 4, 50, 240, 162), False,
            False)
        self.logo.image = pygame.image.load("img/set.jpg")

        #### CATEGORIES ####
        self.gamebuttons = [self.logo]
        self.gamelabels = [self.sets_found_label, self.left_in_deck_label]
        if HINTS:
            self.gamebuttons.append(self.hint_button)
            self.gamelabels.append(self.hints_left_label)
        if not AUTO_ADD3:
            self.gamebuttons.append(self.add3_button)

        # start the game
        self.add_new_cards(12)

    # Add cards to the in-play cards
    # Number = number of cards to add
    # Index allows adding 1 card in the same position as a removed card
    # Does not check whether we SHOULD because assumes we have checked that before calling
    def add_new_cards(self, number, index=0):
        if not len(self.in_play_cards) + len(self.out_of_play_cards) == len(
                self.deck):
            i = 0
            while i < number:
                num = random.randint(0, len(self.deck) - 1)
                card = self.deck[num]
                if card not in self.in_play_cards and card not in self.out_of_play_cards:
                    self.in_play_cards.insert(index, card)
                    i += 1
            if AUTO_ADD3:
                if not self.check_if_any_sets():
                    self.add_new_cards(3)

    # Checks if any sets on the board
    def check_if_any_sets(self):
        for card1 in self.in_play_cards:
            for card2 in self.in_play_cards:
                for card3 in self.in_play_cards:
                    if card1 != card2 and card2 != card3 and card1 != card3:
                        if check_set(card1, card2, card3):
                            return True
        return False

    # Checks if game is won
    def check_if_won(self):
        return(not self.check_if_any_sets()) and \
               (len(self.in_play_cards) + len(self.out_of_play_cards) == len(self.deck))

    # Game can only be lost if playing in time mode
    def check_in_play(self):
        return True  # TODO: add multiplayer set counter so winner is one with most sets

    # Called infinitely
    def update(self):
        # if game not in play, display messages, not cards
        if not self.check_in_play():
            self.actors = []
            self.actors += self.gamelabels + self.gamebuttons
            if HINTS:
                self.hints_left_label.update_text("Hints Remaining: " +
                                                  str(self.hints_left))
            self.left_in_deck_label.update_text("Deck: " + str(
                len(self.deck) -
                (len(self.in_play_cards) + len(self.out_of_play_cards))))

            message_box = planes.Plane(
                'message_box',
                pygame.Rect(
                    LEFT_MARGIN, TOP_MARGIN, 3 * CARD_WIDTH + 2 * SPACE_HORIZ,
                    4 * CARD_HEIGHT + 3 *
                    ((WINDOW_HEIGHT - 4 * CARD_HEIGHT - 2 * TOP_MARGIN) / 3)))
            message_box.image.fill((0, 0, 0))
            message_texts = []

            self.actors.append(message_box)
            self.actors += message_texts

        # game in play
        else:
            self.actors = []

            #check which cards are clicked
            self.clicked_cards = []
            for card in self.in_play_cards:
                self.actors.append(card)
                if card.been_clicked:
                    self.clicked_cards.append(card)
                card.update()

            #add click boxes
            for card in self.clicked_cards:
                clicked_box = planes.Plane(
                    "box" + card.name,
                    pygame.Rect(card.rect.x - 5, card.rect.y - 5,
                                card.rect.width + 10, card.rect.height + 10),
                    False, False)
                clicked_box.image = pygame.image.load("img/clickbox.png")
                self.actors.insert(0, clicked_box)

            #check for sets
            if len(self.clicked_cards) == 3:
                is_set = check_set(self.clicked_cards[0],
                                   self.clicked_cards[1],
                                   self.clicked_cards[2])
                if is_set:
                    self.sets_found += 1
                    self.sets_found_label.update_text("Sets: " +
                                                      str(self.sets_found))

                    #remove cards and add new ones
                    for card in self.clicked_cards:
                        self.out_of_play_cards.append(card)
                        index = self.in_play_cards.index(card)
                        self.in_play_cards.remove(card)
                        if len(self.in_play_cards) < 12:
                            self.add_new_cards(1, index)
                else:
                    self.sets_wrong += 1
                for card in self.clicked_cards:
                    card.been_clicked = False

            self.actors += self.gamelabels + self.gamebuttons
            if HINTS:
                self.hints_left_label.update_text("Hints Remaining: " +
                                                  str(self.hints_left))
            self.left_in_deck_label.update_text("Deck: " + str(
                len(self.deck) -
                (len(self.in_play_cards) + len(self.out_of_play_cards))))
Beispiel #4
0
    def update(self):
        # if game not in play, display messages, not cards
        if not self.check_in_play():
            self.actors = []
            self.actors += self.gamelabels + self.gamebuttons
            self.hints_left_label.update_text("Hints Remaining: " +
                                              str(self.hints_left))
            self.left_in_deck_label.update_text("Deck: " + str(
                len(self.deck) -
                (len(self.in_play_cards) + len(self.out_of_play_cards))))

            message_box = planes.Plane(
                'message_box',
                pygame.Rect(
                    left_margin, top_margin, 3 * CARD_WIDTH + 2 * space_horiz,
                    4 * CARD_HEIGHT + 3 *
                    ((WINDOW_HEIGHT - 4 * CARD_HEIGHT - 2 * top_margin) / 3)))
            message_box.image.fill((0, 0, 0))
            message_texts = []

            # if game won or lost, note time game ended
            if self.check_if_won() or self.check_if_lost():
                if self.end_time == 0:
                    self.end_time = pygame.time.get_ticks()

                total_time = self.end_time - self.start_time - self.pause_time

                if self.check_if_won() and not self.added_time:
                    self.model.add_time(
                        (total_time + (self.sets_wrong * TIME_DEDUC)) / 1000)
                    self.added_time = True

                best_time = ""
                if len(self.model.times) == 0:
                    best_time = format_secs(total_time / 1000)
                else:
                    best_time = format_secs(min(self.model.times))

                win_stats = "Game Complete! \n" + \
                   "Total time: " + format_secs ((self.end_time - self.start_time - self.pause_time)/ 1000) + "\n" +\
                   "Best time: " + best_time

                win_stats_with_loss = "Game Complete! \n" + \
                       "Total time: " + format_secs (total_time/ 1000) + "\n" +\
                       "Incorrect Sets: " + str(self.sets_wrong) + "\n" +\
                       "Adjusted Time: " + format_secs ((total_time+(self.sets_wrong*TIME_DEDUC))/ 1000) + "\n" +\
                       "Best time: " + best_time

                lose_stats = "Game Over!"

                stats = win_stats_with_loss
                if self.check_if_lost():
                    stats = lose_stats

                lines = stats.split("\n")
                box_width = 3 * CARD_WIDTH + 2 * space_horiz
                for line in lines:
                    message_texts.append(
                        ScreenText(
                            line, line,
                            pygame.Rect(
                                left_margin,
                                top_margin + 50 * (lines.index(line) + 1),
                                box_width, 45), FONT_BIG))

            elif self.paused_time_at != 0:  #game is paused
                message_texts.append(
                    ScreenText(
                        "message_text", "Game Paused",
                        pygame.Rect(
                            left_margin, top_margin,
                            3 * CARD_WIDTH + 2 * space_horiz,
                            4 * CARD_HEIGHT + 3 *
                            ((WINDOW_HEIGHT - 4 * CARD_HEIGHT - 2 * top_margin)
                             / 3)), FONT_BIG))

            self.actors.append(message_box)
            self.actors += message_texts
            self.actors += self.pausebuttons

        # game in play
        else:
            self.time_box.update()
            self.actors = [self.time_box]

            #check which cards are clicked
            self.clicked_cards = []
            for card in self.in_play_cards:
                self.actors.append(card)
                if card.been_clicked:
                    self.clicked_cards.append(card)
                card.update()

            #add click boxes
            for card in self.clicked_cards:
                clicked_box = planes.Plane(
                    "box" + card.name,
                    pygame.Rect(card.rect.x - 5, card.rect.y - 5,
                                card.rect.width + 10, card.rect.height + 10),
                    False, False)
                clicked_box.image = pygame.image.load("img/clickbox.png")
                self.actors.insert(1, clicked_box)

            #check for sets
            if len(self.clicked_cards) == 3:
                is_set = check_set(self.clicked_cards[0],
                                   self.clicked_cards[1],
                                   self.clicked_cards[2])
                if is_set:
                    self.sets_found += 1
                    self.sets_found_label.update_text("Sets: " +
                                                      str(self.sets_found))

                    # reset the time box
                    self.time_box.rect.y = -WINDOW_HEIGHT

                    #remove cards and add new ones
                    for card in self.clicked_cards:
                        self.out_of_play_cards.append(card)
                        index = self.in_play_cards.index(card)
                        self.in_play_cards.remove(card)
                        if len(self.in_play_cards) < 12:
                            self.add_new_cards(1, index)
                else:
                    self.sets_wrong += 1
                for card in self.clicked_cards:
                    card.been_clicked = False

            self.actors += self.gamelabels + self.gamebuttons
            self.time_label.update_text("Time: " + format_secs(
                (pygame.time.get_ticks() - self.start_time - self.pause_time) /
                1000))
            self.hints_left_label.update_text("Hints Remaining: " +
                                              str(self.hints_left))
            self.left_in_deck_label.update_text("Deck: " + str(
                len(self.deck) -
                (len(self.in_play_cards) + len(self.out_of_play_cards))))
Beispiel #5
0
    def __init__(self, game_select, model):
        ########################
        # GAME SCREEN ELEMENTS #
        ########################
        self.deck = []

        self.model = model
        self.game_select = game_select

        self.pause_time = 0
        self.paused_time_at = 0

        self.start_time = pygame.time.get_ticks()
        self.end_time = 0  # time game ended at

        #make 81 unique cards, add to deck
        for color in colors:
            for shape in shapes:
                for number in numbers:
                    for shade in shades:
                        card_to_add = Card(color + shape + shade + str(number),
                                           color, shape, number, shade)
                        self.deck.append(card_to_add)
                        card_to_add.image = pygame.image.load(
                            "img/" + card_to_add.name + ".png")

        self.actors = []

        self.in_play_cards = []
        self.clicked_cards = []
        self.out_of_play_cards = []

        self.sets_found = 0
        self.sets_wrong = 0  # should we take off points for these?
        self.hints_left = NUM_HINTS

        # tells if we have already added the game time to the times []
        # prevents from adding the time on every update loop
        self.added_time = False

        #### Elements of a game ####
        self.sets_found_label = ScreenText(
            "sets_found_label", "Sets: " + str(self.sets_found),
            pygame.Rect(3 * WINDOW_WIDTH / 4, 290, WINDOW_WIDTH / 4, 50),
            FONT_BIG)
        self.time_label = ScreenText(
            "time_label", "Time: " + format_secs(self.start_time / 1000),
            pygame.Rect(3 * WINDOW_WIDTH / 4, 220, WINDOW_WIDTH / 4, 100),
            FONT_BIG)
        self.left_in_deck_label = ScreenText(
            "left_in_deck_label", "Deck: " + str(
                len(self.deck) -
                (len(self.in_play_cards) + len(self.out_of_play_cards))),
            pygame.Rect(3 * WINDOW_WIDTH / 4, 505, WINDOW_WIDTH / 4, 25),
            FONT_SMALL)

        self.add3_button = AddThreeCardsButton(
            "add_three_cards_button",
            pygame.Rect(3 * WINDOW_WIDTH / 4 + (WINDOW_WIDTH / 4 - 200) / 2,
                        360, 100, 100), AddThreeCardsButton.clicked, self)
        self.hint_button = HintButton(
            "hint_button",
            pygame.Rect(
                3 * WINDOW_WIDTH / 4 + (WINDOW_WIDTH / 4 - 200) / 2 + 100, 360,
                100, 100), HintButton.clicked, self)
        self.pause_button = PauseButton(
            "pause_button",
            pygame.Rect(
                3 * WINDOW_WIDTH / 4 + (WINDOW_WIDTH / 4 - 200) / 2 + 50,
                WINDOW_HEIGHT - 120, 100, 100), PauseButton.clicked, self)
        self.hints_left_label = ScreenText(
            "hints_left_label", "Hints Remaining: " + str(self.hints_left),
            pygame.Rect(3 * WINDOW_WIDTH / 4, 475, WINDOW_WIDTH / 4, 25),
            FONT_SMALL)
        self.logo = planes.Plane(
            "setlogo", pygame.Rect(3 * WINDOW_WIDTH / 4, 50, 240, 162), False,
            False)
        self.logo.image = pygame.image.load("img/set.jpg")
        self.time_box = TimeBox(
            "time_box",
            pygame.Rect(0, -WINDOW_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT),
            game_select)

        #### PAUSE SCREEN BUTTONS ####
        message_width = 3 * CARD_WIDTH + 2 * space_horiz  # width of playing field

        self.play_button = PlayButton(
            "play_button",
            pygame.Rect(2 * message_width / 5 - 50, WINDOW_HEIGHT - 300, 100,
                        100), PlayButton.clicked, self)
        self.restart_button = RestartButton(
            "restart_button",
            pygame.Rect(3 * message_width / 5 - 50, WINDOW_HEIGHT - 300, 100,
                        100), RestartButton.clicked, self)
        self.back_button = BackButton(
            "back_button",
            pygame.Rect(4 * message_width / 5 - 50, WINDOW_HEIGHT - 300, 100,
                        100), BackButton.clicked, self)
        #### CATEGORIES ####
        self.gamebuttons = [
            self.add3_button, self.hint_button, self.pause_button, self.logo
        ]
        self.gamelabels = [
            self.sets_found_label, self.time_label, self.hints_left_label,
            self.left_in_deck_label
        ]
        self.pausebuttons = [
            self.play_button, self.restart_button, self.back_button
        ]

        # start the game
        self.add_new_cards(12)
Beispiel #6
0
class Game():
    def __init__(self, game_select, model):
        ########################
        # GAME SCREEN ELEMENTS #
        ########################
        self.deck = []

        self.model = model
        self.game_select = game_select

        self.pause_time = 0
        self.paused_time_at = 0

        self.start_time = pygame.time.get_ticks()
        self.end_time = 0  # time game ended at

        #make 81 unique cards, add to deck
        for color in colors:
            for shape in shapes:
                for number in numbers:
                    for shade in shades:
                        card_to_add = Card(color + shape + shade + str(number),
                                           color, shape, number, shade)
                        self.deck.append(card_to_add)
                        card_to_add.image = pygame.image.load(
                            "img/" + card_to_add.name + ".png")

        self.actors = []

        self.in_play_cards = []
        self.clicked_cards = []
        self.out_of_play_cards = []

        self.sets_found = 0
        self.sets_wrong = 0  # should we take off points for these?
        self.hints_left = NUM_HINTS

        # tells if we have already added the game time to the times []
        # prevents from adding the time on every update loop
        self.added_time = False

        #### Elements of a game ####
        self.sets_found_label = ScreenText(
            "sets_found_label", "Sets: " + str(self.sets_found),
            pygame.Rect(3 * WINDOW_WIDTH / 4, 290, WINDOW_WIDTH / 4, 50),
            FONT_BIG)
        self.time_label = ScreenText(
            "time_label", "Time: " + format_secs(self.start_time / 1000),
            pygame.Rect(3 * WINDOW_WIDTH / 4, 220, WINDOW_WIDTH / 4, 100),
            FONT_BIG)
        self.left_in_deck_label = ScreenText(
            "left_in_deck_label", "Deck: " + str(
                len(self.deck) -
                (len(self.in_play_cards) + len(self.out_of_play_cards))),
            pygame.Rect(3 * WINDOW_WIDTH / 4, 505, WINDOW_WIDTH / 4, 25),
            FONT_SMALL)

        self.add3_button = AddThreeCardsButton(
            "add_three_cards_button",
            pygame.Rect(3 * WINDOW_WIDTH / 4 + (WINDOW_WIDTH / 4 - 200) / 2,
                        360, 100, 100), AddThreeCardsButton.clicked, self)
        self.hint_button = HintButton(
            "hint_button",
            pygame.Rect(
                3 * WINDOW_WIDTH / 4 + (WINDOW_WIDTH / 4 - 200) / 2 + 100, 360,
                100, 100), HintButton.clicked, self)
        self.pause_button = PauseButton(
            "pause_button",
            pygame.Rect(
                3 * WINDOW_WIDTH / 4 + (WINDOW_WIDTH / 4 - 200) / 2 + 50,
                WINDOW_HEIGHT - 120, 100, 100), PauseButton.clicked, self)
        self.hints_left_label = ScreenText(
            "hints_left_label", "Hints Remaining: " + str(self.hints_left),
            pygame.Rect(3 * WINDOW_WIDTH / 4, 475, WINDOW_WIDTH / 4, 25),
            FONT_SMALL)
        self.logo = planes.Plane(
            "setlogo", pygame.Rect(3 * WINDOW_WIDTH / 4, 50, 240, 162), False,
            False)
        self.logo.image = pygame.image.load("img/set.jpg")
        self.time_box = TimeBox(
            "time_box",
            pygame.Rect(0, -WINDOW_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT),
            game_select)

        #### PAUSE SCREEN BUTTONS ####
        message_width = 3 * CARD_WIDTH + 2 * space_horiz  # width of playing field

        self.play_button = PlayButton(
            "play_button",
            pygame.Rect(2 * message_width / 5 - 50, WINDOW_HEIGHT - 300, 100,
                        100), PlayButton.clicked, self)
        self.restart_button = RestartButton(
            "restart_button",
            pygame.Rect(3 * message_width / 5 - 50, WINDOW_HEIGHT - 300, 100,
                        100), RestartButton.clicked, self)
        self.back_button = BackButton(
            "back_button",
            pygame.Rect(4 * message_width / 5 - 50, WINDOW_HEIGHT - 300, 100,
                        100), BackButton.clicked, self)
        #### CATEGORIES ####
        self.gamebuttons = [
            self.add3_button, self.hint_button, self.pause_button, self.logo
        ]
        self.gamelabels = [
            self.sets_found_label, self.time_label, self.hints_left_label,
            self.left_in_deck_label
        ]
        self.pausebuttons = [
            self.play_button, self.restart_button, self.back_button
        ]

        # start the game
        self.add_new_cards(12)

    # Add cards to the in-play cards
    # Number = number of cards to add
    # Index allows adding 1 card in the same position as a removed card
    # Does not check whether we SHOULD because assumes we have checked that before calling
    def add_new_cards(self, number, index=0):
        if not len(self.in_play_cards) + len(self.out_of_play_cards) == len(
                self.deck):
            i = 0
            while i < number:
                num = random.randint(0, len(self.deck) - 1)
                card = self.deck[num]
                if card not in self.in_play_cards and card not in self.out_of_play_cards:
                    self.in_play_cards.insert(index, card)
                    i += 1

    # Checks if any sets on the board
    def check_if_any_sets(self):
        for card1 in self.in_play_cards:
            for card2 in self.in_play_cards:
                for card3 in self.in_play_cards:
                    if card1 != card2 and card2 != card3 and card1 != card3:
                        if check_set(card1, card2, card3):
                            return True
        return False

    # Checks if game is won
    def check_if_won(self):
        return (not self.check_if_any_sets ()) and \
            (len (self.in_play_cards) + len (self.out_of_play_cards) == len (self.deck))

    # Game can only be lost if playing in time mode
    def check_if_lost(self):
        return self.time_box.rect.y >= 0

    # Game can only be lost if playing in time mode
    def check_in_play(self):
        return not self.check_if_won() and not self.check_if_lost(
        ) and self.paused_time_at == 0

    # Called infinitely
    def update(self):
        # if game not in play, display messages, not cards
        if not self.check_in_play():
            self.actors = []
            self.actors += self.gamelabels + self.gamebuttons
            self.hints_left_label.update_text("Hints Remaining: " +
                                              str(self.hints_left))
            self.left_in_deck_label.update_text("Deck: " + str(
                len(self.deck) -
                (len(self.in_play_cards) + len(self.out_of_play_cards))))

            message_box = planes.Plane(
                'message_box',
                pygame.Rect(
                    left_margin, top_margin, 3 * CARD_WIDTH + 2 * space_horiz,
                    4 * CARD_HEIGHT + 3 *
                    ((WINDOW_HEIGHT - 4 * CARD_HEIGHT - 2 * top_margin) / 3)))
            message_box.image.fill((0, 0, 0))
            message_texts = []

            # if game won or lost, note time game ended
            if self.check_if_won() or self.check_if_lost():
                if self.end_time == 0:
                    self.end_time = pygame.time.get_ticks()

                total_time = self.end_time - self.start_time - self.pause_time

                if self.check_if_won() and not self.added_time:
                    self.model.add_time(
                        (total_time + (self.sets_wrong * TIME_DEDUC)) / 1000)
                    self.added_time = True

                best_time = ""
                if len(self.model.times) == 0:
                    best_time = format_secs(total_time / 1000)
                else:
                    best_time = format_secs(min(self.model.times))

                win_stats = "Game Complete! \n" + \
                   "Total time: " + format_secs ((self.end_time - self.start_time - self.pause_time)/ 1000) + "\n" +\
                   "Best time: " + best_time

                win_stats_with_loss = "Game Complete! \n" + \
                       "Total time: " + format_secs (total_time/ 1000) + "\n" +\
                       "Incorrect Sets: " + str(self.sets_wrong) + "\n" +\
                       "Adjusted Time: " + format_secs ((total_time+(self.sets_wrong*TIME_DEDUC))/ 1000) + "\n" +\
                       "Best time: " + best_time

                lose_stats = "Game Over!"

                stats = win_stats_with_loss
                if self.check_if_lost():
                    stats = lose_stats

                lines = stats.split("\n")
                box_width = 3 * CARD_WIDTH + 2 * space_horiz
                for line in lines:
                    message_texts.append(
                        ScreenText(
                            line, line,
                            pygame.Rect(
                                left_margin,
                                top_margin + 50 * (lines.index(line) + 1),
                                box_width, 45), FONT_BIG))

            elif self.paused_time_at != 0:  #game is paused
                message_texts.append(
                    ScreenText(
                        "message_text", "Game Paused",
                        pygame.Rect(
                            left_margin, top_margin,
                            3 * CARD_WIDTH + 2 * space_horiz,
                            4 * CARD_HEIGHT + 3 *
                            ((WINDOW_HEIGHT - 4 * CARD_HEIGHT - 2 * top_margin)
                             / 3)), FONT_BIG))

            self.actors.append(message_box)
            self.actors += message_texts
            self.actors += self.pausebuttons

        # game in play
        else:
            self.time_box.update()
            self.actors = [self.time_box]

            #check which cards are clicked
            self.clicked_cards = []
            for card in self.in_play_cards:
                self.actors.append(card)
                if card.been_clicked:
                    self.clicked_cards.append(card)
                card.update()

            #add click boxes
            for card in self.clicked_cards:
                clicked_box = planes.Plane(
                    "box" + card.name,
                    pygame.Rect(card.rect.x - 5, card.rect.y - 5,
                                card.rect.width + 10, card.rect.height + 10),
                    False, False)
                clicked_box.image = pygame.image.load("img/clickbox.png")
                self.actors.insert(1, clicked_box)

            #check for sets
            if len(self.clicked_cards) == 3:
                is_set = check_set(self.clicked_cards[0],
                                   self.clicked_cards[1],
                                   self.clicked_cards[2])
                if is_set:
                    self.sets_found += 1
                    self.sets_found_label.update_text("Sets: " +
                                                      str(self.sets_found))

                    # reset the time box
                    self.time_box.rect.y = -WINDOW_HEIGHT

                    #remove cards and add new ones
                    for card in self.clicked_cards:
                        self.out_of_play_cards.append(card)
                        index = self.in_play_cards.index(card)
                        self.in_play_cards.remove(card)
                        if len(self.in_play_cards) < 12:
                            self.add_new_cards(1, index)
                else:
                    self.sets_wrong += 1
                for card in self.clicked_cards:
                    card.been_clicked = False

            self.actors += self.gamelabels + self.gamebuttons
            self.time_label.update_text("Time: " + format_secs(
                (pygame.time.get_ticks() - self.start_time - self.pause_time) /
                1000))
            self.hints_left_label.update_text("Hints Remaining: " +
                                              str(self.hints_left))
            self.left_in_deck_label.update_text("Deck: " + str(
                len(self.deck) -
                (len(self.in_play_cards) + len(self.out_of_play_cards))))