College Board Requirements:

□ Instructions for input from one of the following:

◆ the user (including user actions that trigger events)

◆ a device

◆ an online data stream

◆ a file

□ Use of at least one list (or other collection type) to represent a collection of data that is stored and used to manage program complexity and help fulfill the program’s purpose

□ At least one procedure that contributes to the program’s intended purpose, where you have defined:

◆ the procedure’s name

◆ the return type (if necessary)

◆ one or more parameters

□ An algorithm that includes sequencing, selection, and iteration that is in the body of the selected procedure

□ Calls to your student-developed procedure

□ Instructions for output (tactile, audible, visual, or textual) based on input and program functionality

Instructions for Input:

In my Clash Royale Quiz, the input from the user is obtained through radio buttons within the quiz section. Each question has multiple choices as radio inputs, this allows the users to select their answer. Here’s the code I used for that below.

function nextQuestion() {
    if (currentQuestion < questions.length) {
        document.getElementById('quiz').innerHTML = createQuestionElement(currentQuestion);
        document.getElementById('nextBtn').textContent = currentQuestion === questions.length - 1 ? 'Finish' : 'Next Question';
    } else {
        showResults();
    }
    currentQuestion++;
}

Another example is within the createQuestionElement. In that function, radio buttons are created for each answer:

function createQuestionElement(index) {
    var question = questions[index];
    var qElement = '<div class="question">' + '<p>' + question.question + '</p>';
    for (var key in question.answers) {
        qElement += '<label><input type="radio" name="question' + index + '" value="' + key + '" onclick="selectAnswer(\'' + key + '\')">' + question.answers[key] + '</label>';
    }
    return qElement + '</div>';
}

Use of at Least One List (or Other Collection Type):

The code has arrays for managing data. The questions array stores quiz questions and their possible answers.

var questions = [
    { question: "Choose your favorite card type:", answers: { a: "Offensive (e.g., Hog Rider, Balloon)", b: "Defensive (e.g., Tesla, Tornado)", c: "Support (e.g., Musketeer, Wizard)", d: "Tank (e.g., Golem, Giant)" }},
    { question: "What's your preferred strategy?", answers: { a: "Fast-paced attacks", b: "Control and counter", c: "Building up a big push", d: "Surprise elements and versatility" }},
    { question: "How do you react to an enemy push?", answers: { a: "Counter-attack on the other lane", b: "Defend solidly and counter-push", c: "Absorb some damage and build a counter-push", d: "Use cycle cards to defend and quickly reset" }},
    { question: "Pick a card you consider essential in any deck:", answers: { a: "Fireball", b: "Zap", c: "Skeleton Army", d: "Elixir Collector" }},
    { question: "What is your reaction to seeing a big tank like Golem?", answers: { a: "Rush the other lane", b: "Build a big defense", c: "Ignore and push the opposite lane", d: "Try to distract and chip away" }},
    { question: "Your favorite time to attack is:", answers: { a: "Immediately after defending", b: "When I have an elixir advantage", c: "Double elixir time", d: "When my opponent makes a mistake" }},
    { question: "Which of these spells do you prefer?", answers: { a: "Lightning", b: "Poison", c: "Fireball", d: "Rocket" }},
    { question: "What role do you prefer your cards to have?", answers: { a: "Versatility", b: "Specific counter", c: "High damage output", d: "Tankiness" }},
    { question: "How do you prefer to win matches?", answers: { a: "One big push", b: "Consistent pressure", c: "Defensive play and counter-attacks", d: "Spell cycle" }},
    { question: "What's your stance on elixir management?", answers: { a: "Aggressive spending for pressure", b: "Balanced - spend wisely", c: "Save for big pushes", d: "Spend as needed but focus on counters" }}
];

Additionally, the allCards array represents a collection of Clash Royale cards with things like type, strategy, and elixir cost.

var allCards = [
    { name: "Hog Rider", type: "Offensive", strategy: "Fast-paced attacks", elixirCost: 4 },
    { name: "Tesla", type: "Defensive", strategy: "Control and counter", elixirCost: 4 },
    { name: "Musketeer", type: "Support", strategy: "Control and counter", elixirCost: 4 },
    { name: "Golem", type: "Tank", strategy: "Building up a big push", elixirCost: 8 },
    { name: "Balloon", type: "Offensive", strategy: "Fast-paced attacks", elixirCost: 5 },
    { name: "Tornado", type: "Defensive", strategy: "Control and counter", elixirCost: 3 },
    { name: "Wizard", type: "Support", strategy: "Building up a big push", elixirCost: 5 },
    { name: "Giant", type: "Tank", strategy: "Building up a big push", elixirCost: 5 },
    { name: "Zap", type: "Support", strategy: "Fast-paced attacks", elixirCost: 2 },
    { name: "Fireball", type: "Support", strategy: "Control and counter", elixirCost: 4 },
    { name: "Ice Spirit", type: "Defensive", strategy: "Fast-paced attacks", elixirCost: 1 },
    { name: "Miner", type: "Offensive", strategy: "Surprise elements and versatility", elixirCost: 3 },
    { name: "Skeleton Army", type: "Defensive", strategy: "Control and counter", elixirCost: 3 },
    { name: "Elixir Collector", type: "Support", strategy: "Building up a big push", elixirCost: 6 },
    { name: "Lumberjack", type: "Offensive", strategy: "Fast-paced attacks", elixirCost: 4 },
    { name: "Baby Dragon", type: "Support", strategy: "Building up a big push", elixirCost: 4 },
    { name: "Night Witch", type: "Offensive", strategy: "Building up a big push", elixirCost: 4 },
    { name: "Royal Giant", type: "Tank", strategy: "Surprise elements and versatility", elixirCost: 6 },
    { name: "Electro Wizard", type: "Support", strategy: "Control and counter", elixirCost: 4 },
    { name: "Mega Minion", type: "Defensive", strategy: "Control and counter", elixirCost: 3 },
    { name: "Poison", type: "Support", strategy: "Surprise elements and versatility", elixirCost: 4 },
    { name: "Dark Prince", type: "Offensive", strategy: "Fast-paced attacks", elixirCost: 4 },
    { name: "Bowler", type: "Defensive", strategy: "Control and counter", elixirCost: 5 },
];

