Computer Programming 1 (JavaScript) • Problem Solving & Mini-Projects

Building Grade Tracker — I can build a grade tracker that computes averages and letter grades using arrays and functions.

Combine arrays and functions to automate grade calculations like a real gradebook application.

A JavaScript data file with code brackets and a laptop.
Inside this lesson 10 sections 5 questions 6 figures

SECTION 1

Historical Context & Motivation

Before computers, teachers calculated grades entirely by hand. They added up columns of numbers in physical gradebooks, divided to find averages, and looked up letter grades from a printed table. A single class of thirty students could take an hour to grade each assignment. As schools grew larger, the need for automated grade calculation became a real problem worth solving — and it's exactly the kind of problem that early computer programs were built to tackle.

1960s • Mainframe Report Cards

Universities began using mainframe computers to process student grades in batch, printing report cards overnight from punched-card data.

1979 • VisiCalc Spreadsheet

The first spreadsheet program, VisiCalc, let teachers enter grades into rows and columns and compute averages with formulas — a huge leap from pen and paper.

1995 • JavaScript Is Born

Brendan Eich created JavaScript in just ten days at Netscape. It soon became the language of interactive web pages, including online grade portals.

2010s • Online Gradebooks Go Mainstream

Platforms like Canvas, Google Classroom, and PowerSchool use JavaScript-driven interfaces to let students and parents check grades in real time.

Today you will build your own version of these tools. The core question is straightforward: given a list of numeric scores, how do you write a program that stores them, computes their average, and converts that average to a letter grade? Answering this question will pull together two of the most important ideas in programming — arrays for storing collections of data and functions for organizing reusable logic.

SECTION 2

Core Principles & Definitions

Building a grade tracker requires you to master a handful of foundational concepts. Each one plays a distinct role in the final program, and understanding them individually makes assembling the whole project much easier.

1

Arrays

An array is an ordered list of values stored in a single variable. In JavaScript you create one with square brackets: let grades = [88, 92, 75];. Each item has an index starting at 0.
2

Iteration

Iteration means looping through every element in a collection. A for loop or the .forEach() method visits each grade so you can add it to a running total.
3

Functions

A function is a reusable block of code with a name. It takes parameters (inputs) and returns a value (output). Think of it as a mini-machine: data goes in, a result comes out.
4

Conditional Logic

Conditional logic uses if / else if / else statements to choose a path based on a condition. This is how you map a numeric average to the correct letter grade.
5

Accumulator Pattern

The accumulator pattern initializes a variable (e.g., let sum = 0), then adds to it inside a loop. After the loop, sum holds the total of all grades.
✦

KEY TAKEAWAY

Think of an array like a row of labeled mailboxes in an apartment building. Each mailbox (index) holds one piece of mail (a grade). A function is like the mail carrier who walks down the row, collects all the mail, and delivers a single summary report — the average.

SECTION 3

Visual Explanation — Data Flow Diagram

The diagram below shows how data moves through the grade tracker from input to output. Follow the arrows to see how an array of raw scores is processed by two functions — one that calculates the average and another that determines the letter grade.

Grade Tracker — Data Flowgrades Array[0] → 88[1] → 92[2] → 75[3] → 98calcAverage(grades)1. sum = 02. loop → sum += grade3. return sum / length88.25getLetterGrade(avg)if avg ≥ 90 → "A"else if avg ≥ 80 → "B"else if avg ≥ 70 → "C"Output"B" (88.25)Key ConceptsArray stores multiple grades in one variablecalcAverage() uses the accumulator pattern (loop + sum)getLetterGrade() uses conditional logic (if / else if)Functions connect together: output of one becomes input of the next
Data flows left to right: raw scores stored in a violet grades array are passed to the cyan calcAverage function, whose numeric result feeds into the pink getLetterGrade function, producing the final green output.

