class GUIGame(Game): def __init__(self, name, WINDOW_SIZE): pygame.init() pygame.display.set_caption(name) pygame.display.set_mode(WINDOW_SIZE) pygame.display.set_icon(ICON) self.pyclock = pygame.time.Clock() # Saves each turn's time; doesn't reset with each new game. self.turns_times = [] self.display_draws = HELP # Show help on launch. self.cards_drawn = False # Wait until the game is ready # ============================ Game Mechanics ===================== # THE GAME IS LAUNCHED WITH MAIN FROM CONSOLE GAME!! # Starts the new game on table # NOT a recursion: just sets all the data to 0. def start(self, PLAYERS): self.board = Board.initial(GUICard) # Clear the ingame data. self.start_turn_time = time.clock() self.set_time = 0 self.players = {x: [] for x in xrange(PLAYERS)} #self.cards_drawn = False self.table_clickable = False # Is it possible to select cards? self.draw_END_BUTTON = False # Draw 'No Sets' and block the game? self.player_turn = None # Whose turn (== player_id or None) # Adds cards if necessary def check(self): in_set = self.board.has_set() # 1. Add up to 12 cards if len(self.board.table) < TABLE_SIZE: self.board = self.board.add_cards() # 2. Continue adding cards until there's a set elif not in_set and len(self.board.table) < TABLE_LIMIT: self.board = self.board.add_cards() # 3. Reshuffle if no set and window can't handle more cards elif not in_set and len(self.board.table) == TABLE_LIMIT: cards = random.shuffle(self.board.deck + self.board.table) new_deck = cards[TABLE_SIZE:] new_table = cards[:TABLE_SIZE] self.board = Board(new_deck, new_table) # 4. Break if added more than window can handle assert(len(self.board.table) <= TABLE_LIMIT) # Gets the cards selected by user def get_user_turn(self, err=0.05): if self.table_clickable: # 1. 3 cards selected if len(self.board.selected) == QUANTITY: if self.board.is_set(self.board.selected): self.table_clickable = False return SET_FOUND # 1.2 It is not set; clear the selection self.board.selected = [] # 2. User hasn't selected set in time elif time.clock() > self.set_time + TIME_LIMIT - err: self.table_clickable = False self.board.selected = [] return SET_NOT_FOUND # Shows 'Game over' def ask_exit(self): self.draw_END_BUTTON = True # ============================ Drawings Tree ====================== def display(self): def draw_start_text(x=15, y=15, padding_top=36): screen.blit(HEADER, (x, y)) y += padding_top for line in LINES['start']: screen.blit(line, (x, y)) y += SIZE16 def draw_buttons(): HELP_BUTTON.draw(screen) START_BUTTON.draw(screen) if self.draw_END_BUTTON: END_BUTTON.draw(screen) def draw_PLAYERS(): for i in xrange(len(SET_BUTTONS)): text = LINES['player'].format(i+1, len(self.players[i])) screen.blit(common_font(text), SET_BUTTONS[i].text) if not self.draw_END_BUTTON: SET_BUTTONS[i].draw(screen) # As it mentioned in pygame documentation, it helps the CPU tickFPS = CLOCK.tick(FPS) screen = pygame.display.get_surface() screen.fill(PALETTE['Background']) draw_buttons() if self.display_draws == HELP: draw_start_text() self.draw_cards(screen, False) else: draw_PLAYERS() # If there are cards to display, they will be displayed if self.board.table: self.draw_cards(screen) if self.cards_drawn: self.draw_turn_timer(screen) self.draw_stats(screen) self.set_countdown(screen) pygame.display.update() # ========================= Draw Cards Function =================== # Ss on module level because it is also used in drawing # SET_EXAMPLE in help menu (draw_table=False). # # With draw_table=True draws SELECTIONs, creates a card click-area # and allowes the game to launch safely (self.cards_drawn = True). def draw_cards(self, screen, draw_table=True): if draw_table: x, y = CARD_START_X, CARD_START_Y rows = CARD_ROWS cards = self.board.table else: x, y = EXAMPLE_X, EXAMPLE_Y rows = EXAMPLE_ROWS cards = SET_EXAMPLE columns = len(cards)/rows card_x, card_y = x, y for row in xrange(0, len(cards), columns): for column in xrange(columns): i = row + column card = cards[i] screen.blit(card.image, (card_x, card_y)) if draw_table: card.rect = pygame.Rect( (card_x, card_y), (CARD_WIDTH, CARD_HEIGHT)) if card in self.board.selected: screen.blit(SELECTION, (card_x-2, card_y-2)) card_x += CARD_WIDTH + CARD_SPACE card_x = x card_y += CARD_HEIGHT + CARD_SPACE if draw_table and not self.cards_drawn: self.cards_drawn = True # =============================== Statuses ============================== # The size of this area is exactly to fit in the refreshing timer. @property def timer_area(self, x=140, y=18): area = pygame.Surface((x, y)) area.fill(PALETTE['Background']) return area def draw_turn_timer(self, screen, x=60, y=0, padding=60): timer_area = self.timer_area # Turn's timer stops when 'Set!' is clicked. if not self.draw_END_BUTTON: if self.set_time: current_time = round_time(self.set_time - self.start_turn_time) else: current_time = round_time(time.clock() - self.start_turn_time) timer_area.blit(LINES['current'], (x-padding, y)) timer_area.blit(time_font(current_time, 'Black'), (x, y)) screen.blit(timer_area, TIMER_AREA_COORD) def draw_stats(self, screen, x=720, y=538): def draw_stat(text, num, x, y, colour='Black', padding=60): screen.blit(text, (x-padding, y)) screen.blit(time_font(num, colour), (x, y)) if self.turns_times: last_time = round_time(self.turns_times[-1]) draw_stat(LINES['last'], last_time, x, y, 'Red') y += SIZE18 best_time = round_time(min(self.turns_times)) draw_stat(LINES['best'], best_time, x, y, 'Green') y += SIZE18 # The only word one symbol longer. total = str(len(self.turns_times)) draw_stat(LINES['total'], total, x, y, 'Emerald', padding=70) def set_countdown(self, screen, space=3): # Display side turn timer when the 'Set!' button is clicked. if self.display_draws == TABLE and self.player_turn is not None: button = SET_BUTTONS[self.player_turn] timer_x = button.coord[0] timer_y = button.coord[1] + button.size[1] + space timer = round_time(TIME_LIMIT - (time.clock() - self.set_time)) screen.blit(time_font(timer, 'Red'), (timer_x, timer_y)) # =========================== Keys Controller =========================== def key_input(self): def click_buttons(): # New Game is clicked. if START_BUTTON.rect.collidepoint(event.pos): self.start(PLAYERS) self.display_draws = TABLE # Help button is clicked. if HELP_BUTTON.rect.collidepoint(event.pos): # Very first reading of rules doesn't count as turn's time. if not self.cards_drawn: self.turns_times = [] self.start_turn_time = time.clock() self.set_time = 0 if self.display_draws == HELP: self.display_draws = TABLE else: self.display_draws = HELP # 'Set!' button is clickable, when we have cards and game to play. if all([not self.table_clickable, self.cards_drawn, not self.draw_END_BUTTON]): for i in xrange(len(SET_BUTTONS)): if SET_BUTTONS[i].rect.collidepoint(event.pos): self.table_clickable = True self.player_turn = i self.set_time = time.clock() def click_cards(): for card in self.board.table: if card.rect.collidepoint(event.pos): if card not in self.board.selected: self.board.selected.append(card) else: self.board.selected.remove(card) # Main pygame loop for event in pygame.event.get(): if event.type == QUIT: sys.exit() if event.type == MOUSEBUTTONDOWN and event.button == 1: click_buttons() if self.table_clickable: click_cards() if event.type == KEYDOWN and event.key == K_s: # cheat print [card.attr for card in self.board.has_set()]