DAY 05 · PRACTICE

5 Questions — Think Deeper 🧠

📦 Topics: Recursion · Sorting · Higher-Order Fns · Objects · DOM ⏱ Est: 2–3 hrs total 🎯 Difficulty: 2.5 / 5
01
Staircase Counter 🪜
RECURSION EASY ~25 min
📖 Scenario
You're climbing stairs and can take 1 or 2 steps at a time. How many different ways can you reach step N? For 3 steps: (1+1+1), (1+2), (2+1) — that's 3 ways. This is a classic recursion problem that secretly hides the Fibonacci pattern inside it. First, warm up with factorial, then solve the stairs problem.
🧠 Recursion = function that calls itself
Every recursive function needs TWO things:
1. Base case — when to STOP (e.g. n == 0 → return 1)
2. Recursive case — call itself with a SMALLER input
Without a base case → infinite loop → crash!
Starter Code
def factorial(n): pass # base case: n == 0 or n == 1 → return 1 # recursive: return n * factorial(n - 1) def count_ways(n): pass # base case: n==0 → 1 way, n==1 → 1 way # recursive: ways(n-1) + ways(n-2) print(factorial(5)) print(factorial(0)) print(count_ways(1)) print(count_ways(3)) print(count_ways(5))
Your Tasks
  • Fill factorial(n) — base case: if n is 0 or 1, return 1. Recursive case: return n * factorial(n-1)
  • Trace it mentally: factorial(4) → 4 × factorial(3) → 4 × 3 × factorial(2) → ... what's the final answer?
  • Fill count_ways(n) — base cases: n==0 or n==1 → return 1. Recursive: return count_ways(n-1) + count_ways(n-2) Think: to reach step N, you came from step N-1 (took 1 step) OR step N-2 (took 2 steps)
  • Print the number of ways to climb 1, 3, and 5 stairs
Expected Output
120
1
1
3
8
💡 One Hint
For count_ways, try n=3 by hand: ways(3) = ways(2) + ways(1) = (ways(1)+ways(0)) + 1 = (1+1) + 1 = 3. The pattern is identical to Fibonacci — each answer is the sum of the previous two!
02
Movie Leaderboard 🎬
SORTING LAMBDA EASY ~20 min
📖 Scenario
IMDb and Letterboxd let you sort movies by rating, year, or title. You'll build that sorting engine — sort a list of movie dictionaries in multiple different ways using Python's sorted() and lambda functions as the sort key. Lambda is just a tiny throwaway function written in one line.
Starter Code
movies = [ {"title": "Interstellar", "year": 2014, "rating": 8.7}, {"title": "Inception", "year": 2010, "rating": 8.8}, {"title": "The Dark Knight", "year": 2008, "rating": 9.0}, {"title": "Parasite", "year": 2019, "rating": 8.5}, {"title": "Dune", "year": 2021, "rating": 8.0}, ] # Write your code below
Your Tasks
  • Sort movies by rating — highest first and print titles + ratings sorted(movies, key=lambda m: m["rating"], reverse=True)
  • Sort movies by year — oldest first and print titles + years
  • Sort movies by title alphabetically (A → Z) and print just the titles
  • Filter and print only movies with rating above 8.5 Use a list comprehension with an if condition