Notice how each box in the diagram represents a single, well-defined task. The array holds the data, calcAverage handles the math, and getLetterGrade handles the classification. This separation is called decomposition — breaking a large problem into smaller, manageable pieces. Each function can be tested and debugged on its own before you connect them together.

SECTION 4

How It Works — The Code Logic

Let's break down the two core computations: calculating the average and determining the letter grade. Even though this is a programming project, there is a simple mathematical formula at the heart of it.

AVERAGE FORMULA

average=(g1+g2+g3+…+gn)÷naverage = (g₁ + g₂ + g₃ + … + gₙ) ÷ n

Where g₁, g₂, …, gₙ are the individual grades stored in the array, and n is the total number of grades (grades.length in JavaScript).

In code, you implement this formula using the accumulator pattern. You start with let sum = 0, loop through every element in the array while adding each grade to sum, and then divide sum by grades.length. The result is the arithmetic mean of all grades.

calcAverage Function

Here is the function in JavaScript:

ℹ

calcAverage — Code

function calcAverage(grades) { let sum = 0; for (let i = 0; i < grades.length; i++) { sum += grades[i]; } return sum / grades.length; }

The parameter grades expects an array of numbers. The for loop starts at index 0 and continues as long as i is less than grades.length. Each pass through the loop adds the current element to sum. After the loop finishes, the function returns the average.

getLetterGrade Function

ℹ

getLetterGrade — Code

function getLetterGrade(avg) { if (avg >= 90) return "A"; if (avg >= 80) return "B"; if (avg >= 70) return "C"; if (avg >= 60) return "D"; return "F"; }

This function takes a single number — the average — and uses a chain of if statements to determine the corresponding letter grade. The order matters: you must check for the highest threshold first. Once a condition is met, return immediately exits the function, so you do not need else if (though using it would also work).

LETTER GRADE MAPPING

A:avg≥90∣B:80≤avg<90∣C:70≤avg<80∣D:60≤avg<70∣F:avg<60A: avg ≥ 90 | B: 80 ≤ avg < 90 | C: 70 ≤ avg < 80 | D: 60 ≤ avg < 70 | F: avg < 60

This standard 10-point scale is used in many U.S. schools. Some schools use different cutoffs — the beauty of a function is that you can adjust the thresholds in one place.

SECTION 5

Detailed Code Walkthrough

Now let's see the complete grade tracker program assembled together and trace exactly what happens at each step. The diagram below shows how the loop processes each index of the array, updating the accumulator on every pass.

Accumulator Pattern — Step-by-Step Tracegrades = [88, 92, 75, 98, 84]sum starts at 0igrades[i]sum beforesum += grades[i]sum after08800 + 88881928888 + 92180275180180 + 75255398255255 + 98353484353353 + 84437After loop: sum = 437, grades.length = 5average = 437 ÷ 5 = 87.4 → Letter Grade: "B"87.4 ≥ 80 and 87.4 < 90, so getLetterGrade returns "B"
This trace table shows how sum grows with each loop iteration. After the loop, dividing by the array's length gives the average, which is then mapped to a letter grade.

The Complete Program

💡

Full Grade Tracker Code

// --- Data --- let grades = [88, 92, 75, 98, 84]; // --- Function 1: Calculate Average --- function calcAverage(arr) { let sum = 0; for (let i = 0; i < arr.length; i++) { sum += arr[i]; } return sum / arr.length; } // --- Function 2: Determine Letter Grade --- function getLetterGrade(avg) { if (avg >= 90) return "A"; if (avg >= 80) return "B"; if (avg >= 70) return "C"; if (avg >= 60) return "D"; return "F"; } // --- Main Logic --- let avg = calcAverage(grades); let letter = getLetterGrade(avg); console.log("Average: " + avg.toFixed(1)); console.log("Letter Grade: " + letter);

The .toFixed(1) method rounds the average to one decimal place for cleaner output. Without it, JavaScript might display a number with many decimal places. You can also use Math.round(avg * 10) / 10 to achieve the same effect.

