Example #1
0
def play(need_load_game=False, data=None):
    """ This is the main play function, the game essentially takes place here """
    # Initial game object initialisations
    if need_load_game:
        p1_c1 = data["p1_c1"]
        p1_c2 = data["p1_c2"]
        p2_c1 = data["p2_c1"]
        p2_c2 = data["p2_c2"]
        die = data["die"]

        # Update the rects for the counters and die
        p1_c1.from_load()
        p1_c2.from_load()
        p2_c1.from_load()
        p2_c2.from_load()
        die.from_load()

        # Game play variables
        names = data["names"]

        p1_c1_move = data["p1_c1_move"]
        p1_c2_move = data["p1_c2_move"]
        p2_c1_move = data["p2_c1_move"]
        p2_c2_move = data["p2_c2_move"]

        die_result = data["die_result"]
        die_rolled = data["die_rolled"]

        move_by = data["move_by"]

        turn = data["turn"]  # 1 or 2

        scores = data["scores"]
    else:
        p1_c1 = Entities.Counter(1, 1)
        p1_c2 = Entities.Counter(1, 2)
        p2_c1 = Entities.Counter(2, 1)
        p2_c2 = Entities.Counter(2, 2)
        die = Entities.Die()

        # Game play variables
        names = display_enter_player_names()

        p1_c1_move = True, None
        p1_c2_move = True, None
        p2_c1_move = True, None
        p2_c2_move = True, None

        die_result = 0
        die_rolled = False

        move_by = 0

        turn = 1  # 1 or 2

        scores = [0, 0]  # Player 1 score, Player 2 score

    # Set up text and button objects
    current_player = Entities.Text(small_font, "Current Player", Colours.WHITE,
                                   430, 135)
    txt_player_one = Entities.Text(small_font, names[0], Colours.WHITE, 430,
                                   150)
    txt_player_two = Entities.Text(small_font, names[1], Colours.WHITE, 430,
                                   150)
    txt_hint = Entities.Text(small_font, "Test", Colours.WHITE, width / 2, 380)

    btn_load = Entities.Button(small_font, "Load", Colours.WHITE, 430, 214)
    btn_save = Entities.Button(small_font, "Save", Colours.WHITE, 430, 246)
    btn_rules = Entities.Button(small_font, "Rules", Colours.WHITE, 430, 278)
    btn_return = Entities.Button(small_font, "Return to\nMenu", Colours.WHITE,
                                 430, 305)

    # Draw to the screen
    def render_board():
        renderer.update_display(display)

        renderer.add(p1_c1)
        renderer.add(p1_c2)
        renderer.add(p2_c1)
        renderer.add(p2_c2)
        renderer.add(die)
        renderer.add(current_player)
        renderer.add(txt_player_one if turn == 1 else txt_player_two)
        renderer.add(btn_load)
        renderer.add(btn_save)
        renderer.add(btn_rules)
        renderer.add(btn_return)
        renderer.add(txt_hint)

        renderer.draw("bg_play", Colours.BLACK)

    def end_turn():
        """ Handle end of turn information such as switching of turns, die image reset etc. """
        new_turn = 1 if turn == 2 else 2
        die.update_image(0)

        check_winner()

        return new_turn, False, 0, 1

    def check_winner():
        """ Check if a player has both of their counters on row 11 (FINISH) """
        if p1_c1.get_row() == 11 and p1_c2.get_row() == 11:
            display_winner(names[0], scores[0])

        if p2_c1.get_row() == 11 and p2_c2.get_row() == 11:
            display_winner(names[1], scores[1])

    def calculate_move_by(result):
        """ Calculate the move_by variable based on the die result, essentially convert the die result
        into the movement distance as specified by the rules """
        movement = 0

        if result in [1, 2, 3]:
            return result
        elif result == 4:
            movement = -1
        elif result == 5:
            movement = "available"

        return movement

    def get_move_text(movement):
        """ Return the text to display to the user based on their movement result """
        if movement == 1:
            return "select counter to move 1 space closer to FINISH!"
        elif movement in [2, 3]:
            return "select counter to move " + str(
                movement) + " spaces closer to FINISH!"
        elif movement == -1:
            return "select counter to move 1 space closer to START!"
        elif movement == "available":
            return "select counter to move to next EMPTY row!"

    # Main game loop
    while True:
        # Handle events (beginning of game logic - i.e clicks on the window)
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                quit_game()

            die_event = die.event(e, die_rolled)

            # Check if the die was clicked
            if die_event[0]:
                if not die_rolled:
                    die_result = die_event[1]
                    die_rolled = True
                    move_by = calculate_move_by(die_result)
                    if turn == 1:
                        p1_c1_move = p1_c1.can_move(move_by, p1_c2.get_row(),
                                                    p2_c1.get_row(),
                                                    p2_c2.get_row())
                        p1_c2_move = p1_c2.can_move(move_by, p1_c1.get_row(),
                                                    p2_c1.get_row(),
                                                    p2_c2.get_row())
                    elif turn == 2:
                        p2_c1_move = p2_c1.can_move(move_by, p2_c2.get_row(),
                                                    p1_c1.get_row(),
                                                    p1_c2.get_row())
                        p2_c2_move = p2_c2.can_move(move_by, p2_c1.get_row(),
                                                    p1_c1.get_row(),
                                                    p1_c2.get_row())
                else:
                    txt_hint.update_text("You can only roll once!", 2)

            # Game logic for each player turn
            if turn == 1:
                if p2_c1.event(e) or p2_c2.event(e):
                    txt_hint.update_text("This isn't your counter!", 2)
                elif die_rolled:
                    if not p1_c1_move[0] and p1_c1.event(e):
                        txt_hint.update_text("This counter cannot be moved!",
                                             2)
                    elif p1_c1_move[0] and p1_c1.event(e):
                        p1_c1.move(p1_c1_move[1])
                        scores[0] += p2_c1.counter_moved(p1_c1.get_row())
                        scores[0] += p2_c2.counter_moved(p1_c1.get_row())
                        turn, die_rolled, die_result, txt_hint.get_text_manager(
                        ).priority = end_turn()
                    elif not p1_c2_move[0] and p1_c2.event(e):
                        txt_hint.update_text("This counter cannot be moved!",
                                             2)
                    elif p1_c2_move[0] and p1_c2.event(e):
                        p1_c2.move(p1_c2_move[1])
                        scores[0] += p2_c1.counter_moved(p1_c2.get_row())
                        scores[0] += p2_c2.counter_moved(p1_c2.get_row())
                        turn, die_rolled, die_result, txt_hint.get_text_manager(
                        ).priority = end_turn()
                    elif not p1_c1_move[0] and not p1_c2_move[0]:
                        txt_hint.update_text(
                            "No counter can move, ending turn...", 3)
                        render_board()
                        time.sleep(5)
                        turn, die_rolled, die_result, txt_hint.get_text_manager(
                        ).priority = end_turn()
                elif p1_c1.event(e) or p1_c2.event(e):
                    txt_hint.update_text(
                        names[turn - 1] + ", you need to roll the die first!",
                        2)
            elif turn == 2:
                if p1_c1.event(e) or p1_c2.event(e):
                    txt_hint.update_text("This isn't your counter!", 2)
                elif die_rolled:
                    if not p2_c1_move[0] and p2_c1.event(e):
                        txt_hint.update_text("This counter cannot be moved!",
                                             2)
                    elif p2_c1_move[0] and p2_c1.event(e):
                        p2_c1.move(p2_c1_move[1])
                        scores[1] += p1_c1.counter_moved(p2_c1.get_row())
                        scores[1] += p1_c2.counter_moved(p2_c1.get_row())
                        turn, die_rolled, die_result, txt_hint.get_text_manager(
                        ).priority = end_turn()
                    if not p2_c2_move[0] and p2_c2.event(e):
                        txt_hint.update_text("This counter cannot be moved!",
                                             2)
                    elif p2_c2_move[0] and p2_c2.event(e):
                        p2_c2.move(p2_c2_move[1])
                        scores[1] += p1_c1.counter_moved(p2_c2.get_row())
                        scores[1] += p1_c2.counter_moved(p2_c2.get_row())
                        turn, die_rolled, die_result, txt_hint.get_text_manager(
                        ).priority = end_turn()
                    elif not p2_c1_move[0] and not p2_c2_move[0]:
                        txt_hint.update_text(
                            "No counter can move, ending turn...", 2)
                        render_board()
                        time.sleep(5)
                        turn, die_rolled, die_result, txt_hint.get_text_manager(
                        ).priority = end_turn()
                elif p2_c1.event(e) or p2_c2.event(e):
                    txt_hint.update_text(
                        names[turn - 1] + ", you need to roll the die first!",
                        2)

            # Current data - used if user clicks save from side menu
            current_data = {
                "p1_c1": p1_c1,
                "p1_c2": p1_c2,
                "p2_c1": p2_c1,
                "p2_c2": p2_c2,
                "die": die,
                "names": names,
                "p1_c1_move": p1_c1_move,
                "p1_c2_move": p1_c2_move,
                "p2_c1_move": p2_c1_move,
                "p2_c2_move": p2_c2_move,
                "die_result": die_result,
                "die_rolled": die_rolled,
                "move_by": move_by,
                "turn": turn,
                "scores": scores
            }

            display_saved_games("play") if btn_load.event(e) else False
            display_save_screen(current_data) if btn_save.event(e) else False
            display_rules("play") if btn_rules.event(e) else False
            display_main_menu() if btn_return.event(e) else False

        # Remaining game logic
        if not die_rolled:
            txt_hint.update_text(names[turn - 1] + ", click the die to roll!")
        elif die_result != 0:
            txt_hint.update_text(names[turn - 1] + " rolled a " +
                                 str(die_result) + ", " +
                                 get_move_text(move_by))

        # Render the game board to the screen
        render_board()

        # Pause loop for a time so that we can get the TARGET_FPS
        clock.tick(TARGET_FPS)