Python by Projects

unit

High-Score Hall of Fame

Every arcade game needs a leaderboard. A messy scrap of paper can hold a few scores, but our program needs to remember every score, grow when a new player finishes, and crown a champion. We build that hall with a Python list.

Each idea comes as a short ladder — simplest first, then one step up, then the real board — with a Notice naming the one new thing.

You will learn

  • Build a list with [...] and read its items by position.
  • Grow a list with .append() and visit every item with a for loop.
  • Measure a list with len, max and min, and work out an average.
  • Rank a list with .sort() and print a numbered hall of fame.

Lesson 1: Build the Score Board

A list lets one variable hold many items in order. Square brackets mark its start and end; commas separate the items.

scores = []
print(scores)

Output

[]

Notice

[] is an empty list — a board with no scores yet.

scores = [1200, 850]
print(scores)

Output

[1200, 850]

Notice

Put items inside the brackets, separated by commas.

scores = [1200, 850, 990, 1500]
print(f"Arcade scores: {scores}")

Output

Arcade scores: [1200, 850, 990, 1500]

Notice

A list can hold as many items as you like — here, the four arcade scores.

List positions start at 0. Square brackets with a position select one item.

scores = [1200, 850, 990, 1500]
print(scores[0])

Output

1200

Notice

scores[0] is the FIRST item (position 0).

print(scores[2])

Output

990

Notice

Each position picks the item sitting there — scores[2] is the third.

print(scores[-1])

Output

1500

Notice

-1 counts back from the end — the LAST score.

The list method .append() adds a new item to the END of the same list.

scores = [1200, 850]
scores.append(990)
print(scores)

Output

[1200, 850, 990]

Notice

.append(990) adds 990 to the end of scores.

best = 1500
scores.append(best)
print(scores)

Output

[1200, 850, 990, 1500]

Notice

You can append a value held in a variable too, not only a literal.

board = []
new_scores = [1200, 850, 990]
for one_score in new_scores:
    board.append(one_score)
print(board)

Output

[1200, 850, 990]

Notice

A for loop can append many items in a row to build a list.

A for loop can also VISIT each item in a list, one at a time.

scores = [1200, 850, 990, 1500]
for one_score in scores:
    print(f"Score: {one_score}")

Output

Score: 1200
Score: 850
Score: 990
Score: 1500

Notice

The loop runs once per item, with one_score holding each value in turn.

scores = [1200, 850, 990, 1500]
total = 0
for one_score in scores:
    total = total + one_score
print(f"Total points: {total}")

Output

Total points: 4540

Notice

Add each item into an accumulator to build a running total over the whole list.

scores = [1200, 850, 990, 1500]
for i in range(len(scores)):
    print(scores[i])

Output

1200
850
990
1500

Notice

You can also loop by POSITION with range(len(scores)), reading each item as scores[i].

scores = [1200, 850, 990, 1500]
for i in range(len(scores)):
    print(f"Entry #{i + 1}: {scores[i]}")

Output

Entry #1: 1200
Entry #2: 850
Entry #3: 990
Entry #4: 1500

Notice

One step more — add 1 to the position for a friendly entry number beside each score.

Built-in functions measure a list. len counts items, max finds the biggest, min the smallest.

scores = [1200, 850, 990, 1500]
print(len(scores))

Output

4

Notice

len(scores) is how many items the list holds.

print(max(scores))

Output

1500

Notice

max(scores) finds the champion — the biggest score.

print(min(scores))

Output

850

Notice

min(scores) finds the smallest score.

Dividing the total by the count gives the average. Python writes that as a decimal, called a float.

scores = [1200, 850, 990, 1500]
total = 0
for one_score in scores:
    total = total + one_score
average = total / len(scores)
print(f"Average score: {average}")

Output

Average score: 1135.0

Notice

/ gives a float (a decimal) — the average of the four scores.

Try it yourself

n = int(input("How many scores? "))
scores = []
for i in range(n):
    score = int(input(f"Score {i + 1}: "))
    scores.append(score)

total = 0
for one_score in scores:
    total = total + one_score
average = total / len(scores)
print(f"Average score: {average}")

Notice

The real version reads however many scores the player types into a list, then uses the same running-total and average logic. (Reads live input, so it does not run here.)