SECTION 6

Worked Example — A Full Semester

Imagine a student named Maya has the following seven test scores for the semester: 95, 82, 78, 91, 88, 73, and 85. Let's walk through the grade tracker step by step.

Maya's Semester Grade

  1. 1

    Step 1 — Store the Grades

    Create an array to hold all seven scores: let grades = [95, 82, 78, 91, 88, 73, 85];. The array has a length of 7.
    grades.length → 7
  2. 2

    Step 2 — Call calcAverage

    Pass the array into calcAverage(grades). Inside the function, the loop accumulates the sum: 95 + 82 + 78 + 91 + 88 + 73 + 85 = 592.
    sum → 592
  3. 3

    Step 3 — Divide to Get the Average

    The function returns 592 / 7, which equals approximately 84.571… JavaScript stores the full decimal value.
    average ≈ 84.6
  4. 4

    Step 4 — Determine the Letter Grade

    Pass 84.571… into getLetterGrade(84.571). The first check is avg >= 90 — false. The second check is avg >= 80 — true! The function returns "B".
    Letter Grade: "B"
  5. 5

    Step 5 — Display the Result

    Using console.log, the program outputs both values to the console. The .toFixed(1) call formats the average to one decimal place.
    "Average: 84.6" and "Letter Grade: B"

SECTION 7

Design Choices — Strengths & Limitations

Every programming design involves trade-offs. The grade tracker we built is intentionally simple, which makes it easy to understand but also limits what it can do. The table below compares the strengths and limitations of our current design.

AspectStrengthLimitation
Data StorageArrays hold any number of grades. Adding a grade is as easy as grades.push(91).Grades are not labeled by assignment name — you lose context about what each number represents.
Average CalculationThe accumulator pattern is clear, efficient, and works for any array size.All grades are weighted equally. Exams and quizzes count the same.
Letter MappingStraightforward conditional chain; easy to read and modify thresholds.Does not handle plus/minus grades (e.g., A−, B+) without additional conditions.
FunctionsReusable — you can call them for different classes or semesters without rewriting code.No error handling — passing an empty array causes a division-by-zero issue.

Comparing the design choices in our grade tracker

✦

KEY TAKEAWAY

Building software is like building with LEGO blocks. You start with a few simple pieces (arrays, functions, conditionals) and snap them together to create something useful. As you level up, you can swap in fancier pieces — like objects for labeled grades or weighted average functions — without rebuilding the whole structure.

SECTION 8

Connection to Advanced Concepts

The grade tracker is a gateway project. The patterns you've learned here — storing data in arrays, processing it with loops, organizing logic into functions — appear everywhere in more advanced programming. The table below shows how each concept you used today scales up.

What You Used TodayWhere It Leads
Array of numbersArrays of objects (e.g., {name: "Quiz 1", score: 88, weight: 0.2}) for richer data modeling
for loop with accumulatorHigher-order array methods like .reduce(), .map(), and .filter()
Two separate functionsClasses and methods in object-oriented programming (OOP), where a GradeTracker class bundles data and behavior together
console.log outputDOM manipulation to display grades in a web page with HTML and CSS, building a real user interface
Hardcoded grade arrayUser input via forms or prompts; persistent storage with databases or localStorage

As you advance, you might also add weighted averages where exams count more than homework, or input validation to reject scores below 0 or above 100. These enhancements use the same fundamental patterns — loops, conditionals, and functions — with slight modifications. The foundation you've built today is genuinely reusable.

SECTION 9

Practice Problems

Question 1: CONCEPTUAL

Explain why we use a separate function for calculating the average instead of putting all the code in one long script. What advantage does this give us?
Show answer
Separating the average calculation into its own function makes the code reusable — you can call calcAverage() on any array of numbers without rewriting the loop. It also makes the program easier to debug because you can test the average function independently. If there's a bug in the letter-grade logic, you know the averaging code isn't to blame. This principle is called decomposition — breaking a complex problem into smaller, testable parts.

