# This is a Mastermind computer game. This program works by asking the user
# to input four colors by their single letter short-form, while checking for
# errors everytime they input. The user can reset all inputs by typing 'rs'
# as well. Then, the program puts all user inputs into a list in order
# and compares it with a list comprising of random colors in random orders
# generated by the program. If the user guesses correctly for both color and
# position, the program counts it as 'correct color(s) in correct position(s)'.
# If the user guesses correctly the color but not the position, the program
# counts it as 'correct color(s) in wrong position(s)'. The user gets 10 chances,
# and the user wins if all 4 guesses for both colors and positions are correct. 

# Imports random library
import random

# List of all the color choices for randomisation by program
allColorList = ['red', 'yellow', 'green', 'blue', 'white']

# FOR TESTING, remove ## to manually set color and order
##randomColorList = ['red', 'blue', 'red', 'green']

# Generates a list of colors randomly in random order 
# FOR TESTING, add ## to not randomise color and order
randomColorList = random.choices(allColorList, k = 4)

# FOR TESTING, remove ## to show answers
##print(randomColorList)

# Function to convert all single letter short-forms to full names by comparisons
# and returns full names to program. 
def translate(guess):
    # Inputs are converted to lower case for easy comparisons.
    if guess.lower() == 'r':
        guess = 'red'
    elif guess.lower() == 'y':
        guess = 'yellow'
    elif guess.lower() == 'g':
        guess = 'green'
    elif guess.lower() == 'b':
        guess = 'blue'
    elif guess.lower() == 'w':
        guess = 'white'
    return guess

# Function to get short-form input from user and checks if inputs are valid. Inputs
# are converted to lower case for easy checking. Input is valid if input is in the
# choicesList or 'rs' for resetting. Inputs are then converted to full name 
# and returned to program.
def determine(index):
    # List of short-forms for all the color choices
    choicesList = ['r', 'y', 'g', 'b', 'w']
    
    while True:
        # number[index] is used to print the position from list
        print('For the', number[index], end = ' ')
        # Gets input for guesses from user
        guess = str(input('position, enter your guess: '))
        
        if guess.lower() in choicesList:
            # Converts short-form input and returns full name if input is in choicesList
            guess = translate(guess)
            return guess
            break
        
        if guess.lower() == 'rs':
            # Returns 'rs' to program to trigger reset
            return guess.lower()
        
        else:
            # Input is not in choicesList or 'rs', program asks user to input again
            print('Invalid selection, please choose again!')

# Initializes number of tries
tries = 1

# Initializes the loop condition
loop = 'y'

# List of positional words
number = ['first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth',
          'ninth', 'tenth']

# Shows the instructions and rules of the game
print('Welcome to Mastermind!')
print('Your objective is to guess the four colours in the correct order.')
print('You have 10 chances to complete the objective. Good luck!')
print()

# Loop for the game
while loop == 'y':
    print('-----------------------------------------------------------------------')
    print('Choose four colors from the following five colors in the correct order:')
    print()
    print('        ', 'red(r), yellow(y), green(g), blue(b), white(w)')
    print()
    print('Answer using "r", "y", "g", "b" or "w", then press ENTER.')
    print('Type "rs" if you want to reset all of your choices.')
    print()
    # number[index] is used to print the position from list
    print('This is your', number[tries-1], 'attempt.')
    
    # Initializes the list of user inputs as an empty list
    guessedColorList = []
    # Initializes the loop condition
    guess1 = 'rs'
    guess2 = 'rs'
    guess3 = 'rs'
    guess4 = 'rs'

    # Loop where if user types 'rs', all user inputs will be reset and loop will restart
    while guess1 == 'rs' or guess2 == 'rs' or guess3 == 'rs' or guess4 == 'rs':
        # Initializes counter 'index' for printing positional words
        index = 0
        print()
        guess1 = determine(index)
        
        # If first input is not 'rs', then continue to ask for second input
        if guess1 != 'rs':
            index += 1
            guess2 = determine(index)
            
            # If second input is not 'rs', then continue to ask for third input
            if guess2 != 'rs':
                index += 1
                guess3 = determine(index)
                
                # If third input is not 'rs', then continue to ask for fourth input
                if guess3 != 'rs':
                    index += 1
                    guess4 = determine(index)
                        
    print()
    # Puts all user inputs into a list
    guessedColorList = [str(guess1), str(guess2), str(guess3), str(guess4)]
    
    # Shows user's inputs
    print('Your guesses are', guessedColorList)
    print()
    
    # Initializes the number of colors in correct places and wrong places
    correctPlace = 0
    wrongPlace = 0

    # Initializes the list of indexes as [0, 1, 2, 3] as there are 4 randomly-generated
    # colors and 4 guesses by user
    randomColorIndexes = [0, 1, 2, 3]
    guessedColorIndexes = [0, 1, 2, 3]

    # Checks for correct color in correct positions by comparisons between the same index
    # from the user input list and randomly-generated list
    for i in range(4):
        if guessedColorList[i] == randomColorList[i]:
            # If there is a correct color is in the correct position, the counter for correct
            # positions will increase, and its index will be removed from both index lists
            correctPlace += 1
            randomColorIndexes.remove(i)
            guessedColorIndexes.remove(i)

    # Initializes the list of correct color in wrong positions from randomly-generated list
    # and user input list as empty lists
    newRandomColorList = []
    newGuessedColorList = []

    # Adds the correct color in wrong positions from randomly-generated list into list
    for i in randomColorIndexes:
        newRandomColorList.append(randomColorList[i])

    # Adds the correct color in wrong positions from user input list into list
    for i in guessedColorIndexes:
        newGuessedColorList.append(guessedColorList[i])

    # Checks for any correct color in wrong positions by checking whether the color in user
    # input list is in the program randomization list
    for i in range(len(randomColorIndexes)):
        if newGuessedColorList[i] in newRandomColorList:
            # Assign the correct color in wrong position into a variable
            element = newGuessedColorList[i]
            # Counter of wrong positions increases
            wrongPlace += 1
            # Remove the correct color in wrong position from program randomization list
            newRandomColorList.remove(element)


    # Shows results
    print('Correct color(s) in correct position(s):', correctPlace)
    print('Correct color(s) in wrong position(s):', wrongPlace)
    print()

    # If user correctly guesses all answers, loop terminates and program shows how many
    # attempts are made
    if correctPlace == 4:
        print('Congratulations! You have won after', tries, 'attempt(s).')
        break

    # If user has wrong answers and has not made more than 10 attempts, program asks user
    # whether user wants to retry again
    if tries < 10:
        # Program shows user the number of attempts made.
        print('You have attempted', tries, 'time(s).')
        while True:
            # Program shows user the number of attempts left.
            print('You have', 10 - tries , 'chance(s) left.')
            print()
            reply = input('Do you want to try again? [y/n]: ')

            # If user does not want to retry, program terminates and shows goodbye message
            if reply.lower() == 'n':
                loop = 'n'
                print('Thank you, goodbye.')
                break
            # If user wants to retry, program loops again and counter for tries increase
            elif reply.lower() == 'y':
                loop = 'y'
                tries += 1
                break
            # If user input is not valid, program asks again if user wants to retry
            else:           
                print('Invalid selection!')

    # If user does not correctly guesses all answers within 10 attempts, user loses and
    # the program prints the answers
    else:
        print('Game over! You have used up all 10 chances!')
        print('The correct answers are', randomColorList)
        print('Better luck next time!')
        break
    print()
