# weighted_scores_vs_centers.py
# Prof. Lee, LJL2, May 23, 2022

"""Compares the weighted version of my_scores to the scores of 
hypothetical students who hit all the A centers, B centers, ... and other grades<a href="https://www.cs.cornell.edu/courses/cs1110/2022sp/resources/weighted_scores_vs_centers.py">weighted_scores_vs_centers.py</a>
named in GRADE_TO_CENTERS_INDEX

This script does NOT take labs into account."""

# STUDENTS: Change the values below to your official scores
my_scores = {"A1": 1110,  
            "A2": 1110, 
            "A3": 1110, 
            "P1": 1110, 
            "A4": 1110, 
            "A5": 1110,
            "A6": 1110,
            "P2": 1110,
            "F":  1110
            }

PTS_POSSIBLE = {"A1": 10, 
                "A2": 75, 
                "A3": 100, 
                "A4": 100, 
                "A5": 100, 
                "A6": 67,
                "P1": 79, 
                "P2": 80,
                 "F":109}


CENTERS = {
    # format: A center, B center, C center, def. below C- line.
    "A1": [10, 8, 6, 3],   
    "A2": [73, 66, 55, 43],
    "A3": [95, 82, 73, 60],
    "A4": [96,82,62,30],
    "A5": [95,86,75,60],
    "A6": [63,54,48,33],
    "P1": [75, 66, 51, 36],
    "P2": [76, 60, 45, 26],
    "F": [102,81,51,33]
}

######### LEAVE EVERYTHING BELOW THIS LINE ALONE #############


# maps grade names to indices in CENTERS.
# Only include names you want to print out.
GRADE_TO_CENTERS_INDEX = {"A": 0, "B": 1, "C": 2, "def. below C-": 3} 

GRADE_DESCRIPTION = {"A": "center of As", 
                     "B": "center of Bs", 
                     "C": "center of Cs", 
                     "C-": "line for definitely below C-"}

# A list of pairs, 
#   * first item is the name of the weighting scheme
#   * the second is a dictionary giving the weighting scheme
# We allow for multiple weight schemes because we have had to have multiple weight
#  schemes in the past.
WEIGHTS = [
    ["2022SP official weighting scheme", 
     {"A1": 4,
     "A2": 6,
     "A3": 7,
     "P1": 15,
     "A4": 8,
     "A5": 7, 
     "A6": 8, 
     "P2": 15, 
     "F": 30}]
]

# Make sure weights sum to 100.
for scheme in range(len(WEIGHTS)):
    scheme_name = WEIGHTS[scheme][0]
    grades2weights = WEIGHTS[scheme][1]
    assert sum(grades2weights.values()) == 100, \
        scheme_name+" weights do not sum to 100"


def get_weighted_score(score_dict):
    """Returns tuple of weighted scores, allowing for multiple weighting schemes.

    Precondition: score_dict is a dictionary of scores, with None
    where score is not known. It's meant to represent an individual student's
    scores.
    """
    accums = [0.0]*len(WEIGHTS) # start w/ 0.0 for all weighting schemes

    for asst in score_dict:
        if type(score_dict[asst]) in [int, float]:
            percent = score_dict[asst]/PTS_POSSIBLE[asst]
            for weight_scheme_i in range(len(WEIGHTS)):
                weight_dict = WEIGHTS[weight_scheme_i][1]
                accums[weight_scheme_i] += percent*weight_dict[asst]
                # print("\tIn loop: accums is: " + str(accums[weight_scheme_i]))
    return tuple(accums)

if __name__ == '__main__':

    # keys will be the grade names, meaning representative students
    hypothetical_students = {}
    # Initialize empty dictionaries for hypothetical students
    for grade_name in GRADE_TO_CENTERS_INDEX:
            hypothetical_students[grade_name] = {}

    # fill in the representative student's dictionaries
    for asst in CENTERS:
        for grade_name in hypothetical_students:
            hypothetical_students[grade_name][asst] = \
                CENTERS[asst][GRADE_TO_CENTERS_INDEX[grade_name]]

    # DEBUG
    # for student in hypothetical_students:
    #     print("Show what the hypothetical students' grades/assignment are")
    #     print(student)
    #     print(hypothetical_students[student])
    # print("\n\n")

    others_wted_scores = []
    for student in hypothetical_students:
        others_wted_scores.append(get_weighted_score(hypothetical_students[student]))
    # if there were two weighting schemes, this might look like
    # [(90, 95), (80, 85), (70, 75)]

    my_wted_score = get_weighted_score(my_scores)

    for weight_scheme_i in range(len(WEIGHTS)):
        print("Reporting for the following weighting scheme: " + \
                WEIGHTS[weight_scheme_i][0])    
        print("Format: ") 
        print(', '.join([name for name in GRADE_DESCRIPTION.values()]))

        print(str(list(map(lambda x: round(x[weight_scheme_i], 3), others_wted_scores)))) #@ 

        print("My weighted score: " + \
            str(round(my_wted_score[weight_scheme_i],3)) + "\n")