Question 2: BASIC CALCULATION

Given the array let scores = [70, 85, 90, 60, 95];, manually trace the accumulator pattern and determine the average and the letter grade.
Show answer
Start with sum = 0. After each iteration: 0 + 70 = 70, 70 + 85 = 155, 155 + 90 = 245, 245 + 60 = 305, 305 + 95 = 400. The final sum is 400. Divide by 5 (the number of scores): 400 ÷ 5 = 80.0. Since 80 ≥ 80, the letter grade is "B". Note that 80 is exactly on the boundary — the condition avg >= 80 is true, so it qualifies as a B, not a C.

Question 3: INTERMEDIATE

Modify the getLetterGrade function so it also handles plus and minus grades. For example, 97–100 = A+, 93–96 = A, 90–92 = A−, 87–89 = B+, and so on. Write the updated function.
Show answer
You need to add more conditions and check narrower ranges. For example: function getLetterGrade(avg) { if (avg >= 97) return "A+"; if (avg >= 93) return "A"; if (avg >= 90) return "A-"; if (avg >= 87) return "B+"; if (avg >= 83) return "B"; if (avg >= 80) return "B-"; if (avg >= 77) return "C+"; if (avg >= 73) return "C"; if (avg >= 70) return "C-"; if (avg >= 67) return "D+"; if (avg >= 60) return "D"; return "F"; } The key insight is that you must check from highest to lowest. Each return statement exits the function immediately, so only the first matching condition fires. This approach scales the same pattern — no new syntax is needed, just more conditions.

Question 4: APPLIED

A teacher has two classes. Class A scores: [91, 84, 77, 95, 88]. Class B scores: [72, 68, 85, 79, 90, 81]. Write code that uses the calcAverage function to find each class's average, then prints which class performed better.
Show answer
First, call let avgA = calcAverage([91, 84, 77, 95, 88]); which gives (91+84+77+95+88) ÷ 5 = 435 ÷ 5 = 87.0. Then let avgB = calcAverage([72, 68, 85, 79, 90, 81]); gives (72+68+85+79+90+81) ÷ 6 = 475 ÷ 6 ≈ 79.2. Use a conditional: if (avgA > avgB) { console.log("Class A performed better"); } else { console.log("Class B performed better"); }. Class A wins with an 87.0 average (B) versus Class B's 79.2 (C). This demonstrates the power of reusable functions — one function works for any array.

Question 5: CRITICAL THINKING

What happens if a student has no grades yet — i.e., the array is empty (let grades = [];)? What will calcAverage(grades) return? Explain why this is a problem and write code to handle it gracefully.
Show answer
If the array is empty, grades.length is 0. The loop body never executes, so sum remains 0. The function returns 0 / 0, which in JavaScript produces NaN (Not a Number). Passing NaN to getLetterGrade means every comparison fails, so it returns "F" — clearly incorrect. To fix this, add a guard clause at the top of calcAverage: if (arr.length === 0) return 0; or return a message like "No grades entered." This is called input validation — anticipating edge cases and preventing bugs before they occur.

SUMMARY

Summary

Summary

In this lesson you built a complete grade tracker in JavaScript. You stored scores in an array, used the accumulator pattern inside a for loop to sum all values, divided by array length to compute the average, and applied conditional logic to convert that average into a letter grade.

The two functions — calcAverage and getLetterGrade — demonstrate decomposition: breaking a problem into small, reusable, testable pieces. This same pattern scales up to real-world applications like online gradebooks, data dashboards, and more. Remember to handle edge cases such as empty arrays, and consider future enhancements like weighted averages and user input to keep building your skills.

Varsity Tutors • Computer Programming 1 (JavaScript) • Building Grade Tracker