"""This module handles everything for the game but the cleaning of user input.""" __author__ = "" __credits__ = "" __email__ = "" import random import copy import time import clean_input total_time = 1.5 def central_function(): """ Calls the other function. Keeps track of played rounds and who is the active player. Game continues until one player has no cards left. :return: None """ print("Wilkommen bei Quartett! ") print("Sie können gegen 1-7 Spieler spielen.") print("Sie können das Spiel bei jeder Eingabe mit 'q' beenden oder mit 'r' neustarten.\n") switch = True card_stack, players_with_cards, players, complete_card_stack = initialize() active = random.randint(0, len(players) - 1) # contains index of the active player # stores the dropped cards all_quartets = [] drop_cards(players_with_cards, all_quartets) if active == 0: print("Du bist als erstes dran!") else: print(f"{players[active]} ist als erstes dran.") time.sleep(total_time) while switch: round(card_stack, players_with_cards, players, active, complete_card_stack, all_quartets) for i in range(len(players)): # check if any card deck is empty if not bool(players_with_cards[i]['cards_on_hand']): switch = False active += 1 if active >= len(players): active = 0 the_winner_is(players_with_cards, players) def round(card_stack, players_with_cards, players, active, complete_card_stack, all_quartets): """ Structures one round in the game. Active player chooses another player from whom to steal a card. If no card is stolen a card has to be drawn from card_stack. Also handles AI decisions. :param card_stack: list of not distributed cards :param players_with_cards: list of dicts with player name, cards and number of quartets :param players: list of player names :param active: index :param complete_card_stack: list of 32 cards for comparison :param all_quartets: list of dropped cards :return: None """ switch = True while switch: print("") players_without_active = copy.copy(players) players_without_active.pop(active) if players[active] == "player0": # human player pretty_print_deck(players_with_cards, active) # chosen_player has the index of player list if len(players_without_active) > 1: print('Folgende Spieler stehen zur Verfügung:') print(players_without_active) chosen_player = players.index(clean_input.io_str( 'Welchen Spieler möchtest du nach einer Karte fragen? ', players_without_active)) else: chosen_player = 1 player_request = clean_input.io_card_selection('Welche Karte möchtest du haben? ') if player_request in players_with_cards[chosen_player]['cards_on_hand']: steal(active, chosen_player, players_with_cards, player_request) drop_cards(players_with_cards, all_quartets, active) if not players_with_cards[active]['cards_on_hand']: switch = False else: print("Diese Karte hat der Spieler nicht. Der nächste Spieler ist dran...") time.sleep(total_time) # end of round # except if stack is not empty, which is not only the case with two players if card_stack: # last card from the stack gets added to active player's hand draw_card = card_stack.pop() print(f"Du ziehst die Karte {draw_card['number']}{draw_card['letter']}" f" vom Stapel.") players_with_cards[active]['cards_on_hand'].append(draw_card) drop_cards(players_with_cards, all_quartets, active) time.sleep(total_time) switch = False else: # AI players # select random player chosen_player = players.index(random.choice(players_without_active)) # get list of cards that are not on the hand of active AI player cards_to_choose_from = [c for c in complete_card_stack if c not in players_with_cards[active]["cards_on_hand"]] # get list of cards that are not on the hand of active AI player AND not in quartets cards_to_choose_from = [c for c in cards_to_choose_from if c not in all_quartets] # select card player_request = random.choice(cards_to_choose_from) if players[chosen_player] == "player0": print( f"{players[active]} fragt dich nach " f"der Karte {player_request['number']}{player_request['letter']}.") else: print( f"{players[active]} fragt {players[chosen_player]} nach " f"der Karte {player_request['number']}{player_request['letter']}.") time.sleep(total_time) if player_request in players_with_cards[chosen_player]['cards_on_hand']: steal(active, chosen_player, players_with_cards, player_request) drop_cards(players_with_cards, all_quartets, active) if not players_with_cards[active]['cards_on_hand']: switch = False else: if players[chosen_player] == "player0": print(f"Du hast die Karte {player_request['number']}{player_request['letter']}" f" nicht. " f"Der nächste Spieler ist dran...") else: print( f"{players[chosen_player]} hat die Karte " f"{player_request['number']}{player_request['letter']} nicht. " f"Der nächste Spieler ist dran...") time.sleep(total_time) # end of round # except if stack is not empty, which is not only the case with two players if card_stack: # last card from the stack gets added to active player's hand players_with_cards[active]['cards_on_hand'].append(card_stack.pop()) drop_cards(players_with_cards, all_quartets, active) switch = False def pretty_print_deck(players_with_cards, player): """ Prints the cards in a players deck in a readable format. :param players_with_cards: list of dicts with player name, cards and number of quartets :param player: index :return: None """ pretty_deck = [] for card in players_with_cards[player]['cards_on_hand']: pretty_deck.append(card['number'] + card['letter']) if player == 0: print("Dein Deck: ", pretty_deck) time.sleep(total_time) def steal(active, chosen_player, players_with_cards, player_request): """ Transfers cards between player decks. :param active: index :param chosen_player: index of player to be asked :param players_with_cards: list of dicts with player name, cards and number of quartets :param player_request: wanted card :return: None """ if active == 0: print(f"player{chosen_player} hat die Karte, die du " "haben möchtest und sie wandert in dein Deck.") else: if chosen_player == 0: print(f"Du hast die Karte, die player{active} " "haben möchte und sie wandert in sein Deck.") else: print(f"player{chosen_player} hat die Karte, die player{active} " "haben möchte und sie wandert in sein Deck.") time.sleep(total_time) card_index = players_with_cards[chosen_player]['cards_on_hand'].index(player_request) players_with_cards[active]['cards_on_hand'].append( players_with_cards[chosen_player]['cards_on_hand'].pop(card_index)) def drop_cards(players_with_cards, all_quartets, active=None): """ Checks whether human or AI player is supposed to drop cards. :param players_with_cards: list of dicts with player name, cards and number of quartets :param all_quartets: list of cards :param active: index :return: None """ # default, check all players if active is None: for p in players_with_cards: drop_cards_help(p, all_quartets) else: p = players_with_cards[active] drop_cards_help(p, all_quartets) def drop_cards_help(p, all_quartets): """ Counts the how often a letter is in the players hand. If there is quartet it will be dropped. The cards a then added to all_quartets. :param p: dict with player name, cards and number of quartets :param all_quartets: list of cards :return: None """ reference = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] counter = [0, 0, 0, 0, 0, 0, 0, 0] for card in p["cards_on_hand"]: counter[reference.index(card["letter"])] += 1 for i in counter: if i == 4: quartet_letter = reference[counter.index(i)] counter[counter.index(i)] = 0 p["quartet"] += 1 if p["player"] == "player0": print(f"Du legst das {quartet_letter}-Quartett ab...") else: print(f"{p['player']} legt das {quartet_letter}-Quartett ab...") # build list of cards that are now dropped q = [c for c in p["cards_on_hand"] if quartet_letter == c["letter"]] # add quartet cards to list for c in q: all_quartets.append(c) p["cards_on_hand"] = [c for c in p["cards_on_hand"] if quartet_letter != c["letter"]] def initialize(): """ Constructs two card stacks. Distributes one of them between the players. Player number is set here, player names are also constructed here. :return: list, list (of dicts), list, list (of dicts) """ card_stack = [] players = [] players_with_cards = [] # define card stack x = 0 for i in range(4): for l in "abcdefgh": d = {"id": str(x), "number": str(i), "letter": l} card_stack.append(d) x += 1 complete_card_stack = copy.copy(card_stack) # determine number of players number_of_players = clean_input.io_int( "Gegen wie viele Spieler wollen Sie spielen (als Ganzzahl)?") while number_of_players < 1 or number_of_players > 7: print("Fehler! Sie dürfen lediglich gegen 1-7 Spieler spielen.") number_of_players = clean_input.io_int( "Gegen wie viele Spieler wollen Sie spielen (als Ganzzahl)?") number_of_players += 1 # Add also human player. for i in range(number_of_players): players.append(f"player{i}") # determine number of cards per player if len(players) == 2: cards_per_player = 10 else: cards_per_player = int(len(card_stack) // len(players)) # distribute hand cards to players for i in range(number_of_players): cards_of_player = [] for j in range(cards_per_player): x = random.randint(0, len(card_stack) - 1) selected_card = card_stack[x] del card_stack[x] cards_of_player.append(selected_card) # create a list that contains every player, their deck and number of made quartets players_with_cards.append( {"player": players[i], "cards_on_hand": cards_of_player, "quartet": 0}) return card_stack, players_with_cards, players, complete_card_stack def the_winner_is(players_with_cards, players): """ Counts the number of quartets a player has made, and chooses the winner, who got the most. :param players_with_cards: Main list of dicts with players and their 'hand' :param players: list of names :return: None """ temp = 1 winners = [] # all potential winners are saved in the winners-list # (in case there is more than one) for i in range(len(players)): winners.append(0) dropped_quartets = players_with_cards[i]['quartet'] if temp < dropped_quartets: temp = dropped_quartets winners.insert(i, dropped_quartets) if temp == dropped_quartets: winners[i] = dropped_quartets # winners then functions as a template # to print all the players' names who have won print("") for i in range(len(winners)): if winners[i] == temp: if players[i] == "player0": print("Du hast das Spiel gewonnen!") else: print(f"{players[i]} hat das Spiel gewonnen!") end_screen() def end_screen(): """ Shows the end screen. :return: None """ clean_input.io_str("Möchten Sie das Spiel beenden oder ein neues Spiel starten? " "Drücken Sie 'q' zum Beenden oder 'r', " "um ein neues Spiel zu starten...", []) # Call central_function() only if quartett.py is the main module if __name__ == "__main__": # remove end_screen() from the_winner_is() if you want to run tests # import doctest # doctest.testfile("tests.txt") central_function()