############################################################
# environment diagram example
############################################################

# EXERCISE

# Given a list of test scores, return a letter grade
# based on all of the scores except for the lowest score.

# Let's split this into 3 separate actions that can be
# represented as helper functions.


def drop_lowest(scores):
    lowest = min(scores)
    scores.remove(lowest)


def average(scores):
    total = sum(scores)
    count = len(scores)
    return total / count


def letter_grade(avg):
    if avg >= 90:
        return 'A'
    elif avg >= 80:
        return 'B'
    elif avg >= 70:
        return 'C'
    else:
        return 'F'


# We can use these helper to construct our final function.


def grade_student(scores):
    drop_lowest(scores)
    avg = average(scores)
    grade = letter_grade(avg)
    return grade


# scores = [83, 90, 92, 78]
# grade = grade_student(scores)
# print("The student's final grade is:", grade)


# Construct an environment diagram to the point where
# line 21 has finished executing (work with a partner).

# Go through the full environment diagram step-
# by-step using https://pythontutor.com/.


############################################################
# debugging and complex environment diagram example
############################################################


# EXERCISE

# Read through the following code and its comments,
# and predict what the desired output is.

# There is a bug in the code. Run the code, and notice
# how the output differs from your expectation. Identify
# the buggy function, and isolate the issue.


# adds a student's new score to their existing scores
def add_score(new_score, scores):
    scores.append(new_score)

# adds a number of points to one of the scores
def add_extra_credit(points, idx, scores):
    scores[idx] += points

# drops the student's lowest score
def drop_lowest(scores):
    print(scores)
    scores.remove(min(scores))

# assigns a name to the student's list of scores
def assign_scores(name, scores):
    assigned_scores = scores.copy()
    assigned_scores.insert(0, name)
    return assigned_scores

# sorts the student's scores in ascending order
def sort_scores(scores):
    sorted_scores = []
    scores[1:].sort()
    sorted_scores.append([scores[0]] + scores[1:])
    return sorted_scores


########################################


# applies modifications to student's scores
def finalize_student(student, scores, new_score=None, extra_credit=None):
    if new_score:
        add_score(new_score, scores)
    if extra_credit:
        add_extra_credit(extra_credit[0], extra_credit[1], scores)
    drop_lowest(scores)
    assigned_scores = assign_scores(student, scores)
    final_scores = sort_scores(assigned_scores)
    return final_scores


# runs finalize_student on each student with desired params
def finalize_scores(students, all_scores):
    finalized_scores = []
    finalized_scores.append(finalize_student(students[0], all_scores[0], new_score=90))
    finalized_scores.append(finalize_student(students[1], all_scores[1], new_score=85, extra_credit=[1,2]))
    finalized_scores.append(finalize_student(students[2], all_scores[2], new_score=95, extra_credit=[2,0]))
    return finalized_scores


students = ["Anthony", "Brooke", "Chris"]
scores_anthony = [92, 84, 91]
scores_brooke = [80, 75, 88]
scores_chris = [96, 73, 79]


# all_scores = [scores_anthony, scores_brooke, scores_chris]
# print("Initial scores: ", all_scores)

# final_scores = finalize_scores(students, all_scores)
# print("Final scores: ", final_scores)


# After debugging, go through the full environment
# diagram step-by-step using https://pythontutor.com/.


############################################################
# hangman version a (bulky main loop)
############################################################


import random
import string


# pick a random word from word list
def choose_word(wordlist):
    return random.choice(wordlist)