Lesson 2: Rank the Hall and Crown the Champion

The list method .sort() rearranges the SAME list in place (it changes the list, and returns None, so call it on its own line).

scores = [1200, 850, 990, 1500]
scores.sort()
print(f"Low to high: {scores}")

Output

Low to high: [850, 990, 1200, 1500]

Notice

.sort() puts the items in order, lowest first.

scores.sort(reverse=True)
print(f"Top score first: {scores}")

Output

Top score first: [1500, 1200, 990, 850]

Notice

.sort(reverse=True) orders them highest first — the leaderboard order.

scores = [1200, 850, 990, 1500]
scores.sort(reverse=True)
print(f"Champion: {scores[0]}")
print(f"Runner-up: {scores[1]}")

Output

Champion: 1500
Runner-up: 1200

Notice

Once the list is sorted top-first, scores[0] is the champion and scores[1] the runner-up — sorting makes the ranks easy to read.

Unlike Unit 06's string methods (which RETURN a changed string), .sort() mutates the list in place and returns None — so write scores.sort(), never best = scores.sort().

Put it together: a helper prints one ranked line, and we loop the sorted board to show every place.

def board_line(place, score):
    return "Place " + str(place) + ": " + str(score)


scores = [1500, 1200, 990, 850]
for place in range(len(scores)):
    print(board_line(place + 1, scores[place]))

Output

Place 1: 1500
Place 2: 1200
Place 3: 990
Place 4: 850

Put it together: a ranked hall must stay top-first when a new score arrives. This helper appends the score and immediately re-sorts the same list before returning it.

def board_line(place, score):
    return "Place " + str(place) + ": " + str(score)


def add_score(scores, new_score):
    scores.append(new_score)
    scores.sort(reverse=True)
    return scores


scores = [1500, 1200, 990, 850]
scores = add_score(scores, 1310)
for place in range(len(scores)):
    print(board_line(place + 1, scores[place]))

Output

Place 1: 1500
Place 2: 1310
Place 3: 1200
Place 4: 990
Place 5: 850

Notice

Append + re-sort keeps the hall ranked after every new score.

Try it yourself

def board_line(place, score):
    return "Place " + str(place) + ": " + str(score)


def add_score(scores, new_score):
    scores.append(new_score)
    scores.sort(reverse=True)
    return scores


n = int(input("How many scores? "))
scores = []
for i in range(n):
    score = int(input(f"Score {i + 1}: "))
    scores.append(score)
scores = add_score(scores, 1310)
for place in range(len(scores)):
    print(board_line(place + 1, scores[place]))

Notice

The real version reads the starting board with input(), then the same helper appends 1310 and re-sorts the hall. (Reads live input, so it does not run here.)

Lesson 3: Polish the Hall

A tier rewards one score: at least 1000 earns gold, at least 500 silver, else bronze.

score = 990
if score >= 1000:
    tier = "gold"
elif score >= 500:
    tier = "silver"
else:
    tier = "bronze"
print(f"A score of {score} earns the {tier} tier.")

Output

A score of 990 earns the silver tier.

Before adding a score, membership can guard against recording it twice. in belongs inside the if condition.

scores = [1500, 1310, 1200, 990, 850]
new_score = 1310
if new_score in scores:
    print(f"The score {new_score} is already on the board.")
else:
    print(f"Adding {new_score}.")

Output

The score 1310 is already on the board.

Try it yourself

n = int(input("How many scores? "))
scores = []
for i in range(n):
    score = int(input(f"Score {i + 1}: "))
    scores.append(score)
new_score = 1310
if new_score in scores:
    print(f"The score {new_score} is already on the board.")
else:
    print(f"Adding {new_score}.")

Notice

The real version reads the board with input() before making the same duplicate-membership check. (Reads live input, so it does not run here.)

Imagine a challenge where the qualifying score doubles each round. A while loop doubles a threshold until it reaches the champion score.

champion = 1500
threshold = 10
while threshold < champion:
    threshold = threshold * 2
print(f"First doubled threshold at or above {champion}: {threshold}")

Output

First doubled threshold at or above 1500: 2560

Here is a deliberate bug. A list with len(scores) items has positions 0 through len(scores) - 1, so the next cell asks for a position just past the end. Leave it unrun and predict the error.

Read the error