Expected Output
By rating: The Dark Knight(9.0) Inception(8.8) Interstellar(8.7) Parasite(8.5) Dune(8.0)
By year: The Dark Knight(2008) Inception(2010) Interstellar(2014) Parasite(2019) Dune(2021)
Alphabetical: Dune, Inception, Interstellar, Parasite, The Dark Knight
Rating > 8.5: The Dark Knight, Inception, Interstellar
💡 One Hint
lambda m: m["rating"] is the same as writing def key(m): return m["rating"] — just shorter. reverse=True flips the order from low→high to high→low. For Task ④: [m["title"] for m in movies if m["rating"] > 8.5]
03
Shopping Cart Calculator 🛒
MAP FILTER LAMBDA EASY ~20 min
📖 Scenario
Amazon applies discounts, filters out-of-stock items, and calculates totals all in one pipeline. You'll use map() — which applies a function to every item — and filter() — which keeps only items that pass a condition. These are called higher-order functions because they take other functions as arguments.
Starter Code
cart = [ {"item": "Laptop", "price": 80000, "in_stock": True}, {"item": "Mouse", "price": 1200, "in_stock": True}, {"item": "Keyboard", "price": 3500, "in_stock": False}, {"item": "Monitor", "price": 25000, "in_stock": True}, {"item": "Webcam", "price": 4500, "in_stock": False}, ] # Write your code below
Your Tasks
  • Use filter() to get only items that are in stock filter(lambda p: p["in_stock"], cart) — wrap in list() to see the result
  • Use map() to apply a 10% discount to all in-stock prices map(lambda p: p["price"] * 0.9, in_stock_items)
  • Calculate and print the total bill after discount Use sum() on the discounted prices list
  • Print the most expensive in-stock item name and its discounted price
Expected Output
In-stock items: Laptop, Mouse, Monitor
Discounted prices: [72000.0, 1080.0, 22500.0]
Total bill: ₹95580.0
Most expensive: Laptop at ₹72000.0
💡 One Hint
filter() and map() return lazy iterators — wrap them in list() to get a real list you can index or loop over. For Task ④, use max(in_stock, key=lambda p: p["price"]) on the original filtered list (before discount), then show the discounted price.
04
Build Your Own Sorter 🔃
BUBBLE SORT ALGORITHMS MEDIUM ~25 min
📖 Scenario
Python's sorted() is great but how does sorting actually work? Bubble Sort is the simplest algorithm to understand: compare neighbouring elements, swap if the left one is bigger, and repeat. After each full pass, the largest unsorted element "bubbles up" to the end — like air bubbles rising in water.
🧠 How Bubble Sort works
Pass 1: [64 34 25 12] → swap → [34 64 25 12] → swap → [34 25 64 12] → swap → [34 25 12 | 64]
64 is now in the right place. Repeat for the rest.
Starter Code
def bubble_sort(arr): n = len(arr) for i in range(n): for j in range(0, n - i - 1): # n-i-1: no need to check sorted end pass # TODO: compare arr[j] and arr[j+1], swap if needed return arr nums = [64, 34, 25, 12, 22, 11, 90] scores = [45, 92, 38, 71, 85] print(bubble_sort(nums)) print(bubble_sort(scores))
Your Tasks
  • Fill in the swap logic: if arr[j] > arr[j+1], swap them Python swap: arr[j], arr[j+1] = arr[j+1], arr[j] — no temp variable needed!
  • Test it on both nums and scores — verify the output is sorted
  • Add a swap counter — count how many swaps were made and print it Create swap_count = 0 before the loops, add 1 each time you swap
  • Try it on an already sorted list like [1, 2, 3, 4, 5] — how many swaps does it make?
Expected Output
[11, 12, 22, 25, 34, 64, 90]
[38, 45, 71, 85, 92]
Swaps for nums: 11
Swaps for [1,2,3,4,5]: 0
💡 One Hint
The inner loop goes up to n - i - 1 because after each outer pass, the last i elements are already sorted in place. No need to re-check them! This is what makes Bubble Sort slightly smarter than checking every pair every time.
05
Mini Library System 📚
OOP LIST OF OBJECTS MEDIUM ~30 min
📖 Scenario
A library tracks books — who borrowed them, whether they're available, and can search by title or author. You'll build a Book class and a Library class that holds a list of books. This is how real software is structured — one class manages data (Book), another class manages a collection of them (Library).
Starter Code
class Book: def __init__(self, title, author, year): pass # store title, author, year AND set is_borrowed = False def borrow(self): pass # if available → mark as borrowed, else print "Already borrowed!" def return_book(self): pass # mark as available again def __str__(self): pass # return a nice string like: "Dune (Frank Herbert, 1965) [Available]" class Library: def __init__(self): self.books = [] def add_book(self, book): pass # append to self.books def search(self, keyword): pass # return books where keyword appears in title OR author (case-insensitive) def available_books(self): pass # return list of books that are NOT borrowed
Your Tasks
  • Fill the Book class — constructor, borrow(), return_book(), and __str__ (which controls what print(book) shows)
  • Fill Library.add_book() and Library.search(keyword) Search hint: keyword.lower() in book.title.lower() or keyword.lower() in book.author.lower()
  • Create a library, add 3 books, borrow one, then print all available books
  • Try borrowing the same book twice — the second attempt should print "Already borrowed!"