# game function
def hangman(secret_word):
    print('Welcome to Hangman!')
    print(f'I am thinking of a word that is {len(secret_word)} letters long.')

    guesses_remaining = 5
    letters_guessed = []
    divider = '--------------'

    # main game loop
    while guesses_remaining > 0:
        print(divider)
        print(f'You currently have {guesses_remaining} guesses left')

        available_letters = ''
        for c in string.ascii_lowercase:
            if c not in letters_guessed:
                available_letters += c
        print('Available letters:', available_letters)

        # display word progress
        progress = ''
        for c in secret_word:
            if c in letters_guessed:
                progress += c
            else:
                progress += '*'
        print('Current word:', progress)

        # check for win
        if '*' not in progress:
            break

        # get user input
        guess = input('Please guess a letter: ').lower()

        # validate input
        if not guess.isalpha() or len(guess) != 1:
            print('Oops! That is not a valid letter.')
            continue

        # record guess
        letters_guessed.append(guess)

        # handle guess result
        if guess in secret_word:
            print('Good guess!')
        else:
            guesses_remaining -= 1
            print('Oops! That letter is not in my word.')

    # end of game
    print(divider)
    if guesses_remaining > 0:
        print('Congratulations, you won!')
    else:
        print(f'Sorry, you ran out of guesses. The word was {secret_word}.')


wordlist = ['storage', 'fashion', 'nuclear', 'lineage', 'gradual', 'tribute', 'liberty', 'mention', 'charity', 'shatter',
            'improve', 'convert', 'comment', 'reptile', 'recover','mixture', 'relieve', 'custody', 'testify', 'factory']
# secret_word = choose_word(wordlist)
# hangman(secret_word)


############################################################
# hangman version b (helper functions)
############################################################


import random
import string


# pick a random word from the word list
def choose_word(wordlist):
    return random.choice(wordlist)


########################################


# check if all characters have been guessed
def has_player_won(secret_word, letters_guessed):
    for c in secret_word:
        if c not in letters_guessed:
            return False
    return True


# letter in word appears if guessed, otherwise *
def get_word_progress(secret_word, letters_guessed):
    progress = ''
    for c in secret_word:
        if c in letters_guessed:
            progress += c
        else:
            progress += '*'
    return progress


# returns letters that haven't been guessed yet
def get_available_letters(letters_guessed):
    available = ''
    for c in string.ascii_lowercase:
        if c not in letters_guessed:
            available += c
    return available


# displays number of guesses left, available letters, current word state
def display_status(divider, guesses_remaining, letters_guessed, secret_word):
    print(divider)
    print(f'You currently have {guesses_remaining} guesses left')
    print('Available letters:', get_available_letters(letters_guessed))
    print('Current word:', get_word_progress(secret_word, letters_guessed))


########################################


# checks if input is a valid letter
def is_valid_guess(guess, letters_guessed):
    if not guess.isalpha() or len(guess) != 1:
        return False, 'Oops! That is not a valid letter.'
    return True, ''


# checks if input is a correct guess
def check_guess(guess, secret_word, guesses_remaining):
    if guess in secret_word:
        return guesses_remaining, 'Good guess!'
    else:
        return guesses_remaining - 1, 'Oops! That letter is not in my word.'


########################################


# game function
def hangman(secret_word):
    print('Welcome to Hangman!')
    print(f'I am thinking of a word that is {len(secret_word)} letters long.')

    guesses_remaining = 5
    letters_guessed = []
    divider = '--------------'

    while guesses_remaining > 0 and not has_player_won(secret_word, letters_guessed):
        display_status(divider, guesses_remaining, letters_guessed, secret_word)

        guess = input('Please guess a letter: ').lower()

        valid, message = is_valid_guess(guess, letters_guessed)
        if not valid:
            print(message)
            continue

        letters_guessed.append(guess)
        guesses_remaining, message = check_guess(guess, secret_word, guesses_remaining)
        print(message)

    print(divider)

    if has_player_won(secret_word, letters_guessed):
        print('Congratulations, you won!')
    else:
        print(f'Sorry, you ran out of guesses. The word was {secret_word}.')


wordlist = ['storage', 'fashion', 'nuclear', 'lineage', 'gradual', 'tribute', 'liberty', 'mention', 'charity', 'shatter',
            'improve', 'convert', 'comment', 'reptile', 'recover','mixture', 'relieve', 'custody', 'testify', 'factory']
# secret_word = choose_word(wordlist)
# hangman(secret_word)