scores = [1500, 1200, 990, 850]
scores[len(scores)]

Read the traceback from the bottom: IndexError: list index out of range means the position does not exist. scores[-1] would select the final score instead.

Algorithm Extension

Extra loop practice — optional enrichment: these drills reuse the same loop shapes on small fixed data, so try as many as you like.

Pattern Spotlight: Find the best (max / argmax)

Keep the best so far while scanning — and remember WHO, not just the number. max(scores) gives the biggest number, but an explicit scan can keep the matching player name too. With parallel names and scores lists, loop through their positions; whenever the current score beats best_score, update both best_score and best_name.

names = ["Ada", "Bo", "Cy"]
scores = [3, 9, 5]
best_name = names[0]
best_score = scores[0]
print(best_name, best_score)

Output

Ada 3

Notice

Seed the champion from the FIRST player — best_name/best_score start as Ada 3; never best_score = 0 (a real score could be lower).

names = ["Ada", "Bo", "Cy"]
scores = [3, 9, 5]
best_name = names[0]
best_score = scores[0]
if scores[1] > best_score:
    best_name = names[1]
    best_score = scores[1]
print(best_name, best_score)

Output

Bo 9

Notice

Compare the next player; 9 > 3, so a new champion — update the NAME and the score together, giving Bo 9.

names = ["Ada", "Bo", "Cy"]
scores = [3, 9, 5]
i = 2
print(names[i], scores[i])

Output

Cy 5

Notice

names[i] and scores[i] are the SAME player (Cy 5) — the loop will walk i over both lists in step.

names = ["Ada", "Bo", "Cy"]
scores = [3, 9, 5]
best_name = names[0]
best_score = scores[0]
for i in range(len(scores)):
    if scores[i] > best_score:
        best_name = names[i]
        best_score = scores[i]
print(best_name, best_score)

Output

Bo 9

Notice

One pass keeps the highest-scoring player's NAME and score — the champion Bo 9, not just the number.

Try it yourself

n = int(input("How many players? "))
names = []
scores = []
for i in range(n):
    names.append(input(f"Name {i + 1}: "))
    scores.append(int(input(f"Score {i + 1}: ")))
best_name = names[0]
best_score = scores[0]
for i in range(len(scores)):
    if scores[i] > best_score:
        best_name = names[i]
        best_score = scores[i]
print(best_name, best_score)

Notice

The real version reads each player's name and score together with input(), then the same one-pass scan keeps the champion pair. (Reads live input, so it does not run here.)

Pattern Spotlight: Keep the ones that pass (filter)

The job is to build a NEW list of only the items that pass a test. Start with an empty list, check each score inside a loop, and append the score only when the condition passes.

Computational-thinking contrast: A person might glance across score cards and sort the qualifying cards into a new pile. A program checks one score at a time and appends each passing score to a new list.

kept = []
kept.append(9)
print(kept)

Output

[9]

Notice

Start an empty result list and append a keeper — kept is now [9].

kept = []
kept.append(9)
score = 3
if score >= 5:
    kept.append(score)
print(kept)

Output

[9]

Notice

Check BEFORE appending; 3 >= 5 is False, so 3 is not kept — kept stays [9].

scores = [3, 9, 5, 7]
kept = []
for s in scores:
    if s >= 5:
        kept.append(s)
print(kept)

Output

[9, 5, 7]

Notice

One pass copies just the qualifying scores (>= 5) into the new list — [9, 5, 7].

Try it yourself

n = int(input("How many scores? "))
scores = []
for i in range(n):
    score = int(input(f"Score {i + 1}: "))
    scores.append(score)
kept = []
for s in scores:
    if s >= 5:
        kept.append(s)
print(kept)

Notice

The real version reads the score list with input(), then the same filter copies only scores that pass. (Reads live input, so it does not run here.)

Recap

  • A list holds many items in order; scores[0] is the first and scores[-1] the last.
  • .append() adds an item to the end of the same list.
  • for one_score in scores: visits each item, and range(len(scores)) gives each position.
  • len, max and min measure a list; the total divided by the count gives a float average.
  • scores.sort(reverse=True) puts the top score first and returns None, so call it on its own line.

You can now build a leaderboard that crowns a champion.

Go to the exercises (24)

For parents and teachers: report a problem