Expected Output
Dune (Frank Herbert, 1965) [Available]
1984 (George Orwell, 1949) [Available]
Borrowed: Dune
Already borrowed!
Available: 1984, The Alchemist
Search 'orwell': 1984 (George Orwell, 1949) [Available]
💡 One Hint
__str__ is a special method — when you do print(book), Python automatically calls it. Inside it, use an f-string like: f"{self.title} ({self.author}, {self.year}) [{'Borrowed' if self.is_borrowed else 'Available'}]"
01
Staircase Counter 🪜
RECURSION EASY ~25 min
📖 Scenario
You're climbing stairs and can take 1 or 2 steps at a time. How many different ways can you reach step N? For 3 steps: (1+1+1), (1+2), (2+1) — that's 3 ways. Warm up with factorial first to get comfortable with recursive methods in Java, then solve the stairs problem.
🧠 Recursion in Java
Every recursive method needs TWO things:
1. Base case — an if statement that returns a value directly (no recursion)
2. Recursive case — calls itself with a SMALLER input
Without a base case → StackOverflowError!
Starter Code
public class Recursion { static int factorial(int n) { // base case: if n == 0 or n == 1, return 1 // recursive: return n * factorial(n - 1) return 0; } static int countWays(int n) { // base case: n==0 or n==1 → return 1 // recursive: countWays(n-1) + countWays(n-2) return 0; } public static void main(String[] args) { System.out.println(factorial(5)); System.out.println(factorial(0)); System.out.println(countWays(1)); System.out.println(countWays(3)); System.out.println(countWays(5)); } }
Your Tasks
  • Fill factorial(n) — base: if (n <= 1) return 1; recursive: return n * factorial(n-1);
  • Trace manually: what does factorial(4) evaluate to step-by-step?
  • Fill countWays(n) — base: n==0 or n==1 → return 1. Recursive: return the sum of two calls
  • Print ways for 1, 3, and 5 stairs — verify: 1 → 1, 3 → 3, 5 → 8
Expected Output
120
1
1
3
8
💡 One Hint
In Java, combine two base cases cleanly: if (n <= 1) return 1; — this handles both n==0 and n==1 with one line. Then: return countWays(n-1) + countWays(n-2);
02
Movie Leaderboard 🎬
SORTING COMPARATOR EASY ~20 min
📖 Scenario
IMDb sorts movies by rating, year, or title. In Java, you sort using Comparator — a rule that tells Java how to compare two objects. You'll use lambda expressions (Java 8+) to write these rules in one clean line instead of a whole class.
Starter Code
import java.util.*; public class MovieSort { public static void main(String[] args) { // Each movie: {title, year, rating} List<String[]> movies = new ArrayList<>(); movies.add(new String[]{"Interstellar", "2014", "8.7"}); movies.add(new String[]{"Inception", "2010", "8.8"}); movies.add(new String[]{"The Dark Knight", "2008", "9.0"}); movies.add(new String[]{"Parasite", "2019", "8.5"}); movies.add(new String[]{"Dune", "2021", "8.0"}); // Write your code below } }
Your Tasks
  • Sort by rating — highest first and print titles + ratings movies.sort((a, b) -> Double.compare(Double.parseDouble(b[2]), Double.parseDouble(a[2])))
  • Sort by year — oldest first and print titles + years Compare Integer.parseInt(a[1]) vs b[1]
  • Sort by title alphabetically and print just the titles Use a[0].compareTo(b[0])
  • Filter and print only movies with rating above 8.5 using a loop and if
Expected Output
By rating: The Dark Knight(9.0) Inception(8.8) Interstellar(8.7) Parasite(8.5) Dune(8.0)
By year: The Dark Knight(2008) Inception(2010) Interstellar(2014) Parasite(2019) Dune(2021)
Alphabetical: Dune, Inception, Interstellar, Parasite, The Dark Knight
Rating > 8.5: The Dark Knight, Inception, Interstellar
💡 One Hint
Java's lambda comparator (a, b) -> ... returns a negative number if a comes first, positive if b comes first, zero if equal. Double.compare(b, a) automatically gives highest-first order. a[0].compareTo(b[0]) gives alphabetical order for Strings.
03
Shopping Cart Calculator 🛒
STREAMS LAMBDA EASY ~20 min
📖 Scenario
Amazon applies discounts, filters out-of-stock items, and totals your cart. You'll do the same using a regular loop + ArrayList approach (no Streams needed). Filter available items, apply a discount, and calculate the total — solid practice for looping over a list of data.
Starter Code
import java.util.*; public class ShoppingCart { public static void main(String[] args) { // {item, price, inStock} — price as String for easy storage List<String[]> cart = new ArrayList<>(); cart.add(new String[]{"Laptop", "80000", "true"}); cart.add(new String[]{"Mouse", "1200", "true"}); cart.add(new String[]{"Keyboard", "3500", "false"}); cart.add(new String[]{"Monitor", "25000", "true"}); cart.add(new String[]{"Webcam", "4500", "false"}); // Write your code below } }
Your Tasks
  • Loop through cart and build an ArrayList of in-stock items only Check p[2].equals("true") to filter
  • Apply a 10% discount to each in-stock item — store discounted prices in a new list
  • Calculate and print the total bill after discount
  • Find and print the most expensive in-stock item name and its discounted price
Expected Output
In-stock items: Laptop, Mouse, Monitor
Discounted prices: [72000.0, 1080.0, 22500.0]
Total bill: ₹95580.0
Most expensive: Laptop at ₹72000.0
💡 One Hint
Use double discounted = Integer.parseInt(p[1]) * 0.9; for the discount. Track the max with a variable — same "update if bigger" pattern from Q1 of Day 1. For the total, add each discounted price to a running double total = 0;.
04
Build Your Own Sorter 🔃
BUBBLE SORT ALGORITHMS MEDIUM ~25 min
📖 Scenario
Java's Collections.sort() is great but how does sorting actually work underneath? Bubble Sort is the most visual algorithm: compare two neighbouring elements, swap if needed, and repeat. After every full pass, the largest unsorted element "bubbles up" to its final position — just like air bubbles rising in water.
🧠 How Bubble Sort works
Pass 1: [64 34 25 12] → swap → [34 64 25 12] → swap → [34 25 64 12] → swap → [34 25 12 | 64]
64 is now in the right place. Repeat for the rest.
Starter Code
public class BubbleSort { static void bubbleSort(int[] arr) { int n = arr.length; for (int i = 0; i < n; i++) { for (int j = 0; j < n - i - 1; j++) { // TODO: if arr[j] > arr[j+1], swap them // Java needs a temp variable to swap! } } } public static void main(String[] args) { int[] nums = {64, 34, 25, 12, 22, 11, 90}; int[] scores = {45, 92, 38, 71, 85}; bubbleSort(nums); bubbleSort(scores); System.out.println(Arrays.toString(nums)); System.out.println(Arrays.toString(scores)); } }
Your Tasks
  • Fill in the swap logic using a temp variable: int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp;
  • Test on both arrays — verify they print in ascending order
  • Add a swap counter — print how many swaps happened Add int swapCount = 0 before the loops; swapCount++ inside the if block
  • Test on {1, 2, 3, 4, 5} — how many swaps does it make?
Expected Output
[11, 12, 22, 25, 34, 64, 90]
[38, 45, 71, 85, 92]
Swaps for nums: 11
Swaps for [1,2,3,4,5]: 0
💡 One Hint
Unlike Python's elegant swap (a, b = b, a), Java needs a temp: int t = arr[j]; arr[j] = arr[j+1]; arr[j+1] = t;. This is because Java is strict — you can't assign to two variables simultaneously.
05
Mini Library System 📚
OOP ARRAYLIST OF OBJECTS MEDIUM ~30 min
📖 Scenario
A library tracks books — who borrowed them and whether they're available. Build a Book class and a Library class that stores an ArrayList<Book>. This is the standard Java pattern: one class models the data, another manages a collection of it — the same structure used in enterprise Java apps.
Starter Code
import java.util.*; class Book { String title, author; int year; boolean isBorrowed; Book(String title, String author, int year) { // TODO: set fields, isBorrowed = false } void borrow() { /* TODO */ } void returnBook() { /* TODO */ } public String toString() { // return "Dune (Frank Herbert, 1965) [Available]" return ""; } } class Library { ArrayList<Book> books = new ArrayList<>(); void addBook(Book b) { /* TODO */ } ArrayList<Book> search(String keyword) { // return books where keyword is in title OR author (case-insensitive) return new ArrayList<>(); } ArrayList<Book> availableBooks() { // return books where isBorrowed == false return new ArrayList<>(); } } public class Main { public static void main(String[] args) { // Create library, add books, test borrow/return/search } }
Your Tasks
  • Fill Book constructor, borrow(), returnBook(), and toString()
  • Fill Library.addBook(), search(), and availableBooks() Search: book.title.toLowerCase().contains(keyword.toLowerCase())
  • In main(): create a library, add 3 books, borrow one, print available books
  • Try borrowing the same book twice — verify the error message prints on the second attempt
Expected Output
Dune (Frank Herbert, 1965) [Available]
Borrowed: Dune
Already borrowed!
Available: 1984, The Alchemist
Search 'orwell': 1984 (George Orwell, 1949) [Available]
💡 One Hint
Java's toString() works like Python's __str__ — when you call System.out.println(book), Java automatically calls book.toString(). Use the ternary operator for the status: isBorrowed ? "Borrowed" : "Available"
01
Staircase Counter 🪜
RECURSION EASY ~25 min
📖 Scenario
Same staircase problem — but now in JavaScript! JS functions are first-class citizens meaning you can write them multiple ways: function name(){}, const name = () => {}, or even inline. Recursion works identically — the key concepts (base case, recursive case) are universal across all languages.
🌐 JavaScript Note
JS uses console.log() instead of print/println.
No type declarations — just let, const, or nothing.
Arrow function: const factorial = (n) => { ... }
Starter Code
function factorial(n) { // base case: if n <= 1, return 1 // recursive: return n * factorial(n - 1) } function countWays(n) { // base case: n <= 1 → return 1 // recursive: countWays(n-1) + countWays(n-2) } console.log(factorial(5)); console.log(factorial(0)); console.log(countWays(1)); console.log(countWays(3)); console.log(countWays(5));
Your Tasks
  • Fill factorial(n) — same logic as Python/Java but JS syntax
  • Fill countWays(n) — base: if (n <= 1) return 1; recursive: sum of two calls
  • Rewrite factorial as an arrow function: const factorial = (n) => { ... }
  • Rewrite it even shorter as a one-liner arrow function: const factorial = n => n <= 1 ? 1 : n * factorial(n-1); The ternary operator ? : replaces if/else in one line
Expected Output
120
1
1
3
8
💡 One Hint
In JavaScript, undefined is returned if your function has no return statement. Make sure BOTH the base case and the recursive case have explicit return. A common mistake: if (n <= 1) { 1; } — missing return!
02
Movie Leaderboard 🎬
SORT ARROW FN FILTER EASY ~20 min
📖 Scenario
JavaScript arrays have built-in .sort(), .filter(), and .map() — and they all take arrow functions as arguments. This is the most natural and common way to work with data in JS. Almost every real web app — Netflix, Spotify, IMDb — does exactly this kind of data manipulation.
Starter Code
const movies = [ { title: "Interstellar", year: 2014, rating: 8.7 }, { title: "Inception", year: 2010, rating: 8.8 }, { title: "The Dark Knight", year: 2008, rating: 9.0 }, { title: "Parasite", year: 2019, rating: 8.5 }, { title: "Dune", year: 2021, rating: 8.0 }, ]; // Write your code below
Your Tasks
  • Sort by rating highest first and log each title + rating [...movies].sort((a, b) => b.rating - a.rating) — the spread [...] makes a copy so original isn't mutated
  • Sort by year oldest firsta.year - b.year
  • Sort alphabetically by titlea.title.localeCompare(b.title)
  • Use .filter() to get movies with rating > 8.5, then .map() to extract just their titles Chain them: movies.filter(...).map(m => m.title)
Expected Output
By rating: The Dark Knight(9) Inception(8.8) Interstellar(8.7) Parasite(8.5) Dune(8)
By year: The Dark Knight(2008) Inception(2010) Interstellar(2014) Parasite(2019) Dune(2021)
Alphabetical: ['Dune','Inception','Interstellar','Parasite','The Dark Knight']
Rating > 8.5: ['The Dark Knight', 'Inception', 'Interstellar']
💡 One Hint
JS's .sort() mutates the original array — always copy first with the spread operator: [...movies].sort(...). Subtracting numbers in the comparator (b.rating - a.rating) is the JS idiom for numeric sort — positive means b comes first, negative means a comes first.
03
Shopping Cart Calculator 🛒
MAP FILTER REDUCE EASY ~20 min
📖 Scenario
JavaScript's array methods — .filter(), .map(), .reduce() — are the backbone of frontend data processing. You'll use all three together in a method chain: filter out-of-stock items, map prices with a discount, then reduce to a total. This is exactly how modern React and Vue apps process data.
🌐 New: .reduce()
array.reduce((total, item) => total + item, 0)
Starts at 0, adds each item to running total. The 0 is the starting value.
It's like a built-in loop that accumulates one result.
Starter Code
const cart = [ { item: "Laptop", price: 80000, inStock: true }, { item: "Mouse", price: 1200, inStock: true }, { item: "Keyboard", price: 3500, inStock: false }, { item: "Monitor", price: 25000, inStock: true }, { item: "Webcam", price: 4500, inStock: false }, ]; // Write your code below
Your Tasks
  • Use .filter() to keep only in-stock items, log their names
  • Use .map() on in-stock items to apply a 10% discount — return a new object with updated price p => ({ ...p, price: p.price * 0.9 }) — the spread ...p copies all properties
  • Use .reduce() on discounted items to get the total bill
  • Find the most expensive discounted item using .reduce() (max, item) => item.price > max.price ? item : max
Expected Output
In-stock: Laptop, Mouse, Monitor
Discounted: Laptop(72000) Mouse(1080) Monitor(22500)
Total: ₹95580
Most expensive: Laptop at ₹72000
💡 One Hint
Chain all steps: const discounted = cart.filter(p => p.inStock).map(p => ({...p, price: p.price * 0.9})); — then use .reduce() on discounted. The ({...p, price: ...}) syntax creates a NEW object with all old properties plus an updated price — original cart is untouched.
04
Live Todo List 📝
DOM EVENTS HTML+JS MEDIUM ~30 min
📖 Scenario
JavaScript's superpower over Python and Java is that it runs inside the browser and can change what's on screen in real time. The DOM (Document Object Model) is the live tree of everything on your webpage. document.getElementById() grabs an element, .innerHTML changes its content. This is how Notion, Trello, and every interactive website works.
🌐 DOM Basics
document.getElementById("myId") → grab an element
element.innerHTML += "<li>text</li>" → add HTML inside it
button.addEventListener("click", fn) → run fn when button clicked
input.value → get what the user typed
Starter Code (paste into an HTML file)
<!-- HTML part --> <input id="taskInput" placeholder="Enter a task..." /> <button id="addBtn">Add Task</button> <ul id="taskList"></ul> <p id="counter">Tasks: 0</p> <!-- JS part --> <script> let tasks = []; function addTask() { // TODO: get value from input, add to tasks array, re-render } function renderTasks() { // TODO: build HTML string from tasks array, set taskList.innerHTML // TODO: update counter text } document.getElementById("addBtn") .addEventListener("click", addTask); </script>
Your Tasks
  • In addTask(): get the input value, push it to the tasks array, clear the input, call renderTasks() Guard: if the input is empty (after .trim()), do nothing
  • In renderTasks(): loop through tasks, build a string of <li> elements, set it as taskList.innerHTML
  • Update the counter: document.getElementById("counter").textContent = "Tasks: " + tasks.length
  • Add a delete button inside each <li> — clicking it removes that task from the array and re-renders Use tasks.splice(index, 1) to remove by index, then call renderTasks()
Expected Behaviour
Type a task → click Add → appears in the list below
Counter updates: "Tasks: 1", "Tasks: 2", ...
Empty input → nothing happens (no blank tasks)
Click delete on any task → it disappears, counter updates
💡 One Hint
For the delete button, generate HTML like: `<li>${task} <button onclick="deleteTask(${i})">✕</button></li>` and define function deleteTask(i) { tasks.splice(i, 1); renderTasks(); }. Template literals (backticks) let you embed variables with ${}.
05
Mini Library System 📚
CLASSES OBJECTS MEDIUM ~30 min
📖 Scenario
JavaScript has had classes since ES6 (2015) — they look almost identical to Java and Python classes. The syntax is a clean mix: class Name {} like Java, constructor() instead of __init__, and this like Java. JS classes are the backbone of every modern framework — React components are classes under the hood.
Starter Code
class Book { constructor(title, author, year) { // TODO: set this.title, this.author, this.year, this.isBorrowed = false } borrow() { /* TODO */ } returnBook() { /* TODO */ } toString() { // return "Dune (Frank Herbert, 1965) [Available]" return ""; } } class Library { constructor() { this.books = []; } addBook(book) { /* TODO */ } search(keyword) { // return books where keyword is in title OR author } availableBooks() { // return books that are NOT borrowed } } // Test it const lib = new Library();
Your Tasks
  • Fill the Book class — constructor, borrow(), returnBook(), toString()
  • Fill LibraryaddBook(), search(keyword) using .filter(), availableBooks() using .filter() search: this.books.filter(b => b.title.toLowerCase().includes(keyword.toLowerCase()) || ...)
  • Create a library, add 3 books, borrow one, log all available books
  • Try borrowing the same book twice — verify "Already borrowed!" logs on second attempt
Expected Output
Dune (Frank Herbert, 1965) [Available]
Borrowed: Dune
Already borrowed!
Available: 1984, The Alchemist
Search 'orwell': 1984 (George Orwell, 1949) [Available]
💡 One Hint
JS's toString() is called automatically by console.log(book) ONLY if you call it explicitly: console.log(book.toString()). Otherwise console.log shows the object structure. Use template literals for clean output: `${this.title} (${this.author}, ${this.year}) [${this.isBorrowed ? 'Borrowed' : 'Available'}]`