diff --git a/Week1/practice-exercises/1-remove-the-comma.js b/Week1/practice-exercises/1-remove-the-comma.js index b71cffd..002f52c 100644 --- a/Week1/practice-exercises/1-remove-the-comma.js +++ b/Week1/practice-exercises/1-remove-the-comma.js @@ -7,8 +7,12 @@ let myString = 'hello,this,is,a,difficult,to,read,sentence'; +// ✅ Replace commas with spaces +myString = myString.replace(/,/g, ' '); +// Optional: log it +console.log(myString); /* --- Code that will test your solution, do NOT change. Write above this line --- */ -console.assert(myString === 'hello this is a difficult to read sentence', 'There is something wrong with your solution'); \ No newline at end of file +console.assert(myString === 'hello this is a difficult to read sentence', 'There is something wrong with your solution'); diff --git a/Week1/practice-exercises/2-even-odd-reporter.js b/Week1/practice-exercises/2-even-odd-reporter.js index 6edf23e..9273364 100644 --- a/Week1/practice-exercises/2-even-odd-reporter.js +++ b/Week1/practice-exercises/2-even-odd-reporter.js @@ -7,3 +7,10 @@ * If it's even, log to the console The number [PUT_NUMBER_HERE] is even!. */ +for (let i = 0; i <= 20; i++) { + if (i % 2 === 0) { + console.log(`The number ${i} is even!`); + } else { + console.log(`The number ${i} is odd!`); + } +} diff --git a/Week1/practice-exercises/3-recipe-card.js b/Week1/practice-exercises/3-recipe-card.js index 24bcb54..7326538 100644 --- a/Week1/practice-exercises/3-recipe-card.js +++ b/Week1/practice-exercises/3-recipe-card.js @@ -4,11 +4,21 @@ * Declare a variable that holds an empty object literal (your meal recipe). * Give the object 3 properties: a title (string), a servings (number) and an ingredients (array of strings) property. * Log each property out separately, using a loop (for, while or do/while) - * - * Expected result: - * - * Meal name: Omelette - * Serves: 2 - * Ingredients: 4 eggs, 2 strips of bacon, 1 tsp salt/pepper */ + +const recipe = { + title: 'Omelette', + servings: 2, + ingredients: ['4 eggs', '2 strips of bacon', '1 tsp salt/pepper'], +}; + +// Log title and servings +console.log(`Meal name: ${recipe.title}`); +console.log(`Serves: ${recipe.servings}`); + +// Log ingredients using a loop +console.log('Ingredients:'); +for (let i = 0; i < recipe.ingredients.length; i++) { + console.log(`- ${recipe.ingredients[i]}`); +} diff --git a/Week1/practice-exercises/4-reading-list.js b/Week1/practice-exercises/4-reading-list.js index f535657..66da3cb 100644 --- a/Week1/practice-exercises/4-reading-list.js +++ b/Week1/practice-exercises/4-reading-list.js @@ -9,3 +9,31 @@ * If you haven't read it log a string like You still need to read "The Lord of the Rings" */ +const books = [ + { + title: 'The Hobbit', + author: 'J.R.R. Tolkien', + alreadyRead: true, + }, + { + title: 'The Lord of the Rings', + author: 'J.R.R. Tolkien', + alreadyRead: false, + }, + { + title: 'Harry Potter and the Sorcerer\'s Stone', + author: 'J.K. Rowling', + alreadyRead: true, + }, +]; + +for (let i = 0; i < books.length; i++) { + const book = books[i]; + console.log(`${book.title} by ${book.author}`); + + if (book.alreadyRead) { + console.log(`You already read "${book.title}"`); + } else { + console.log(`You still need to read "${book.title}"`); + } +} diff --git a/Week1/practice-exercises/5-who-wants-a-drink.js b/Week1/practice-exercises/5-who-wants-a-drink.js index f37f02b..e20f152 100644 --- a/Week1/practice-exercises/5-who-wants-a-drink.js +++ b/Week1/practice-exercises/5-who-wants-a-drink.js @@ -8,4 +8,24 @@ */ // There are 3 different types of drinks: -const drinkTypes = ['cola', 'lemonade', 'water']; \ No newline at end of file +const drinkTypes = ['cola', 'lemonade', 'water']; +const drinkTray = []; + +const drinkCounts = { + cola: 0, + lemonade: 0, + water: 0, +}; + +for (let i = 0; i < 5; i++) { + for (let j = 0; j < drinkTypes.length; j++) { + const drink = drinkTypes[j]; + if (drinkCounts[drink] < 2) { + drinkTray.push(drink); + drinkCounts[drink]++; + break; + } + } +} + +console.log(`Hey guys, I brought a ${drinkTray.join(', ')}!`); diff --git a/Week1/prep-exercises/1-traffic-light/traffic-light-1.js b/Week1/prep-exercises/1-traffic-light/traffic-light-1.js index f1d9169..da67c78 100644 --- a/Week1/prep-exercises/1-traffic-light/traffic-light-1.js +++ b/Week1/prep-exercises/1-traffic-light/traffic-light-1.js @@ -8,24 +8,18 @@ const trafficLight = { }; let rotations = 0; + while (rotations < 2) { const currentState = trafficLight.state; console.log("The traffic light is on", currentState); - // TODO - // if the color is green, turn it orange - // if the color is orange, turn it red - // if the color is red, add 1 to rotations and turn it green + // Transition logic + if (currentState === "green") { + trafficLight.state = "orange"; + } else if (currentState === "orange") { + trafficLight.state = "red"; + } else if (currentState === "red") { + rotations += 1; + trafficLight.state = "green"; + } } - -/** - * The output should be: - -The traffic light is on green -The traffic light is on orange -The traffic light is on red -The traffic light is on green -The traffic light is on orange -The traffic light is on red - -*/ diff --git a/Week1/prep-exercises/1-traffic-light/traffic-light-2.js b/Week1/prep-exercises/1-traffic-light/traffic-light-2.js index 8c6ba95..17ca0cd 100644 --- a/Week1/prep-exercises/1-traffic-light/traffic-light-2.js +++ b/Week1/prep-exercises/1-traffic-light/traffic-light-2.js @@ -14,20 +14,13 @@ while (cycle < 2) { const currentState = trafficLight.possibleStates[trafficLight.stateIndex]; console.log("The traffic light is on", currentState); - // TODO - // if the color is green, turn it orange - // if the color is orange, turn it red - // if the color is red, add 1 to cycles and turn it green -} - -/** - * The output should be: - -The traffic light is on green -The traffic light is on orange -The traffic light is on red -The traffic light is on green -The traffic light is on orange -The traffic light is on red - -*/ + // Transition logic + if (currentState === "green") { + trafficLight.stateIndex = 1; // orange + } else if (currentState === "orange") { + trafficLight.stateIndex = 2; // red + } else if (currentState === "red") { + cycle++; // completed one full cycle + trafficLight.stateIndex = 0; // green + } +} \ No newline at end of file diff --git a/Week2/prep-exercises/1-traffic-light/traffic-light.js b/Week2/prep-exercises/1-traffic-light/traffic-light.js index f4a5c1a..70f9cb5 100644 --- a/Week2/prep-exercises/1-traffic-light/traffic-light.js +++ b/Week2/prep-exercises/1-traffic-light/traffic-light.js @@ -6,17 +6,13 @@ */ function getCurrentState(trafficLight) { - // TODO - // Should return the current state (i.e. colour) of the `trafficLight` - // object passed as a parameter. + // ✅ Return current state from possibleStates using stateIndex + return trafficLight.possibleStates[trafficLight.stateIndex]; } function getNextStateIndex(trafficLight) { - // TODO - // Return the index of the next state of the `trafficLight` such that: - // - if the color is green, it will turn to orange - // - if the color is orange, it will turn to red - // - if the color is red, it will turn to green + // ✅ Cycle through: 0 → 1 → 2 → 0 → ... + return (trafficLight.stateIndex + 1) % trafficLight.possibleStates.length; } // This function loops for the number of seconds specified by the `secs` @@ -47,14 +43,3 @@ function main() { } main(); -/** - * The output should be: - -0 The traffic light is now green -1 The traffic light is now orange -2 The traffic light is now red -3 The traffic light is now green -4 The traffic light is now orange -5 The traffic light is now red - -*/ diff --git a/Week2/prep-exercises/2-experiments/index.js b/Week2/prep-exercises/2-experiments/index.js index 7e5aa92..002502a 100644 --- a/Week2/prep-exercises/2-experiments/index.js +++ b/Week2/prep-exercises/2-experiments/index.js @@ -3,27 +3,19 @@ function runExperiment(sampleSize) { const valueCounts = [0, 0, 0, 0, 0, 0]; - // TODO - // Write a for loop that iterates `sampleSize` times (sampleSize is a number). - // In each loop iteration: - // - // 1. Generate a random integer between 1 and 6 (as if throwing a six-sided die). - // 2. Add `1` to the element of the `valueCount` that corresponds to the random - // value from the previous step. Use the first element of `valueCounts` - // for keeping a count how many times the value 1 is thrown, the second - // element for value 2, etc. + // Simulate die rolls + for (let i = 0; i < sampleSize; i++) { + const roll = Math.floor(Math.random() * 6) + 1; // random int 1–6 + valueCounts[roll - 1]++; // update the corresponding count + } const results = []; - // TODO - // Write a for..of loop for the `valueCounts` array created in the previous - // loop. In each loop iteration: - // 1. For each possible value of the die (1-6), compute the percentage of how - // many times that value was thrown. Remember that the first value of - // `valueCounts` represent the die value of 1, etc. - // 2. Convert the computed percentage to a number string with a precision of - // two decimals, e.g. '14.60'. - // 3. Then push that string onto the `results` array. + // Compute percentages + for (const count of valueCounts) { + const percentage = ((count / sampleSize) * 100).toFixed(2); + results.push(percentage); + } return results; } @@ -31,16 +23,10 @@ function runExperiment(sampleSize) { function main() { const sampleSizes = [100, 1000, 1000000]; - // TODO - // Write a for..of loop that calls the `runExperiment()` function for each - // value of the `sampleSizes` array. - // Log the results of each experiment as well as the experiment size to the - // console. - // The expected output could look like this: - // - // [ '26.00', '17.00', '10.00', '19.00', '16.00', '12.00' ] 100 - // [ '14.60', '17.10', '19.30', '15.50', '16.70', '16.80' ] 1000 - // [ '16.71', '16.68', '16.69', '16.66', '16.67', '16.59' ] 1000000 + for (const size of sampleSizes) { + const result = runExperiment(size); + console.log(result, size); + } } main(); diff --git a/Week3/challenges/1-sum-entries.js b/Week3/challenges/1-sum-entries.js index f7dd419..5f69dcb 100644 --- a/Week3/challenges/1-sum-entries.js +++ b/Week3/challenges/1-sum-entries.js @@ -1,17 +1,16 @@ -/** - * Credit to https://adventofcode.com/ for this exercise - -In the list below you have an array of numbers. The goal is to find the two numbers that add up to 2020. - -Once you have found those numbers, multiply the numbers and store the result of that in the result variable. - */ - - const list = [1721, 979, 366, 299, 675, 1456]; let result; - -// Write your code here +// Find two numbers that sum to 2020 +for (let i = 0; i < list.length; i++) { + for (let j = i + 1; j < list.length; j++) { + if (list[i] + list[j] === 2020) { + result = list[i] * list[j]; + break; + } + } + if (result !== undefined) break; +} // TEST CODE, do not change -console.assert(result === 514579, `The result is not correct, it is ${result}, but should be 514579`); \ No newline at end of file +console.assert(result === 514579, `The result is not correct, it is ${result}, but should be 514579`); diff --git a/Week3/challenges/2-sum-three-entries.js b/Week3/challenges/2-sum-three-entries.js index f5f8773..d72a3dd 100644 --- a/Week3/challenges/2-sum-three-entries.js +++ b/Week3/challenges/2-sum-three-entries.js @@ -1,17 +1,19 @@ -/** - * Credit to https://adventofcode.com/ for this exercise - -In the list below you have an array of numbers. The goal is to find the three numbers that add up to 2020. - -Once you have found those numbers, multiply the numbers and store the result of that in the result variable. - */ - - const list = [1721, 979, 366, 299, 675, 1456]; let result; - -// Write your code here +// Find three numbers that sum to 2020 +for (let i = 0; i < list.length; i++) { + for (let j = i + 1; j < list.length; j++) { + for (let k = j + 1; k < list.length; k++) { + if (list[i] + list[j] + list[k] === 2020) { + result = list[i] * list[j] * list[k]; + break; + } + } + if (result !== undefined) break; + } + if (result !== undefined) break; +} // TEST CODE, do not change -console.assert(result === 241861950, `The result is not correct, it is ${result}, but should be 241861950`); \ No newline at end of file +console.assert(result === 241861950, `The result is not correct, it is ${result}, but should be 241861950`); diff --git a/Week3/challenges/3-password-validation.js b/Week3/challenges/3-password-validation.js index fa7ad11..c70b64b 100644 --- a/Week3/challenges/3-password-validation.js +++ b/Week3/challenges/3-password-validation.js @@ -1,23 +1,19 @@ - -/** - * Credit to https://adventofcode.com/ for this exercise - * - * Each object in the passwordList gives a password policy and then the password. - * The times field says the minimal and maximal amount of times the letter should be in the password. So 1-3 means at least 1 time, at most 3 times. - * The letter field gives which letter should be counted - * The password field gives the password - * - * In the list 2 passwords are valid, the middle one is not as there is no b in the password. - * - * We expect the output: - * - * 'abcde' is VALID, a is present 1 times and should have been present at least 1 and at most 3 times - * 'cdefg' is INVALID, b is present 0 times and should have been present at least 1 and at most 3 times - * 'ccccccccc' is VALID, c is present 9 times and should have been present at least 2 and at most 9 times - */ - const passwordList = [ { times: '1-3', letter: 'a', password: 'abcde'}, { times: '1-3', letter: 'b', password: 'cdefg'}, { times: '2-9', letter: 'c', password: 'ccccccccc'} -]; \ No newline at end of file +]; + +for (const entry of passwordList) { + const [min, max] = entry.times.split('-').map(Number); + const letter = entry.letter; + const password = entry.password; + + const count = password.split('').filter(char => char === letter).length; + + const isValid = count >= min && count <= max; + + console.log( + `'${password}' is ${isValid ? 'VALID' : 'INVALID'}, ${letter} is present ${count} times and should have been present at least ${min} and at most ${max} times` + ); +} diff --git a/Week3/challenges/4-bank-account.js b/Week3/challenges/4-bank-account.js index 8f0f035..dacd959 100644 --- a/Week3/challenges/4-bank-account.js +++ b/Week3/challenges/4-bank-account.js @@ -1,24 +1,6 @@ -/** - * It is time to write some bigger code! You have a bankAccount that is modeled as given. - * - * Finish the two functions that will donate money (donateMoney) and pay rent (payRent). - * If you do not have enough funds, call the onFail function given and don't change the bankAccount. - * If you do have the funds, update the bankAccount accordingly. - * - * TIP: have a look at the test code to get more information on what needs to happen - * TIP: a lot of the things the functions do are the same, you may want to create one or more other functions to not duplicate code - */ - const bankAccount = { - // The currentBalance is how much money you have in your bankAccount. currentBalance: 250, - // The transactions are a list of changes so that you can keep track. transactions: [ - /** - * The prevAmount is what your balance was before the transaction, - * the newAmount is what your balance was after the transaction - * and the reason is what the transaction was about - */ { prevAmount: 350, newAmount: 250, @@ -27,11 +9,31 @@ const bankAccount = { ], }; +// Common function to handle payments +const makePayment = (amount, reason, onSuccess, onFail) => { + if (bankAccount.currentBalance >= amount) { + const prevAmount = bankAccount.currentBalance; + const newAmount = prevAmount - amount; + + bankAccount.currentBalance = newAmount; + bankAccount.transactions.push({ + prevAmount, + newAmount, + reason, + }); + + onSuccess(); + } else { + onFail(); + } +}; + const donateMoney = (amount, onSuccess, onFail) => { - // TODO complete this function + makePayment(amount, "Donation", onSuccess, onFail); }; + const payRent = (amount, onSuccess, onFail) => { - // TODO complete this function + makePayment(amount, "Rent", onSuccess, onFail); }; /** @@ -60,34 +62,3 @@ console.log(bankAccount); donateMoney(100, onSuccessDutch, onFailDutch); console.log(bankAccount); - -/** -* The console should print out the following: -Payment successful! Thank you! -{ -currentBalance: 150, -transactions: [ - { prevAmount: 350, newAmount: 250, reason: 'Donation' }, - { prevAmount: 250, newAmount: 150, reason: 'Donation' } -] -} -Payment successful! Thank you! -{ -currentBalance: 50, -transactions: [ - { prevAmount: 350, newAmount: 250, reason: 'Donation' }, - { prevAmount: 250, newAmount: 150, reason: 'Donation' }, - { prevAmount: 150, newAmount: 50, reason: 'Rent' } -] -} -U heeft niet voldoende saldo om deze betaling te doen. -{ -currentBalance: 50, -transactions: [ - { prevAmount: 350, newAmount: 250, reason: 'Donation' }, - { prevAmount: 250, newAmount: 150, reason: 'Donation' }, - { prevAmount: 150, newAmount: 50, reason: 'Rent' } -] -} -* -*/ diff --git a/Week3/prep-exercises/1-hyf-program/1-find-mentors.js b/Week3/prep-exercises/1-hyf-program/1-find-mentors.js index 72baa61..64b7f9b 100644 --- a/Week3/prep-exercises/1-hyf-program/1-find-mentors.js +++ b/Week3/prep-exercises/1-hyf-program/1-find-mentors.js @@ -1,26 +1,32 @@ -import { modules, students, mentors, classes } from "./hyf.js"; +// Simulated data from hyf.js +export const mentors = [ + { name: 'Stas', modules: ['html', 'javascript', 'using-apis'] }, + { name: 'Joe', modules: ['css', 'javascript', 'node'] }, + { name: 'Marc', modules: ['react', 'node', 'using-apis'] }, +]; + +// Your task functions /** - * Tjebbe would like help to get a list of possible mentors for a module. - * Fill in this function that finds all the mentors that can teach the given module. - * - * It should return an array of names. So something like: - * ['John', 'Mary'] + * Returns an array of mentor names who can teach the given module. */ const possibleMentorsForModule = (moduleName) => { - // TODO complete this function + return mentors + .filter((mentor) => mentor.modules.includes(moduleName)) + .map((mentor) => mentor.name); }; -// You can uncomment out this line to try your function -// console.log(possibleMentorsForModule('using-apis')); /** - * Tjebbe wants to make it even easier for himself. - * Fill in this function that chooses a random mentor to teach the given module. - * - * It should return a single name. + * Returns a single random mentor name who can teach the given module. */ const findMentorForModule = (moduleName) => { - // TODO complete this function + const possibleMentors = possibleMentorsForModule(moduleName); + if (possibleMentors.length === 0) return null; + + const randomIndex = Math.floor(Math.random() * possibleMentors.length); + return possibleMentors[randomIndex]; }; -// You can uncomment out this line to try your function -// console.log(findMentorForModule('javascript')); + +// Test examples +console.log(possibleMentorsForModule('using-apis')); // e.g. ['Stas', 'Marc'] +console.log(findMentorForModule('javascript')); // e.g. 'Stas' or 'Joe' diff --git a/Week3/prep-exercises/1-hyf-program/2-class-list.js b/Week3/prep-exercises/1-hyf-program/2-class-list.js index 44d2798..1efca60 100644 --- a/Week3/prep-exercises/1-hyf-program/2-class-list.js +++ b/Week3/prep-exercises/1-hyf-program/2-class-list.js @@ -1,36 +1,35 @@ import { modules, students, mentors, classes } from "./hyf.js"; -/** - * We would like to have a list of everyone that is currently participating in a class. - * This means the students, but also the mentors that are currently teaching the class. - * The students should be self explanatory, but to find the mentors you will need to follow these steps: - * - Check what the `currentModule` of the class is - * - Find the mentor(s) that are `nowTeaching` that module - * - * Should return the list of names and their roles. So something like: - * - * [{ name: 'John', role: 'student' }, { name: 'Mary', role: 'mentor' }] - */ const getPeopleOfClass = (className) => { - // TODO complete this function + const classInfo = classes.find((cls) => cls.name === className); + if (!classInfo) return []; + + const currentModule = classInfo.currentModule; + + // Get students of this class + const classStudents = students + .filter((student) => student.class === className) + .map((student) => ({ name: student.name, role: 'student' })); + + // Get mentors teaching this module + const classMentors = mentors + .filter((mentor) => mentor.nowTeaching.includes(currentModule)) + .map((mentor) => ({ name: mentor.name, role: 'mentor' })); + + return [...classStudents, ...classMentors]; }; -// You can uncomment out this line to try your function -// console.log(getPeopleOfClass('class34')); -/** - * We would like to have a complete overview of the current active classes. - * First find the active classes, then for each get the people of that class. - * - * Should return an object with the class names as properties. - * Each class name property contains an array identical to the return from `getPeopleFromClass`. So something like: - * - * { - * class34: [{ name: 'John', role: 'student' }, { name: 'Mary', role: 'mentor' }], - * class35: [{ name: 'Jane', role: 'student' }, { name: 'Steve', role: 'mentor' }] - * } - */ const getActiveClasses = () => { - // TODO complete this function + const activeClasses = classes.filter((cls) => cls.active); + + const result = {}; + for (const cls of activeClasses) { + result[cls.name] = getPeopleOfClass(cls.name); + } + + return result; }; -// You can uncomment out this line to try your function + +// Example usage +// console.log(getPeopleOfClass('class34')); // console.log(getActiveClasses()); diff --git a/Week4/prep-exercises/1-wallet/ex1-closure-example.js b/Week4/prep-exercises/1-wallet/ex1-closure-example.js index e98b056..77437be 100644 --- a/Week4/prep-exercises/1-wallet/ex1-closure-example.js +++ b/Week4/prep-exercises/1-wallet/ex1-closure-example.js @@ -1,10 +1,8 @@ import eurosFormatter from "./euroFormatter.js"; /** - * This is the closure way of doing things and we have already completed it for you so you don't need to do anything. - * We leave it here as an example of how your other implementations should work! + * Wallet implementation using closures. */ - function createWallet(name, cash = 0) { let dailyAllowance = 40; let dayTotalWithdrawals = 0; @@ -15,12 +13,12 @@ function createWallet(name, cash = 0) { function withdraw(amount) { if (cash - amount < 0) { - console.log(`Insufficient funds!`); + console.log(`${name} has insufficient funds!`); return 0; } if (dayTotalWithdrawals + amount > dailyAllowance) { - console.log(`Insufficient remaining daily allowance!`); + console.log(`${name} has exceeded the daily allowance!`); return 0; } @@ -31,19 +29,17 @@ function createWallet(name, cash = 0) { function transferInto(wallet, amount) { console.log( - `Transferring ${eurosFormatter.format( - amount - )} from ${name} to ${wallet.getName()}` + `Transferring ${eurosFormatter.format(amount)} from ${name} to ${wallet.getName()}` ); const withdrawnAmount = withdraw(amount); - wallet.deposit(withdrawnAmount); + if (withdrawnAmount > 0) { + wallet.deposit(withdrawnAmount); + } } function setDailyAllowance(newAllowance) { dailyAllowance = newAllowance; - console.log( - `Daily allowance set to: ${eurosFormatter.format(newAllowance)}` - ); + console.log(`${name}'s daily allowance set to ${eurosFormatter.format(newAllowance)}`); } function resetDailyAllowance() { @@ -72,18 +68,17 @@ function main() { const walletJoe = createWallet("Joe", 10); const walletJane = createWallet("Jane", 20); - walletJack.transferInto(walletJoe, 50); - walletJack.setDailyAllowance(80); - walletJack.transferInto(walletJoe, 50); - - walletJane.transferInto(walletJoe, 25); + walletJack.transferInto(walletJoe, 50); // allowed: 50/40 daily limit fails + walletJack.setDailyAllowance(80); // increase limit + walletJack.transferInto(walletJoe, 50); // now works - walletJane.deposit(20); - walletJane.transferInto(walletJoe, 25); + walletJane.transferInto(walletJoe, 25); // insufficient funds + walletJane.deposit(20); // +20 + walletJane.transferInto(walletJoe, 25); // should now work - walletJack.reportBalance(); - walletJoe.reportBalance(); - walletJane.reportBalance(); + walletJack.reportBalance(); // Expect: 50 + walletJoe.reportBalance(); // Expect: 85 + walletJane.reportBalance(); // Expect: -5 } main(); diff --git a/Week4/prep-exercises/1-wallet/ex2-classes.js b/Week4/prep-exercises/1-wallet/ex2-classes.js index f016137..533a125 100644 --- a/Week4/prep-exercises/1-wallet/ex2-classes.js +++ b/Week4/prep-exercises/1-wallet/ex2-classes.js @@ -3,10 +3,14 @@ import eurosFormatter from './euroFormatter.js'; class Wallet { #name; #cash; + #dailyAllowance; + #dayTotalWithdrawals; constructor(name, cash) { this.#name = name; this.#cash = cash; + this.#dailyAllowance = 40; + this.#dayTotalWithdrawals = 0; } get name() { @@ -18,29 +22,42 @@ class Wallet { } withdraw(amount) { - if (this.#cash - amount < 0) { - console.log(`Insufficient funds!`); + if (this.#cash < amount) { + console.log(`${this.#name} has insufficient funds!`); + return 0; + } + + if (this.#dayTotalWithdrawals + amount > this.#dailyAllowance) { + console.log(`${this.#name} has exceeded the daily allowance!`); return 0; } this.#cash -= amount; + this.#dayTotalWithdrawals += amount; return amount; } transferInto(wallet, amount) { console.log( - `Transferring ${eurosFormatter.format(amount)} from ${this.name} to ${ - wallet.name - }` + `Transferring ${eurosFormatter.format(amount)} from ${this.#name} to ${wallet.name}` ); const withdrawnAmount = this.withdraw(amount); - wallet.deposit(withdrawnAmount); + if (withdrawnAmount > 0) { + wallet.deposit(withdrawnAmount); + } + } + + setDailyAllowance(amount) { + this.#dailyAllowance = amount; + console.log(`${this.#name}'s daily allowance set to ${eurosFormatter.format(amount)}`); + } + + resetDailyAllowance() { + this.#dayTotalWithdrawals = 0; } reportBalance() { - console.log( - `Name: ${this.name}, balance: ${eurosFormatter.format(this.#cash)}` - ); + console.log(`Name: ${this.#name}, balance: ${eurosFormatter.format(this.#cash)}`); } } @@ -49,11 +66,13 @@ function main() { const walletJoe = new Wallet('Joe', 10); const walletJane = new Wallet('Jane', 20); - walletJack.transferInto(walletJoe, 50); - walletJane.transferInto(walletJoe, 25); + walletJack.transferInto(walletJoe, 50); // Exceeds default allowance (40), should fail + walletJack.setDailyAllowance(80); // Increases allowance + walletJack.transferInto(walletJoe, 50); // Now allowed + walletJane.transferInto(walletJoe, 25); // Insufficient funds walletJane.deposit(20); - walletJane.transferInto(walletJoe, 25); + walletJane.transferInto(walletJoe, 25); // Now allowed walletJack.reportBalance(); walletJoe.reportBalance(); diff --git a/Week4/prep-exercises/1-wallet/ex3-object.js b/Week4/prep-exercises/1-wallet/ex3-object.js index e94faac..76da5fa 100644 --- a/Week4/prep-exercises/1-wallet/ex3-object.js +++ b/Week4/prep-exercises/1-wallet/ex3-object.js @@ -1,41 +1,59 @@ import eurosFormatter from './euroFormatter.js'; function createWallet(name, cash = 0) { + let dailyAllowance = 40; + let dayTotalWithdrawals = 0; + return { _name: name, _cash: cash, - deposit: function (amount) { + deposit(amount) { this._cash += amount; }, - withdraw: function (amount) { - if (this._cash - amount < 0) { - console.log(`Insufficient funds!`); + withdraw(amount) { + if (this._cash < amount) { + console.log(`${this._name} has insufficient funds!`); + return 0; + } + + if (dayTotalWithdrawals + amount > dailyAllowance) { + console.log(`${this._name} has exceeded the daily allowance!`); return 0; } this._cash -= amount; + dayTotalWithdrawals += amount; return amount; }, - transferInto: function (wallet, amount) { + transferInto(wallet, amount) { console.log( - `Transferring ${eurosFormatter.format(amount)} from ${ - this._name - } to ${wallet.getName()}` + `Transferring ${eurosFormatter.format(amount)} from ${this._name} to ${wallet.getName()}` ); const withdrawnAmount = this.withdraw(amount); - wallet.deposit(withdrawnAmount); + if (withdrawnAmount > 0) { + wallet.deposit(withdrawnAmount); + } }, - reportBalance: function () { + reportBalance() { console.log( `Name: ${this._name}, balance: ${eurosFormatter.format(this._cash)}` ); }, - getName: function () { + setDailyAllowance(amount) { + dailyAllowance = amount; + console.log(`${this._name}'s daily allowance set to ${eurosFormatter.format(amount)}`); + }, + + resetDailyAllowance() { + dayTotalWithdrawals = 0; + }, + + getName() { return this._name; }, }; @@ -46,11 +64,13 @@ function main() { const walletJoe = createWallet('Joe', 10); const walletJane = createWallet('Jane', 20); - walletJack.transferInto(walletJoe, 50); - walletJane.transferInto(walletJoe, 25); + walletJack.transferInto(walletJoe, 50); // Exceeds default daily allowance (40) + walletJack.setDailyAllowance(80); + walletJack.transferInto(walletJoe, 50); // Now works - walletJane.deposit(20); - walletJane.transferInto(walletJoe, 25); + walletJane.transferInto(walletJoe, 25); // Fails due to insufficient funds + walletJane.deposit(20); // +20 + walletJane.transferInto(walletJoe, 25); // Now works walletJack.reportBalance(); walletJoe.reportBalance(); diff --git a/Week4/prep-exercises/1-wallet/ex4-object-shared-methods.js b/Week4/prep-exercises/1-wallet/ex4-object-shared-methods.js index bd4fd20..5bc258d 100644 --- a/Week4/prep-exercises/1-wallet/ex4-object-shared-methods.js +++ b/Week4/prep-exercises/1-wallet/ex4-object-shared-methods.js @@ -5,23 +5,29 @@ function deposit(amount) { } function withdraw(amount) { - if (this._cash - amount < 0) { - console.log(`Insufficient funds!`); + if (this._cash < amount) { + console.log(`${this._name} has insufficient funds!`); + return 0; + } + + if (this._dayTotalWithdrawals + amount > this._dailyAllowance) { + console.log(`${this._name} has exceeded the daily allowance!`); return 0; } this._cash -= amount; + this._dayTotalWithdrawals += amount; return amount; } function transferInto(wallet, amount) { console.log( - `Transferring ${eurosFormatter.format(amount)} from ${ - this._name - } to ${wallet.getName()}` + `Transferring ${eurosFormatter.format(amount)} from ${this._name} to ${wallet.getName()}` ); const withdrawnAmount = this.withdraw(amount); - wallet.deposit(withdrawnAmount); + if (withdrawnAmount > 0) { + wallet.deposit(withdrawnAmount); + } } function reportBalance() { @@ -34,15 +40,28 @@ function getName() { return this._name; } +function setDailyAllowance(amount) { + this._dailyAllowance = amount; + console.log(`${this._name}'s daily allowance set to ${eurosFormatter.format(amount)}`); +} + +function resetDailyAllowance() { + this._dayTotalWithdrawals = 0; +} + function createWallet(name, cash = 0) { return { _name: name, _cash: cash, + _dailyAllowance: 40, + _dayTotalWithdrawals: 0, deposit, withdraw, transferInto, reportBalance, getName, + setDailyAllowance, + resetDailyAllowance, }; } @@ -51,11 +70,13 @@ function main() { const walletJoe = createWallet('Joe', 10); const walletJane = createWallet('Jane', 20); - walletJack.transferInto(walletJoe, 50); - walletJane.transferInto(walletJoe, 25); + walletJack.transferInto(walletJoe, 50); // Fails: exceeds daily allowance + walletJack.setDailyAllowance(80); // Increases allowance + walletJack.transferInto(walletJoe, 50); // Works now + walletJane.transferInto(walletJoe, 25); // Fails: not enough cash walletJane.deposit(20); - walletJane.transferInto(walletJoe, 25); + walletJane.transferInto(walletJoe, 25); // Now works walletJack.reportBalance(); walletJoe.reportBalance(); diff --git a/Week4/prep-exercises/1-wallet/ex5-prototype.js b/Week4/prep-exercises/1-wallet/ex5-prototype.js index 7cba410..489f999 100644 --- a/Week4/prep-exercises/1-wallet/ex5-prototype.js +++ b/Week4/prep-exercises/1-wallet/ex5-prototype.js @@ -3,6 +3,8 @@ import eurosFormatter from './euroFormatter.js'; function Wallet(name, cash) { this._name = name; this._cash = cash; + this._dailyAllowance = 40; + this._dayTotalWithdrawals = 0; } Wallet.prototype.deposit = function (amount) { @@ -10,23 +12,38 @@ Wallet.prototype.deposit = function (amount) { }; Wallet.prototype.withdraw = function (amount) { - if (this._cash - amount < 0) { - console.log(`Insufficient funds!`); + if (this._cash < amount) { + console.log(`${this._name} has insufficient funds!`); + return 0; + } + + if (this._dayTotalWithdrawals + amount > this._dailyAllowance) { + console.log(`${this._name} has exceeded the daily allowance!`); return 0; } this._cash -= amount; + this._dayTotalWithdrawals += amount; return amount; }; Wallet.prototype.transferInto = function (wallet, amount) { console.log( - `Transferring ${eurosFormatter.format(amount)} from ${ - this._name - } to ${wallet.getName()}` + `Transferring ${eurosFormatter.format(amount)} from ${this._name} to ${wallet.getName()}` ); const withdrawnAmount = this.withdraw(amount); - wallet.deposit(withdrawnAmount); + if (withdrawnAmount > 0) { + wallet.deposit(withdrawnAmount); + } +}; + +Wallet.prototype.setDailyAllowance = function (amount) { + this._dailyAllowance = amount; + console.log(`${this._name}'s daily allowance set to ${eurosFormatter.format(amount)}`); +}; + +Wallet.prototype.resetDailyAllowance = function () { + this._dayTotalWithdrawals = 0; }; Wallet.prototype.reportBalance = function () { @@ -44,11 +61,13 @@ function main() { const walletJoe = new Wallet('Joe', 10); const walletJane = new Wallet('Jane', 20); - walletJack.transferInto(walletJoe, 50); - walletJane.transferInto(walletJoe, 25); + walletJack.transferInto(walletJoe, 50); // Fails: exceeds daily limit + walletJack.setDailyAllowance(80); + walletJack.transferInto(walletJoe, 50); // Now allowed + walletJane.transferInto(walletJoe, 25); // Fails: insufficient funds walletJane.deposit(20); - walletJane.transferInto(walletJoe, 25); + walletJane.transferInto(walletJoe, 25); // Now allowed walletJack.reportBalance(); walletJoe.reportBalance(); diff --git a/Week4/prep-exercises/2-game-of-life/Cell.js b/Week4/prep-exercises/2-game-of-life/Cell.js index cac08da..fff3381 100644 --- a/Week4/prep-exercises/2-game-of-life/Cell.js +++ b/Week4/prep-exercises/2-game-of-life/Cell.js @@ -7,17 +7,22 @@ */ export default class Cell { - static size; + static size = 10; // Default size if not overridden constructor(x, y) { this.x = x; this.y = y; this.alive = Math.random() > 0.5; this.nextAlive = false; + this.lifeTime = this.alive ? 1 : 0; // ✅ Track how long the cell has been alive } draw(context) { - // Draw this background + if (!Cell.size) { + throw new Error('Cell.size is not defined.'); + } + + // Draw cell background context.fillStyle = '#303030'; context.fillRect( this.x * Cell.size, @@ -27,8 +32,14 @@ export default class Cell { ); if (this.alive) { - // Draw living this inside background - context.fillStyle = `rgb(24, 215, 236)`; + // Set opacity based on lifeTime + let opacity = 0.25; + if (this.lifeTime === 2) opacity = 0.5; + else if (this.lifeTime === 3) opacity = 0.75; + else if (this.lifeTime >= 4) opacity = 1; + + // Draw inner part for living cell with rgba color + context.fillStyle = `rgba(24, 215, 236, ${opacity})`; context.fillRect( this.x * Cell.size + 1, this.y * Cell.size + 1, @@ -39,15 +50,22 @@ export default class Cell { } liveAndLetDie(aliveNeighbors) { - if (aliveNeighbors === 2) { - // Living cell remains living, dead cell remains dead - this.nextAlive = this.alive; - } else if (aliveNeighbors === 3) { - // Dead cell becomes living, living cell remains living - this.nextAlive = true; + if (this.alive) { + if (aliveNeighbors === 2 || aliveNeighbors === 3) { + this.nextAlive = true; + this.lifeTime += 1; // ✅ Survives, increment lifeTime + } else { + this.nextAlive = false; + this.lifeTime = 0; // ✅ Dies, reset lifeTime + } } else { - // Living cell dies, dead cell remains dead - this.nextAlive = false; + if (aliveNeighbors === 3) { + this.nextAlive = true; + this.lifeTime = 1; // ✅ Reborn, start at 1 + } else { + this.nextAlive = false; + // ✅ Remains dead, no change to lifeTime needed (assumed 0) + } } } diff --git a/Week4/prep-exercises/2-game-of-life/Game.js b/Week4/prep-exercises/2-game-of-life/Game.js index 697d15e..93434e9 100644 --- a/Week4/prep-exercises/2-game-of-life/Game.js +++ b/Week4/prep-exercises/2-game-of-life/Game.js @@ -1,4 +1,5 @@ import Grid from './Grid.js'; +import Cell from './Cell.js'; // Required to set Cell.size const CELL_SIZE = 10; const NUM_COLUMNS = 75; @@ -6,17 +7,20 @@ const NUM_ROWS = 40; export default class Game { constructor(canvas) { - // Resize the canvas to accommodate the desired number of cell rows and - // columns + // Resize the canvas to accommodate the desired number of cell rows and columns canvas.height = NUM_ROWS * CELL_SIZE; canvas.width = NUM_COLUMNS * CELL_SIZE; - // Obtain a context that is needed to draw on the canvas + // Obtain a 2D context to draw on the canvas this.context = canvas.getContext('2d'); - if (!(this.context instanceof CanvasRenderingContext2D)) { - throw new Error('Context not found'); + if (!this.context || !(this.context instanceof CanvasRenderingContext2D)) { + throw new Error('Failed to get 2D drawing context from canvas.'); } + // Set Cell size globally for use in rendering + Cell.size = CELL_SIZE; + + // Initialize the grid this.grid = new Grid(NUM_ROWS, NUM_COLUMNS, CELL_SIZE); } diff --git a/Week4/prep-exercises/2-game-of-life/Grid.js b/Week4/prep-exercises/2-game-of-life/Grid.js index 3157730..399652b 100644 --- a/Week4/prep-exercises/2-game-of-life/Grid.js +++ b/Week4/prep-exercises/2-game-of-life/Grid.js @@ -4,24 +4,28 @@ export default class Grid { rows = []; constructor(numRows, numColumns, cellSize) { + if (!cellSize || typeof cellSize !== 'number' || cellSize <= 0) { + throw new Error('Invalid cell size provided to Grid.'); + } + this.numRows = numRows; this.numColumns = numColumns; + // Set static size for Cell class Cell.size = cellSize; - // Create the grid as a two-dimensional array (i.e. an array of arrays) + // Create the grid as a two-dimensional array (array of arrays) for (let y = 0; y < numRows; y++) { const row = []; for (let x = 0; x < numColumns; x++) { - const cell = new Cell(x, y); - row.push(cell); + row.push(new Cell(x, y)); } this.rows.push(row); } } isAlive(x, y) { - // Out-of-border cells are presumed dead + // Out-of-bounds cells are considered dead if (x < 0 || x >= this.numColumns || y < 0 || y >= this.numRows) { return 0; } diff --git a/Week4/prep-exercises/2-game-of-life/app.js b/Week4/prep-exercises/2-game-of-life/app.js index db55856..ba031aa 100644 --- a/Week4/prep-exercises/2-game-of-life/app.js +++ b/Week4/prep-exercises/2-game-of-life/app.js @@ -2,8 +2,10 @@ import Game from './Game.js'; function main() { const canvas = document.getElementById('canvas'); - if (!(canvas instanceof HTMLCanvasElement)) { - throw new Error('Canvas element not found'); + + // Check if the canvas element exists and is actually a + if (!canvas || !(canvas instanceof HTMLCanvasElement)) { + throw new Error('Canvas element not found or is not a valid '); } // Create the game "engine" @@ -13,4 +15,5 @@ function main() { game.start(); } +// Start the game when the window is fully loaded window.addEventListener('load', main);