At Least One Procedure That Contributes to the Program’s Intended Purpose:

The generateCustomDeckRecommendation function shows a custom procedure with parameters. This function processes user preferences and from that, it then generates a Clash Royale deck based on the users answers to the questions. It also filters and sorts the allCards array.

function generateCustomDeckRecommendation(cardTypePreference, strategyPreference) {

    var filteredCards = allCards.filter(card => card.type === cardTypePreference && card.strategy === strategyPreference);
    var recommendedDeck = filteredCards.sort((a, b) => a.elixirCost - b.elixirCost).slice(0, 8);
    var deckMessage = "Recommended Deck based on your preferences: " + recommendedDeck.map(card => card.name).join(", ");
    return deckMessage;
}

Algorithm Involving Sequencing, Selection, and Iteration:

  • Sequencing: Operations are performed in a specific order, starting from initializing variables, iterating over elements, calculating the average elixir cost, and also updating the UI.
  • Iteration: It iterates over card div elements so it can sum up their elixir costs using a for loop.
  • Selection: Uses an if statement to check whether the average elixir cost element exists before updating or creating it to show the value.
function recalculateAndDisplayAverageElixirCost() {
    var totalElixirCost = 0;
    var cardDivs = document.getElementById('deckImages').querySelectorAll('div');

    for (var i = 0; i < cardDivs.length; i++) {
        var cardName = cardDivs[i].querySelector('img').alt; 
        totalElixirCost += elixirCosts[cardName];
    }

    var averageElixirCost = (totalElixirCost / cardDivs.length).toFixed(2);

    var avgElixirCostElement = document.getElementById('averageElixirCost');
    if (!avgElixirCostElement) {
        avgElixirCostElement = document.createElement('p');
        avgElixirCostElement.id = 'averageElixirCost';
        document.getElementById('result').appendChild(avgElixirCostElement);
    }

    avgElixirCostElement.textContent = 'Average Elixir Cost: ' + averageElixirCost;
}

Calls to the Student-Developed Procedure:

This code shown below sets the user’s “Strategy Preferences” and their “Card type preferences”. Then calls the generateCustomDeckRecommendation to generate a deck recomendation. The recommendation is also logged to the console.

var userCardTypePreference = "Offensive";
var userStrategyPreference = "Fast-paced attacks";

var customDeckRecommendation = generateCustomDeckRecommendation(userCardTypePreference, userStrategyPreference);
console.log(customDeckRecommendation);

Instructions for output (tactile, audible, visual, or textual) based on input and program functionality:

After the user completes the quiz, the showResults function shown below updates the website and then displays the deck as well as its average elixir cost.

function showResults() {
    var deckSuggestion = calculateDeckSuggestion();
    document.getElementById('quiz').style.display = 'none';
    document.getElementById('nextBtn').style.display = 'none';
    var deckListHtml = '<h3>Your Ideal Deck:</h3><div id="deckImages">';
    var totalElixirCost = 0;
    var deckListText = deckSuggestion.split(': ')[1].split(', ');
    deckListText.forEach(function(cardName) {
        deckListHtml += `<div><img src="${cardImages[cardName.trim()]}" alt="${cardName}" class="card-image">${cardName}</div>`;
        totalElixirCost += elixirCosts[cardName.trim()];
    });
    var averageElixirCost = (totalElixirCost / deckListText.length).toFixed(2);
    document.getElementById('result').innerHTML = deckListHtml;
    var avgElixirCostElement = document.getElementById('averageElixirCost');
    if (!avgElixirCostElement) {
        avgElixirCostElement = document.createElement('p');
        avgElixirCostElement.id = 'averageElixirCost';
        document.getElementById('result').appendChild(avgElixirCostElement);
    }
    avgElixirCostElement.textContent = 'Average Elixir Cost: ' + averageElixirCost;
    document.getElementById('result').style.display = 'block';
    showViableOptions(deckSuggestion);
}

CPT Video Requirements for College Board:

□ Input to your program

□ At least one aspect of the functionality of your program

□ Output produced by your program

Your video may NOT contain:

□ Any distinguishing information about yourself

□ Voice narration (though text captions are encouraged)

Your video must be:

□ Either .webm, .mp4, .wmv, .avi, or .mov format

□ No more than 1 minute in length

□ No more than 30MB in file size

CPT Video