{
  "version": "1.0.0",
  "total_exercises": 450,
  "topics": [
    {
      "id": "variables",
      "title": "Variables",
      "exercise_count": 50,
      "exercises": [
        {
          "id": "var_01",
          "title": "Basic Variable Assignment",
          "difficulty": 1,
          "description": "Create a variable named `name` and assign it your name as a string.",
          "hints": [
            "Use the syntax: variable_name = value",
            "String values must be enclosed in quotes (single or double)"
          ],
          "solution": "name = \"Alice\"",
          "starter_code": "# Create a variable called name\n",
          "test_code": "assert isinstance(name, str), 'name should be a string (text), got ' + str(type(name).__name__)\nassert len(name) > 0, \"name should not be empty\"",
          "concepts": [
            "assignment",
            "strings",
            "variable naming"
          ]
        },
        {
          "id": "var_02",
          "title": "Numeric Variable Assignment",
          "difficulty": 1,
          "description": "Create a variable named `age` and assign it the value 25.",
          "hints": [
            "Numeric values (integers) don't need quotes",
            "The syntax is the same: variable_name = value"
          ],
          "solution": "age = 25",
          "starter_code": "# Create a variable called age\n",
          "test_code": "assert age == 25, 'age should be 25, got ' + str(repr(age))",
          "concepts": [
            "assignment",
            "integers",
            "numeric variables"
          ]
        },
        {
          "id": "var_03",
          "title": "Float Variable Assignment",
          "difficulty": 1,
          "description": "Create a variable named `height` and assign it the value 5.9 (representing height in feet).",
          "hints": [
            "Floating-point numbers have a decimal point",
            "height = 5.9 will automatically create a float"
          ],
          "solution": "height = 5.9",
          "starter_code": "# Create a variable called height\n",
          "test_code": "assert height == 5.9, 'height should be 5.9, got ' + str(repr(height))",
          "concepts": [
            "assignment",
            "floats",
            "numeric variables"
          ]
        },
        {
          "id": "var_04",
          "title": "Boolean Variable Assignment",
          "difficulty": 1,
          "description": "Create a variable named `is_student` and assign it the boolean value True.",
          "hints": [
            "Boolean values are True or False (capital T and F)",
            "These represent true/false conditions"
          ],
          "solution": "is_student = True",
          "starter_code": "# Create a variable called is_student\n",
          "test_code": "assert is_student == True, 'is_student should be True, got ' + str(repr(is_student))",
          "concepts": [
            "assignment",
            "booleans",
            "logic"
          ]
        },
        {
          "id": "var_05",
          "title": "Multiple Variable Assignment",
          "difficulty": 1,
          "description": "Assign the values 10, 20, and 30 to three variables: `x`, `y`, and `z` using a single line of code.",
          "hints": [
            "You can assign multiple variables at once: a, b, c = 1, 2, 3",
            "The order matters: first value to first variable, etc."
          ],
          "solution": "x, y, z = 10, 20, 30",
          "starter_code": "# Assign 10, 20, 30 to x, y, z in one line\n",
          "test_code": "assert x == 10, 'x should be 10, got ' + str(repr(x))\nassert y == 20, 'y should be 20, got ' + str(repr(y))\nassert z == 30, 'z should be 30, got ' + str(repr(z))",
          "concepts": [
            "multiple assignment",
            "unpacking"
          ]
        },
        {
          "id": "var_06",
          "title": "Variable Swapping",
          "difficulty": 1,
          "description": "Swap the values of two variables `a` and `b` (a=5, b=10) so that a=10 and b=5.",
          "hints": [
            "Python allows you to swap without a temporary variable",
            "Use: a, b = b, a"
          ],
          "solution": "a, b = 5, 10\na, b = b, a",
          "starter_code": "a, b = 5, 10\n# Swap the values\n",
          "test_code": "assert a == 10, 'a should be 10, got ' + str(repr(a))\nassert b == 5, 'b should be 5, got ' + str(repr(b))",
          "concepts": [
            "swapping",
            "multiple assignment"
          ]
        },
        {
          "id": "var_07",
          "title": "Variable Naming Conventions",
          "difficulty": 1,
          "description": "Create variables following snake_case naming convention for a person's first name, last name, and email address.",
          "hints": [
            "snake_case uses lowercase letters and underscores (no spaces or hyphens)",
            "Examples: first_name, last_name, email_address"
          ],
          "solution": "first_name = \"John\"\nlast_name = \"Doe\"\nemail_address = \"john.doe@example.com\"",
          "starter_code": "# Create variables following snake_case convention\n",
          "test_code": "assert isinstance(first_name, str), 'first_name should be a string (text), got ' + str(type(first_name).__name__)\nassert len(first_name) > 0, \"first_name should not be empty\"\nassert isinstance(last_name, str), 'last_name should be a string (text), got ' + str(type(last_name).__name__)\nassert len(last_name) > 0, \"last_name should not be empty\"\nassert isinstance(email_address, str), 'email_address should be a string (text), got ' + str(type(email_address).__name__)\nassert len(email_address) > 0, \"email_address should not be empty\"",
          "concepts": [
            "naming conventions",
            "strings"
          ]
        },
        {
          "id": "var_08",
          "title": "Reassigning Variables",
          "difficulty": 1,
          "description": "Create a variable `count` with value 0, then reassign it to 10.",
          "hints": [
            "First assignment: count = 0",
            "Then reassign: count = 10"
          ],
          "solution": "count = 0\ncount = 10",
          "starter_code": "# Create count and reassign it\n",
          "test_code": "assert count == 10, 'count should be 10, got ' + str(repr(count))",
          "concepts": [
            "reassignment",
            "variable mutation"
          ]
        },
        {
          "id": "var_09",
          "title": "None Type Variable",
          "difficulty": 1,
          "description": "Create a variable named `result` and assign it None (representing no value).",
          "hints": [
            "None is a special value (not a string, not 0, not empty)",
            "result = None"
          ],
          "solution": "result = None",
          "starter_code": "# Create a variable with None value\n",
          "test_code": "pass  # Verify your code runs without errors",
          "concepts": [
            "None type",
            "null values"
          ]
        },
        {
          "id": "var_10",
          "title": "Constant Naming Convention",
          "difficulty": 1,
          "description": "Create a constant variable for the speed of light (299792458 m/s) using ALL_CAPS naming convention.",
          "hints": [
            "Constants are named in ALL_CAPS with underscores",
            "Example: SPEED_OF_LIGHT = 299792458"
          ],
          "solution": "SPEED_OF_LIGHT = 299792458",
          "starter_code": "# Create a constant for speed of light\n",
          "test_code": "assert SPEED_OF_LIGHT == 299792458, 'SPEED_OF_LIGHT should be 299792458, got ' + str(repr(SPEED_OF_LIGHT))",
          "concepts": [
            "constants",
            "naming conventions"
          ]
        },
        {
          "id": "var_11",
          "title": "String Concatenation",
          "difficulty": 2,
          "description": "Create two string variables `greeting` and `name`, then concatenate them with a space to create a full greeting.",
          "hints": [
            "Use the + operator to concatenate strings",
            "greeting + ' ' + name"
          ],
          "solution": "greeting = \"Hello\"\nname = \"Alice\"\nfull_greeting = greeting + ' ' + name",
          "starter_code": "greeting = \"Hello\"\nname = \"Alice\"\n# Concatenate them\n",
          "test_code": "assert isinstance(greeting, str), 'greeting should be a string (text), got ' + str(type(greeting).__name__)\nassert len(greeting) > 0, \"greeting should not be empty\"\nassert isinstance(name, str), 'name should be a string (text), got ' + str(type(name).__name__)\nassert len(name) > 0, \"name should not be empty\"\nassert isinstance(full_greeting, str), 'full_greeting should be a string (text), got ' + str(type(full_greeting).__name__)\nassert len(full_greeting) > 0, \"full_greeting should not be empty\"",
          "concepts": [
            "strings",
            "concatenation",
            "operators"
          ]
        },
        {
          "id": "var_12",
          "title": "Augmented Assignment (+=)",
          "difficulty": 2,
          "description": "Start with `total = 100`, then add 50 to it using the += operator.",
          "hints": [
            "total += 50 is shorthand for total = total + 50",
            "Augmented assignment operators work with other operators too (*=, -=, etc.)"
          ],
          "solution": "total = 100\ntotal += 50",
          "starter_code": "total = 100\n# Add 50 using +=\n",
          "test_code": "assert total == 150, 'total should be 150, got ' + str(repr(total))",
          "concepts": [
            "augmented assignment",
            "operators"
          ]
        },
        {
          "id": "var_13",
          "title": "F-String Formatting",
          "difficulty": 2,
          "description": "Create variables `name` and `age`, then use an f-string to print 'Name: [name], Age: [age]'.",
          "hints": [
            "F-strings use f\" \" syntax",
            "Inside f-strings, use {variable_name} to insert values"
          ],
          "solution": "name = \"Bob\"\nage = 30\nmessage = f\"Name: {name}, Age: {age}\"",
          "starter_code": "name = \"Bob\"\nage = 30\n# Use f-string to create message\n",
          "test_code": "assert isinstance(name, str), 'name should be a string (text), got ' + str(type(name).__name__)\nassert len(name) > 0, \"name should not be empty\"\nassert isinstance(age, (int, float)), 'age should be a number, got ' + str(type(age).__name__)\nassert isinstance(message, str), 'message should be a string (text), got ' + str(type(message).__name__)\nassert len(message) > 0, \"message should not be empty\"",
          "concepts": [
            "f-strings",
            "string formatting"
          ]
        },
        {
          "id": "var_14",
          "title": "Type Inference in Python",
          "difficulty": 2,
          "description": "Create three variables with different types (string, integer, float), then verify each type using the type() function.",
          "hints": [
            "Python automatically infers the type based on the value",
            "You can check types later: type(variable) returns <class 'type_name'>"
          ],
          "solution": "text = \"hello\"\nnum_int = 42\nnum_float = 3.14\ntype_text = type(text)\ntype_int = type(num_int)\ntype_float = type(num_float)",
          "starter_code": "text = \"hello\"\nnum_int = 42\nnum_float = 3.14\n# Check types\n",
          "test_code": "assert isinstance(text, str), 'text should be a string (text), got ' + str(type(text).__name__)\nassert len(text) > 0, \"text should not be empty\"\nassert isinstance(num_int, (int, float)), 'num_int should be a number, got ' + str(type(num_int).__name__)\nassert isinstance(num_float, (int, float)), 'num_float should be a number, got ' + str(type(num_float).__name__)\nassert 'type_text' in dir(), \"'type_text' is not defined\"\nassert callable(type_text), \"'type_text' should be a function\"\nassert 'type_int' in dir(), \"'type_int' is not defined\"\nassert callable(type_int), \"'type_int' should be a function\"\nassert 'type_float' in dir(), \"'type_float' is not defined\"\nassert callable(type_float), \"'type_float' should be a function\"",
          "concepts": [
            "type inference",
            "dynamic typing"
          ]
        },
        {
          "id": "var_15",
          "title": "Variable Reassignment with Calculation",
          "difficulty": 2,
          "description": "Create a variable `price = 100`, then reassign it by adding 25% tax to it.",
          "hints": [
            "25% of 100 is 25",
            "price = price + (price * 0.25) or price *= 1.25"
          ],
          "solution": "price = 100\nprice = price * 1.25",
          "starter_code": "price = 100\n# Add 25% tax\n",
          "test_code": "assert price == 125.0, 'price should be 125.0, got ' + str(repr(price))",
          "concepts": [
            "reassignment",
            "arithmetic",
            "percentages"
          ]
        },
        {
          "id": "var_16",
          "title": "Multi-line String Variables",
          "difficulty": 2,
          "description": "Create a variable `poem` containing a multi-line string (at least 3 lines).",
          "hints": [
            "Use triple quotes for multi-line strings: \"\"\" ... \"\"\"",
            "Or use \\n escape sequence for newlines"
          ],
          "solution": "poem = \"\"\"Line one\\nLine two\\nLine three\"\"\"",
          "starter_code": "# Create a multi-line string variable\n",
          "test_code": "assert isinstance(poem, str), 'poem should be a string (text), got ' + str(type(poem).__name__)\nassert len(poem) > 0, \"poem should not be empty\"",
          "concepts": [
            "strings",
            "multi-line strings",
            "escape sequences"
          ]
        },
        {
          "id": "var_17",
          "title": "Using Underscore as Throwaway Variable",
          "difficulty": 2,
          "description": "Unpack a tuple (5, 10) into `x` and `_` (throwaway variable), ignoring the second value.",
          "hints": [
            "Use _ when you don't care about a value",
            "x, _ = 5, 10"
          ],
          "solution": "x, _ = 5, 10",
          "starter_code": "# Unpack ignoring the second value\n",
          "test_code": "assert x == 5, 'x should be 5, got ' + str(repr(x))",
          "concepts": [
            "unpacking",
            "throwaway variables"
          ]
        },
        {
          "id": "var_18",
          "title": "Variable in Expression",
          "difficulty": 2,
          "description": "Create variables `base = 5` and `exponent = 3`, then create `result` = base^exponent (5 to the power of 3).",
          "hints": [
            "Use the ** operator for exponentiation",
            "result = base ** exponent"
          ],
          "solution": "base = 5\nexponent = 3\nresult = base ** exponent",
          "starter_code": "base = 5\nexponent = 3\n# Calculate base^exponent\n",
          "test_code": "assert base == 5, 'base should be 5, got ' + str(repr(base))\nassert exponent == 3, 'exponent should be 3, got ' + str(repr(exponent))\nassert result == 125, 'result should be 125, got ' + str(repr(result))",
          "concepts": [
            "exponentiation",
            "operators",
            "expressions"
          ]
        },
        {
          "id": "var_19",
          "title": "Real-World: Restaurant Bill",
          "difficulty": 2,
          "description": "Create variables for a restaurant bill: `subtotal = 50`, `tax_rate = 0.1`, `tip_pct = 0.15`, then calculate the final total including tax and tip.",
          "hints": [
            "Total = subtotal + tax + tip",
            "tax = subtotal * tax_rate; tip = subtotal * tip_pct"
          ],
          "solution": "subtotal = 50\ntax_rate = 0.1\ntip_pct = 0.15\ntax = subtotal * tax_rate\ntip = subtotal * tip_pct\ntotal = subtotal + tax + tip",
          "starter_code": "subtotal = 50\ntax_rate = 0.1\ntip_pct = 0.15\n# Calculate total\n",
          "test_code": "assert subtotal == 50, 'subtotal should be 50, got ' + str(repr(subtotal))\nassert tax_rate == 0.1, 'tax_rate should be 0.1, got ' + str(repr(tax_rate))\nassert tip_pct == 0.15, 'tip_pct should be 0.15, got ' + str(repr(tip_pct))\nassert tax == 5.0, 'tax should be 5.0, got ' + str(repr(tax))\nassert tip == 7.5, 'tip should be 7.5, got ' + str(repr(tip))\nassert total == 62.5, 'total should be 62.5, got ' + str(repr(total))",
          "concepts": [
            "arithmetic",
            "real-world scenarios",
            "financial calculations"
          ]
        },
        {
          "id": "var_20",
          "title": "Real-World: Temperature Conversion",
          "difficulty": 2,
          "description": "Create a variable `celsius = 25`, then calculate and store `fahrenheit` using the formula: F = (C × 9/5) + 32.",
          "hints": [
            "The formula is: fahrenheit = (celsius * 9/5) + 32",
            "25°C should be 77°F"
          ],
          "solution": "celsius = 25\nfahrenheit = (celsius * 9/5) + 32",
          "starter_code": "celsius = 25\n# Convert to Fahrenheit\n",
          "test_code": "assert celsius == 25, 'celsius should be 25, got ' + str(repr(celsius))\nassert fahrenheit == 77.0, 'fahrenheit should be 77.0, got ' + str(repr(fahrenheit))",
          "concepts": [
            "arithmetic",
            "formulas",
            "real-world scenarios"
          ]
        },
        {
          "id": "var_21",
          "title": "String Methods on Variables",
          "difficulty": 3,
          "description": "Create a variable `text = \"python\"` and use string methods to create `upper_text` (uppercase) and `title_text` (title case).",
          "hints": [
            "String methods: .upper(), .title(), .lower()",
            "Example: upper_text = text.upper()"
          ],
          "solution": "text = \"python\"\nupper_text = text.upper()\ntitle_text = text.title()",
          "starter_code": "text = \"python\"\n# Create uppercase and title case versions\n",
          "test_code": "assert text == 'python', \"text should be 'python', got \" + str(repr(text))\nassert isinstance(upper_text, str), 'upper_text should be a string (text), got ' + str(type(upper_text).__name__)\nassert len(upper_text) > 0, \"upper_text should not be empty\"\nassert isinstance(title_text, str), 'title_text should be a string (text), got ' + str(type(title_text).__name__)\nassert len(title_text) > 0, \"title_text should not be empty\"",
          "concepts": [
            "string methods",
            "method calls"
          ]
        },
        {
          "id": "var_22",
          "title": "List Variable with Multiple Elements",
          "difficulty": 3,
          "description": "Create a list variable `fruits = [\"apple\", \"banana\", \"cherry\"]` and access the first and last elements.",
          "hints": [
            "Lists use square brackets: [element1, element2, ...]",
            "Index 0 is first, -1 is last"
          ],
          "solution": "fruits = [\"apple\", \"banana\", \"cherry\"]\nfirst = fruits[0]\nlast = fruits[-1]",
          "starter_code": "fruits = [\"apple\", \"banana\", \"cherry\"]\n# Access first and last\n",
          "test_code": "assert isinstance(fruits, list), 'fruits should be a list, got ' + str(type(fruits).__name__)\nassert len(fruits) > 0, \"fruits should not be empty\"\nassert first == 'apple', \"first should be 'apple', got \" + str(repr(first))\nassert last == 'cherry', \"last should be 'cherry', got \" + str(repr(last))",
          "concepts": [
            "lists",
            "indexing",
            "sequences"
          ]
        },
        {
          "id": "var_23",
          "title": "Dictionary Variable Access",
          "difficulty": 3,
          "description": "Create a dictionary `person = {\"name\": \"Alice\", \"age\": 30, \"city\": \"NYC\"}` and access the values for name and age.",
          "hints": [
            "Dictionaries use curly braces: {key: value, ...}",
            "Access values: dict_var[\"key\"]"
          ],
          "solution": "person = {\"name\": \"Alice\", \"age\": 30, \"city\": \"NYC\"}\nname = person[\"name\"]\nage = person[\"age\"]",
          "starter_code": "person = {\"name\": \"Alice\", \"age\": 30, \"city\": \"NYC\"}\n# Access name and age\n",
          "test_code": "assert isinstance(person, dict), 'person should be a dictionary, got ' + str(type(person).__name__)\nassert len(person) > 0, \"person should not be empty\"\nassert name == 'Alice', \"name should be 'Alice', got \" + str(repr(name))\nassert age == 30, 'age should be 30, got ' + str(repr(age))",
          "concepts": [
            "dictionaries",
            "key-value pairs",
            "data structures"
          ]
        },
        {
          "id": "var_24",
          "title": "Variable Scope: Global vs Local",
          "difficulty": 3,
          "description": "Create a global variable `global_var = 10`, then create a function that creates a local variable `local_var = 20` and returns their sum.",
          "hints": [
            "Global variables exist outside functions",
            "Local variables exist only inside functions"
          ],
          "solution": "global_var = 10\ndef add_vars():\n    local_var = 20\n    return global_var + local_var\nresult = add_vars()",
          "starter_code": "global_var = 10\ndef add_vars():\n    # Create local variable and sum with global\n    pass\n",
          "test_code": "assert 'add_vars' in dir(), \"Function 'add_vars' not defined. Did you write: def add_vars(...)?\"\n_r0 = add_vars()\nassert _r0 == 30, 'Test 1: add_vars() returned ' + str(repr(_r0)) + ', expected 30'",
          "concepts": [
            "scope",
            "global variables",
            "local variables",
            "functions"
          ]
        },
        {
          "id": "var_25",
          "title": "Variable Shadowing",
          "difficulty": 3,
          "description": "Create a global variable `x = 5`, then create a function that creates a local variable `x = 10` and returns it (shadowing the global).",
          "hints": [
            "Shadowing occurs when a local variable has the same name as a global",
            "Inside the function, the local x 'shadows' the global x"
          ],
          "solution": "x = 5\ndef shadow_test():\n    x = 10\n    return x\nresult = shadow_test()",
          "starter_code": "x = 5\ndef shadow_test():\n    # Create local x that shadows global\n    pass\n",
          "test_code": "assert 'shadow_test' in dir(), \"Function 'shadow_test' not defined. Did you write: def shadow_test(...)?\"\n_r0 = shadow_test()\nassert _r0 == 10, 'Test 1: shadow_test() returned ' + str(repr(_r0)) + ', expected 10'",
          "concepts": [
            "scope",
            "shadowing",
            "variable conflict"
          ]
        },
        {
          "id": "var_26",
          "title": "Augmented Assignment with Strings",
          "difficulty": 3,
          "description": "Start with `text = \"Hello\"`, then use += to append \" World\" to it.",
          "hints": [
            "The += operator works with strings to concatenate",
            "text += \" World\" appends to the existing string"
          ],
          "solution": "text = \"Hello\"\ntext += \" World\"",
          "starter_code": "text = \"Hello\"\n# Append using +=\n",
          "test_code": "assert isinstance(text, str), 'text should be a string (text), got ' + str(type(text).__name__)\nassert len(text) > 0, \"text should not be empty\"",
          "concepts": [
            "augmented assignment",
            "string concatenation"
          ]
        },
        {
          "id": "var_27",
          "title": "Multiple Operations with Variables",
          "difficulty": 3,
          "description": "Create variables for a store: `item_price = 25`, `quantity = 4`, then calculate `subtotal`, then add `discount = 0.1` (10% off), and store final `price`.",
          "hints": [
            "subtotal = item_price * quantity",
            "discount_amount = subtotal * discount; price = subtotal - discount_amount"
          ],
          "solution": "item_price = 25\nquantity = 4\nsubtotal = item_price * quantity\ndiscount = 0.1\ndiscount_amount = subtotal * discount\nprice = subtotal - discount_amount",
          "starter_code": "item_price = 25\nquantity = 4\n# Calculate with discount\n",
          "test_code": "assert item_price == 25, 'item_price should be 25, got ' + str(repr(item_price))\nassert quantity == 4, 'quantity should be 4, got ' + str(repr(quantity))\nassert subtotal == 100, 'subtotal should be 100, got ' + str(repr(subtotal))\nassert discount == 0.1, 'discount should be 0.1, got ' + str(repr(discount))\nassert discount_amount == 10.0, 'discount_amount should be 10.0, got ' + str(repr(discount_amount))\nassert price == 90.0, 'price should be 90.0, got ' + str(repr(price))",
          "concepts": [
            "arithmetic",
            "multi-step calculations"
          ]
        },
        {
          "id": "var_28",
          "title": "Dynamic Type Change",
          "difficulty": 3,
          "description": "Create a variable `value = \"123\"` (string), then reassign it to the integer 123, showing Python's dynamic typing.",
          "hints": [
            "Python allows a variable to change types",
            "Use int(value) to convert or reassign directly"
          ],
          "solution": "value = \"123\"\nvalue = int(value)",
          "starter_code": "value = \"123\"\n# Convert to integer\n",
          "test_code": "assert value == 123, 'value should be 123, got ' + str(repr(value))",
          "concepts": [
            "dynamic typing",
            "type conversion"
          ]
        },
        {
          "id": "var_29",
          "title": "Boolean Expression Result",
          "difficulty": 3,
          "description": "Create variables `a = 10` and `b = 5`, then create a boolean variable `is_greater = a > b` that stores the result of the comparison.",
          "hints": [
            "Comparison operators: >, <, ==, !=, >=, <=",
            "is_greater = a > b will be True"
          ],
          "solution": "a = 10\nb = 5\nis_greater = a > b",
          "starter_code": "a = 10\nb = 5\n# Create boolean variable from comparison\n",
          "test_code": "assert a == 10, 'a should be 10, got ' + str(repr(a))\nassert b == 5, 'b should be 5, got ' + str(repr(b))\nassert isinstance(is_greater, bool), 'is_greater should be a boolean (True/False), got ' + str(type(is_greater).__name__)",
          "concepts": [
            "booleans",
            "comparisons",
            "operators"
          ]
        },
        {
          "id": "var_30",
          "title": "F-String with Expressions",
          "difficulty": 3,
          "description": "Create variables `width = 10` and `height = 20`, then use an f-string to display 'Area: [calculated area]'.",
          "hints": [
            "F-strings can contain expressions inside curly braces",
            "f\"Area: {width * height}\""
          ],
          "solution": "width = 10\nheight = 20\narea_message = f\"Area: {width * height}\"",
          "starter_code": "width = 10\nheight = 20\n# Use f-string with calculation\n",
          "test_code": "assert width == 10, 'width should be 10, got ' + str(repr(width))\nassert height == 20, 'height should be 20, got ' + str(repr(height))\nassert isinstance(area_message, str), 'area_message should be a string (text), got ' + str(type(area_message).__name__)\nassert len(area_message) > 0, \"area_message should not be empty\"",
          "concepts": [
            "f-strings",
            "expressions",
            "formatting"
          ]
        },
        {
          "id": "var_31",
          "title": "Tuple Unpacking with Rest",
          "difficulty": 3,
          "description": "Unpack the tuple (1, 2, 3, 4, 5) where `first = 1`, `second = 2`, and `rest = [3, 4, 5]` using * unpacking.",
          "hints": [
            "Use the * operator to capture remaining elements",
            "first, second, *rest = (1, 2, 3, 4, 5)"
          ],
          "solution": "first, second, *rest = (1, 2, 3, 4, 5)",
          "starter_code": "# Unpack with * to capture rest\n",
          "test_code": "assert first == 1, 'first should be 1, got ' + str(repr(first))\nassert second == 2, 'second should be 2, got ' + str(repr(second))\nassert isinstance(rest, list), 'rest should be a list, got ' + str(type(rest).__name__)\nassert len(rest) > 0, \"rest should not be empty\"",
          "concepts": [
            "unpacking",
            "variadic unpacking",
            "advanced assignment"
          ]
        },
        {
          "id": "var_32",
          "title": "Variable Swap Advanced",
          "difficulty": 3,
          "description": "Given three variables `a = 1`, `b = 2`, `c = 3`, rotate their values so that a=2, b=3, c=1.",
          "hints": [
            "Multiple assignment allows rotation: a, b, c = b, c, a",
            "This shifts each value one position"
          ],
          "solution": "a, b, c = 1, 2, 3\na, b, c = b, c, a",
          "starter_code": "a, b, c = 1, 2, 3\n# Rotate values\n",
          "test_code": "assert a == 2, 'a should be 2, got ' + str(repr(a))\nassert b == 3, 'b should be 3, got ' + str(repr(b))\nassert c == 1, 'c should be 1, got ' + str(repr(c))",
          "concepts": [
            "multiple assignment",
            "rotation",
            "swapping"
          ]
        },
        {
          "id": "var_33",
          "title": "Real-World: User Profile",
          "difficulty": 3,
          "description": "Create a user profile with variables: `first_name`, `last_name`, `email`, `age`, then use an f-string to create a profile summary.",
          "hints": [
            "Combine multiple variables of different types",
            "Use f-string to format: f\"User: {first_name} {last_name}, Email: {email}, Age: {age}\""
          ],
          "solution": "first_name = \"John\"\nlast_name = \"Smith\"\nemail = \"john@example.com\"\nage = 28\nprofile = f\"User: {first_name} {last_name}, Email: {email}, Age: {age}\"",
          "starter_code": "# Create user profile variables\n",
          "test_code": "assert isinstance(first_name, str), 'first_name should be a string (text), got ' + str(type(first_name).__name__)\nassert len(first_name) > 0, \"first_name should not be empty\"\nassert isinstance(last_name, str), 'last_name should be a string (text), got ' + str(type(last_name).__name__)\nassert len(last_name) > 0, \"last_name should not be empty\"\nassert isinstance(email, str), 'email should be a string (text), got ' + str(type(email).__name__)\nassert len(email) > 0, \"email should not be empty\"\nassert age == 28, 'age should be 28, got ' + str(repr(age))\nassert isinstance(profile, str), 'profile should be a string (text), got ' + str(type(profile).__name__)\nassert len(profile) > 0, \"profile should not be empty\"",
          "concepts": [
            "multiple variables",
            "f-strings",
            "real-world scenarios"
          ]
        },
        {
          "id": "var_34",
          "title": "Real-World: BMI Calculator",
          "difficulty": 3,
          "description": "Calculate BMI with variables: `weight_kg = 70`, `height_m = 1.75`. BMI = weight / (height²). Store in `bmi` variable.",
          "hints": [
            "BMI formula: bmi = weight_kg / (height_m ** 2)",
            "Result should be approximately 22.86"
          ],
          "solution": "weight_kg = 70\nheight_m = 1.75\nbmi = weight_kg / (height_m ** 2)",
          "starter_code": "weight_kg = 70\nheight_m = 1.75\n# Calculate BMI\n",
          "test_code": "assert weight_kg == 70, 'weight_kg should be 70, got ' + str(repr(weight_kg))\nassert height_m == 1.75, 'height_m should be 1.75, got ' + str(repr(height_m))\nassert bmi == 22.857142857142858, 'bmi should be 22.857142857142858, got ' + str(repr(bmi))",
          "concepts": [
            "arithmetic",
            "formulas",
            "real-world scenarios"
          ]
        },
        {
          "id": "var_35",
          "title": "Constants and Reuse",
          "difficulty": 3,
          "description": "Define mathematical constants `PI = 3.14159` and `E = 2.71828`, then use them to calculate `circle_area = PI * 5**2` and `exponential_e = E**2`.",
          "hints": [
            "Define constants in ALL_CAPS",
            "Reuse them in multiple calculations"
          ],
          "solution": "PI = 3.14159\nE = 2.71828\ncircle_area = PI * 5**2\nexponential_e = E**2",
          "starter_code": "PI = 3.14159\nE = 2.71828\n# Use constants\n",
          "test_code": "assert PI == 3.14159, 'PI should be 3.14159, got ' + str(repr(PI))\nassert E == 2.71828, 'E should be 2.71828, got ' + str(repr(E))\nassert circle_area == 78.53975, 'circle_area should be 78.53975, got ' + str(repr(circle_area))\nassert exponential_e == 7.3890461584, 'exponential_e should be 7.3890461584, got ' + str(repr(exponential_e))",
          "concepts": [
            "constants",
            "reuse",
            "arithmetic"
          ]
        },
        {
          "id": "var_36",
          "title": "List Comprehension Assignment",
          "difficulty": 4,
          "description": "Create a variable `squares` that stores squares of numbers 1-5 using list comprehension: [1, 4, 9, 16, 25].",
          "hints": [
            "List comprehension syntax: [expression for item in iterable]",
            "[x**2 for x in range(1, 6)]"
          ],
          "solution": "squares = [x**2 for x in range(1, 6)]",
          "starter_code": "# Create list of squares using comprehension\n",
          "test_code": "assert isinstance(squares, list), 'squares should be a list, got ' + str(type(squares).__name__)\nassert len(squares) > 0, \"squares should not be empty\"",
          "concepts": [
            "list comprehension",
            "advanced assignment"
          ]
        },
        {
          "id": "var_37",
          "title": "Dictionary from Variables",
          "difficulty": 4,
          "description": "Create variables `keys = [\"a\", \"b\", \"c\"]` and `values = [1, 2, 3]`, then create a dictionary `my_dict = {\"a\": 1, \"b\": 2, \"c\": 3}` using dict() or dict comprehension.",
          "hints": [
            "Use zip() to pair keys and values: dict(zip(keys, values))",
            "Or use dict comprehension: {k: v for k, v in zip(keys, values)}"
          ],
          "solution": "keys = [\"a\", \"b\", \"c\"]\nvalues = [1, 2, 3]\nmy_dict = dict(zip(keys, values))",
          "starter_code": "keys = [\"a\", \"b\", \"c\"]\nvalues = [1, 2, 3]\n# Create dictionary\n",
          "test_code": "assert isinstance(keys, list), 'keys should be a list, got ' + str(type(keys).__name__)\nassert len(keys) > 0, \"keys should not be empty\"\nassert isinstance(values, list), 'values should be a list, got ' + str(type(values).__name__)\nassert len(values) > 0, \"values should not be empty\"\nassert isinstance(my_dict, dict), 'my_dict should be a dictionary, got ' + str(type(my_dict).__name__)\nassert len(my_dict) > 0, \"my_dict should not be empty\"",
          "concepts": [
            "dictionaries",
            "zip",
            "advanced data structures"
          ]
        },
        {
          "id": "var_38",
          "title": "Mutable vs Immutable: List Assignment",
          "difficulty": 4,
          "description": "Create a list `original = [1, 2, 3]`, assign it to `copy = original`, then modify copy to [1, 2, 3, 4]. Show that both reference the same list.",
          "hints": [
            "Lists are mutable and share references",
            "copy = original doesn't make a new list, it makes another reference"
          ],
          "solution": "original = [1, 2, 3]\ncopy = original\ncopy.append(4)\nsame_reference = original is copy",
          "starter_code": "original = [1, 2, 3]\ncopy = original\n# Modify and check\n",
          "test_code": "assert isinstance(original, list), 'original should be a list, got ' + str(type(original).__name__)\nassert len(original) > 0, \"original should not be empty\"\nassert isinstance(copy, list), 'copy should be a list, got ' + str(type(copy).__name__)\nassert len(copy) > 0, \"copy should not be empty\"\nassert isinstance(same_reference, bool), 'same_reference should be a boolean (True/False), got ' + str(type(same_reference).__name__)",
          "concepts": [
            "mutability",
            "references",
            "object identity"
          ]
        },
        {
          "id": "var_39",
          "title": "Mutable vs Immutable: String Assignment",
          "difficulty": 4,
          "description": "Create a string `original = \"hello\"`, assign it to `copy = original`, then try to modify copy (strings are immutable, so create a new string).",
          "hints": [
            "Strings are immutable, so reassignment creates a new object",
            "copy = original + \" world\" creates a new string"
          ],
          "solution": "original = \"hello\"\ncopy = original\ncopy = copy + \" world\"\nsame_reference = original is copy",
          "starter_code": "original = \"hello\"\ncopy = original\n# Modify and check\n",
          "test_code": "assert original == 'hello', \"original should be 'hello', got \" + str(repr(original))\nassert isinstance(copy, str), 'copy should be a string (text), got ' + str(type(copy).__name__)\nassert len(copy) > 0, \"copy should not be empty\"\nassert isinstance(same_reference, bool), 'same_reference should be a boolean (True/False), got ' + str(type(same_reference).__name__)",
          "concepts": [
            "immutability",
            "references",
            "object identity"
          ]
        },
        {
          "id": "var_40",
          "title": "Nested Data Structure Assignment",
          "difficulty": 4,
          "description": "Create a nested dictionary `student = {\"name\": \"Alice\", \"grades\": {\"math\": 95, \"english\": 88}}` and access nested values.",
          "hints": [
            "Nested structures: student[\"grades\"][\"math\"]",
            "Dictionaries inside dictionaries"
          ],
          "solution": "student = {\"name\": \"Alice\", \"grades\": {\"math\": 95, \"english\": 88}}\nmath_grade = student[\"grades\"][\"math\"]\nenglish_grade = student[\"grades\"][\"english\"]",
          "starter_code": "student = {\"name\": \"Alice\", \"grades\": {\"math\": 95, \"english\": 88}}\n# Access nested values\n",
          "test_code": "assert isinstance(student, dict), 'student should be a dictionary, got ' + str(type(student).__name__)\nassert len(student) > 0, \"student should not be empty\"\nassert math_grade == 95, 'math_grade should be 95, got ' + str(repr(math_grade))\nassert english_grade == 88, 'english_grade should be 88, got ' + str(repr(english_grade))",
          "concepts": [
            "nested structures",
            "data structures",
            "access patterns"
          ]
        },
        {
          "id": "var_41",
          "title": "Variable with Conditional Expression",
          "difficulty": 4,
          "description": "Create a variable `score = 85`, then use a conditional expression to assign `grade = \"A\" if score >= 90 else \"B\"` (ternary operator).",
          "hints": [
            "Ternary conditional: value_if_true if condition else value_if_false",
            "grade = \"A\" if score >= 90 else \"B\""
          ],
          "solution": "score = 85\ngrade = \"A\" if score >= 90 else \"B\"",
          "starter_code": "score = 85\n# Use ternary operator\n",
          "test_code": "assert score == 85, 'score should be 85, got ' + str(repr(score))\nassert grade == 'B', \"grade should be 'B', got \" + str(repr(grade))",
          "concepts": [
            "conditional expressions",
            "ternary operator"
          ]
        },
        {
          "id": "var_42",
          "title": "Generator Expression Assignment",
          "difficulty": 4,
          "description": "Create a generator `even_numbers = (x for x in range(1, 11) if x % 2 == 0)` that yields even numbers 1-10.",
          "hints": [
            "Generator comprehension uses parentheses: (expression for ...)",
            "Similar to list comprehension but lazy (doesn't compute all at once)"
          ],
          "solution": "even_numbers = (x for x in range(1, 11) if x % 2 == 0)",
          "starter_code": "# Create a generator expression\n",
          "test_code": "pass  # Verify your code runs without errors",
          "concepts": [
            "generators",
            "comprehensions",
            "lazy evaluation"
          ]
        },
        {
          "id": "var_43",
          "title": "Real-World: Invoice with Multiple Variables",
          "difficulty": 4,
          "description": "Create an invoice: `items = [(\"Widget\", 10, 5), (\"Gadget\", 15, 2)]` (name, price, qty), calculate `total`, add `tax = 0.08`, and final `invoice_total`.",
          "hints": [
            "items is a list of tuples",
            "total = sum(price * qty for each item); invoice_total = total * (1 + tax)"
          ],
          "solution": "items = [(\"Widget\", 10, 5), (\"Gadget\", 15, 2)]\ntotal = sum(price * qty for name, price, qty in items)\ntax = 0.08\ninvoice_total = total * (1 + tax)",
          "starter_code": "items = [(\"Widget\", 10, 5), (\"Gadget\", 15, 2)]\n# Calculate invoice\n",
          "test_code": "assert isinstance(items, list), 'items should be a list, got ' + str(type(items).__name__)\nassert len(items) > 0, \"items should not be empty\"\nassert total == 80, 'total should be 80, got ' + str(repr(total))\nassert tax == 0.08, 'tax should be 0.08, got ' + str(repr(tax))\nassert invoice_total == 86.4, 'invoice_total should be 86.4, got ' + str(repr(invoice_total))",
          "concepts": [
            "real-world scenarios",
            "comprehensions",
            "calculations"
          ]
        },
        {
          "id": "var_44",
          "title": "Variable Chain Assignment",
          "difficulty": 4,
          "description": "Use chain assignment to set three variables to the same value in one statement: `a = b = c = 42`.",
          "hints": [
            "a = b = c = 42 assigns 42 to all three",
            "All three variables reference the same value (for immutables like int)"
          ],
          "solution": "a = b = c = 42",
          "starter_code": "# Chain assignment\n",
          "test_code": "assert a == 42, 'a should be 42, got ' + str(repr(a))\nassert b == 42, 'b should be 42, got ' + str(repr(b))\nassert c == 42, 'c should be 42, got ' + str(repr(c))",
          "concepts": [
            "chain assignment",
            "multiple variables"
          ]
        },
        {
          "id": "var_45",
          "title": "Real-World: Weather Data Analysis",
          "difficulty": 4,
          "description": "Store daily temps: `temps = [72, 75, 68, 70, 73]`, then calculate `avg_temp`, `max_temp`, `min_temp`, and create a summary f-string.",
          "hints": [
            "Use sum(), len(), max(), min() functions",
            "avg_temp = sum(temps) / len(temps)"
          ],
          "solution": "temps = [72, 75, 68, 70, 73]\navg_temp = sum(temps) / len(temps)\nmax_temp = max(temps)\nmin_temp = min(temps)\nsummary = f\"Avg: {avg_temp:.1f}, Max: {max_temp}, Min: {min_temp}\"",
          "starter_code": "temps = [72, 75, 68, 70, 73]\n# Analyze temperature data\n",
          "test_code": "assert isinstance(temps, list), 'temps should be a list, got ' + str(type(temps).__name__)\nassert len(temps) > 0, \"temps should not be empty\"\nassert avg_temp == 71.6, 'avg_temp should be 71.6, got ' + str(repr(avg_temp))\nassert max_temp == 75, 'max_temp should be 75, got ' + str(repr(max_temp))\nassert min_temp == 68, 'min_temp should be 68, got ' + str(repr(min_temp))\nassert isinstance(summary, str), 'summary should be a string (text), got ' + str(type(summary).__name__)\nassert len(summary) > 0, \"summary should not be empty\"",
          "concepts": [
            "data analysis",
            "built-in functions",
            "aggregation"
          ]
        },
        {
          "id": "var_46",
          "title": "Global Keyword and Modification",
          "difficulty": 5,
          "description": "Create a global variable `counter = 0`, then create a function that uses the `global` keyword to increment it.",
          "hints": [
            "Use `global variable_name` inside a function to modify global scope",
            "Without global, assignment creates a local variable"
          ],
          "solution": "counter = 0\ndef increment():\n    global counter\n    counter += 1\n    return counter",
          "starter_code": "counter = 0\ndef increment():\n    # Use global to modify counter\n    pass\n",
          "test_code": "assert 'increment' in dir(), \"Function 'increment' not defined. Did you write: def increment(...)?\"\n_r0 = increment()\nassert _r0 == 1, 'Test 1: increment() returned ' + str(repr(_r0)) + ', expected 1'",
          "concepts": [
            "global keyword",
            "scope modification",
            "state management"
          ]
        },
        {
          "id": "var_47",
          "title": "Unpacking Nested Structures",
          "difficulty": 5,
          "description": "Unpack nested tuples: `data = ((1, 2), (3, 4))` to extract `a=1, b=2, c=3, d=4` in a single unpacking statement.",
          "hints": [
            "Use nested unpacking: (a, b), (c, d) = data",
            "Each level can be unpacked independently"
          ],
          "solution": "data = ((1, 2), (3, 4))\n(a, b), (c, d) = data",
          "starter_code": "data = ((1, 2), (3, 4))\n# Unpack nested tuples\n",
          "test_code": "assert isinstance(data, tuple), 'data should be a tuple, got ' + str(type(data).__name__)\nassert len(data) > 0, \"data should not be empty\"\nassert a == 1, 'a should be 1, got ' + str(repr(a))\nassert b == 2, 'b should be 2, got ' + str(repr(b))\nassert c == 3, 'c should be 3, got ' + str(repr(c))\nassert d == 4, 'd should be 4, got ' + str(repr(d))",
          "concepts": [
            "nested unpacking",
            "advanced assignment",
            "destructuring"
          ]
        },
        {
          "id": "var_48",
          "title": "Advanced: String Format Method",
          "difficulty": 5,
          "description": "Create variables `name = \"Bob\"`, `age = 25`, and use the `.format()` method with variable substitution: `\"My name is {} and I am {} years old\".format(name, age)`.",
          "hints": [
            "The .format() method uses curly braces {} as placeholders",
            "Values are passed as arguments: .format(arg1, arg2, ...)"
          ],
          "solution": "name = \"Bob\"\nage = 25\nmessage = \"My name is {} and I am {} years old\".format(name, age)",
          "starter_code": "name = \"Bob\"\nage = 25\n# Use .format() method\n",
          "test_code": "assert name == 'Bob', \"name should be 'Bob', got \" + str(repr(name))\nassert age == 25, 'age should be 25, got ' + str(repr(age))\nassert isinstance(message, str), 'message should be a string (text), got ' + str(type(message).__name__)\nassert len(message) > 0, \"message should not be empty\"",
          "concepts": [
            "string methods",
            "formatting",
            ".format()"
          ]
        },
        {
          "id": "var_49",
          "title": "Real-World: Portfolio Calculation",
          "difficulty": 5,
          "description": "Simulate a portfolio: `holdings = {\"AAPL\": (150, 30), \"MSFT\": (300, 20)}` (price, shares), calculate total value of each holding and total portfolio.",
          "hints": [
            "holdings structure: symbol -> (price, shares)",
            "Use dict comprehension or loops to calculate values"
          ],
          "solution": "holdings = {\"AAPL\": (150, 30), \"MSFT\": (300, 20)}\nvalues = {symbol: price * shares for symbol, (price, shares) in holdings.items()}\nportfolio_total = sum(values.values())",
          "starter_code": "holdings = {\"AAPL\": (150, 30), \"MSFT\": (300, 20)}\n# Calculate portfolio value\n",
          "test_code": "assert isinstance(holdings, dict), 'holdings should be a dictionary, got ' + str(type(holdings).__name__)\nassert len(holdings) > 0, \"holdings should not be empty\"\nassert isinstance(values, dict), 'values should be a dictionary, got ' + str(type(values).__name__)\nassert len(values) > 0, \"values should not be empty\"\nassert portfolio_total == 10500, 'portfolio_total should be 10500, got ' + str(repr(portfolio_total))",
          "concepts": [
            "real-world scenarios",
            "dict comprehension",
            "complex calculations"
          ]
        },
        {
          "id": "var_50",
          "title": "Comprehension with Conditional: Challenge",
          "difficulty": 5,
          "description": "Create a variable `result` that is a dictionary of numbers and their squares, but only for numbers 1-10 where the square is > 25: `{6: 36, 7: 49, 8: 64, ..., 10: 100}`.",
          "hints": [
            "Use dict comprehension: {x: x**2 for x in range(1, 11) if x**2 > 25}",
            "Apply both iteration and filtering in one comprehension"
          ],
          "solution": "result = {x: x**2 for x in range(1, 11) if x**2 > 25}",
          "starter_code": "# Create dict comprehension with condition\n",
          "test_code": "assert isinstance(result, dict), 'result should be a dictionary, got ' + str(type(result).__name__)\nassert len(result) > 0, \"result should not be empty\"",
          "concepts": [
            "dict comprehension",
            "conditionals",
            "advanced filtering"
          ]
        }
      ]
    },
    {
      "id": "data_types",
      "title": "Data Types",
      "exercise_count": 50,
      "exercises": [
        {
          "id": "dt_01",
          "title": "Identify Integer Type",
          "difficulty": 1,
          "description": "Create a variable `x` that holds the integer value 42 and use the `type()` function to verify it's an int.",
          "hints": [
            "Use the assignment operator to assign 42 to x",
            "Call type(x) and compare it to int"
          ],
          "solution": "x = 42\nresult = type(x) == int",
          "starter_code": "",
          "test_code": "assert x == 42, 'x should be 42, got ' + str(repr(x))\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "int",
            "type()"
          ]
        },
        {
          "id": "dt_02",
          "title": "Identify Float Type",
          "difficulty": 1,
          "description": "Create a variable `y` that holds the float value 3.14 and verify it's a float using type().",
          "hints": [
            "Use a decimal point to make it a float",
            "Compare type(y) to float"
          ],
          "solution": "y = 3.14\nresult = type(y) == float",
          "starter_code": "",
          "test_code": "assert y == 3.14, 'y should be 3.14, got ' + str(repr(y))\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "float",
            "type()"
          ]
        },
        {
          "id": "dt_03",
          "title": "Identify String Type",
          "difficulty": 1,
          "description": "Create a variable `message` with the string 'Hello' and verify it's a string.",
          "hints": [
            "Wrap text in quotes to make it a string",
            "Use type() to check the type"
          ],
          "solution": "message = 'Hello'\nresult = type(message) == str",
          "starter_code": "",
          "test_code": "assert message == 'Hello', \"message should be 'Hello', got \" + str(repr(message))\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "str",
            "type()"
          ]
        },
        {
          "id": "dt_04",
          "title": "Identify Boolean Type",
          "difficulty": 1,
          "description": "Create a variable `flag` with the boolean value True and verify its type.",
          "hints": [
            "Use True (capital T) for boolean true",
            "Compare the type to bool"
          ],
          "solution": "flag = True\nresult = type(flag) == bool",
          "starter_code": "",
          "test_code": "assert flag == True, 'flag should be True, got ' + str(repr(flag))\nassert result == True, 'result should be True, got ' + str(repr(result))",
          "concepts": [
            "bool",
            "type()"
          ]
        },
        {
          "id": "dt_05",
          "title": "Convert String to Integer",
          "difficulty": 1,
          "description": "Convert the string '123' to an integer using the int() function and store in variable `num`.",
          "hints": [
            "Use the int() function with a string argument",
            "Make sure to pass the string '123' not the number 123"
          ],
          "solution": "num = int('123')\nresult = num == 123 and type(num) == int",
          "starter_code": "",
          "test_code": "assert num == 123, 'num should be 123, got ' + str(repr(num))\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "int()",
            "type conversion"
          ]
        },
        {
          "id": "dt_06",
          "title": "Convert Integer to String",
          "difficulty": 1,
          "description": "Convert the integer 456 to a string using str() and store in variable `text`.",
          "hints": [
            "Use the str() function with the integer",
            "After conversion, it should have type str"
          ],
          "solution": "text = str(456)\nresult = text == '456' and type(text) == str",
          "starter_code": "",
          "test_code": "assert isinstance(text, str), 'text should be a string (text), got ' + str(type(text).__name__)\nassert len(text) > 0, \"text should not be empty\"\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "str()",
            "type conversion"
          ]
        },
        {
          "id": "dt_07",
          "title": "Convert String to Float",
          "difficulty": 1,
          "description": "Convert the string '3.14' to a float using float() and store in variable `pi_approx`.",
          "hints": [
            "Use the float() function",
            "It should work with decimal notation in strings"
          ],
          "solution": "pi_approx = float('3.14')\nresult = abs(pi_approx - 3.14) < 0.0001 and type(pi_approx) == float",
          "starter_code": "",
          "test_code": "assert pi_approx == 3.14, 'pi_approx should be 3.14, got ' + str(repr(pi_approx))\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "float()",
            "type conversion"
          ]
        },
        {
          "id": "dt_08",
          "title": "Convert to Boolean",
          "difficulty": 1,
          "description": "Convert the integer 1 to a boolean using bool() and store in variable `b`.",
          "hints": [
            "Use the bool() function",
            "Non-zero numbers convert to True"
          ],
          "solution": "b = bool(1)\nresult = b is True and type(b) == bool",
          "starter_code": "",
          "test_code": "assert isinstance(b, bool), 'b should be a boolean (True/False), got ' + str(type(b).__name__)\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "bool()",
            "type conversion"
          ]
        },
        {
          "id": "dt_09",
          "title": "String Length with len()",
          "difficulty": 1,
          "description": "Find the length of the string 'Python' using len() and store in variable `length`.",
          "hints": [
            "The len() function counts characters in a string",
            "'Python' has 6 characters"
          ],
          "solution": "length = len('Python')\nresult = length == 6",
          "starter_code": "",
          "test_code": "assert isinstance(length, (int, float)), 'length should be a number, got ' + str(type(length).__name__)\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "len()",
            "str"
          ]
        },
        {
          "id": "dt_10",
          "title": "Check Type with isinstance()",
          "difficulty": 1,
          "description": "Use isinstance() to check if the variable `x = 100` is an integer. Store the result in `check_result`.",
          "hints": [
            "isinstance() takes an object and a type as arguments",
            "The syntax is isinstance(object, type)"
          ],
          "solution": "x = 100\ncheck_result = isinstance(x, int)",
          "starter_code": "",
          "test_code": "assert x == 100, 'x should be 100, got ' + str(repr(x))\nassert isinstance(check_result, bool), 'check_result should be a boolean (True/False), got ' + str(type(check_result).__name__)",
          "concepts": [
            "isinstance()",
            "type checking"
          ]
        },
        {
          "id": "dt_11",
          "title": "String Upper Method",
          "difficulty": 2,
          "description": "Convert the string 'hello world' to uppercase using the upper() method and store in `upper_text`.",
          "hints": [
            "Use the .upper() method on the string",
            "String methods are called with a dot"
          ],
          "solution": "upper_text = 'hello world'.upper()\nresult = upper_text == 'HELLO WORLD'",
          "starter_code": "",
          "test_code": "assert isinstance(upper_text, str), 'upper_text should be a string (text), got ' + str(type(upper_text).__name__)\nassert len(upper_text) > 0, \"upper_text should not be empty\"\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "str.upper()",
            "string methods"
          ]
        },
        {
          "id": "dt_12",
          "title": "String Lower Method",
          "difficulty": 2,
          "description": "Convert 'PYTHON ROCKS' to lowercase using lower() and store in `lower_text`.",
          "hints": [
            "Use the .lower() method",
            "The result should be all lowercase"
          ],
          "solution": "lower_text = 'PYTHON ROCKS'.lower()\nresult = lower_text == 'python rocks'",
          "starter_code": "",
          "test_code": "assert isinstance(lower_text, str), 'lower_text should be a string (text), got ' + str(type(lower_text).__name__)\nassert len(lower_text) > 0, \"lower_text should not be empty\"\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "str.lower()",
            "string methods"
          ]
        },
        {
          "id": "dt_13",
          "title": "String Strip Method",
          "difficulty": 2,
          "description": "Remove leading and trailing whitespace from '  hello  ' using strip() and store in `stripped`.",
          "hints": [
            "The .strip() method removes whitespace from both ends",
            "It doesn't modify the middle of the string"
          ],
          "solution": "stripped = '  hello  '.strip()\nresult = stripped == 'hello'",
          "starter_code": "",
          "test_code": "assert isinstance(stripped, str), 'stripped should be a string (text), got ' + str(type(stripped).__name__)\nassert len(stripped) > 0, \"stripped should not be empty\"\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "str.strip()",
            "whitespace"
          ]
        },
        {
          "id": "dt_14",
          "title": "String Replace Method",
          "difficulty": 2,
          "description": "Replace 'cat' with 'dog' in 'the cat sat on the mat' and store in `replaced`.",
          "hints": [
            "Use the .replace() method with two arguments",
            "The syntax is .replace(old, new)"
          ],
          "solution": "replaced = 'the cat sat on the mat'.replace('cat', 'dog')\nresult = replaced == 'the dog sat on the mat'",
          "starter_code": "",
          "test_code": "assert isinstance(replaced, str), 'replaced should be a string (text), got ' + str(type(replaced).__name__)\nassert len(replaced) > 0, \"replaced should not be empty\"\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "str.replace()",
            "string methods"
          ]
        },
        {
          "id": "dt_15",
          "title": "String Find Method",
          "difficulty": 2,
          "description": "Find the index of 'world' in 'hello world' using find() and store in `index`.",
          "hints": [
            "The .find() method returns the starting index of the substring",
            "'hello ' is 6 characters, so 'world' starts at index 6"
          ],
          "solution": "index = 'hello world'.find('world')\nresult = index == 6",
          "starter_code": "",
          "test_code": "assert isinstance(index, (int, float)), 'index should be a number, got ' + str(type(index).__name__)\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "str.find()",
            "string indexing"
          ]
        },
        {
          "id": "dt_16",
          "title": "String Indexing",
          "difficulty": 2,
          "description": "Get the character at index 0 from 'Python' and store in `first_char`.",
          "hints": [
            "Use bracket notation: string[index]",
            "Index 0 is the first character"
          ],
          "solution": "first_char = 'Python'[0]\nresult = first_char == 'P'",
          "starter_code": "",
          "test_code": "assert isinstance(first_char, str), 'first_char should be a string (text), got ' + str(type(first_char).__name__)\nassert len(first_char) > 0, \"first_char should not be empty\"\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "str indexing",
            "indexing"
          ]
        },
        {
          "id": "dt_17",
          "title": "String Slicing",
          "difficulty": 2,
          "description": "Get characters from index 0 to 3 (exclusive) from 'Python' using slicing and store in `slice_text`.",
          "hints": [
            "Use the syntax string[start:end]",
            "[0:3] gives characters at indices 0, 1, 2"
          ],
          "solution": "slice_text = 'Python'[0:3]\nresult = slice_text == 'Pyt'",
          "starter_code": "",
          "test_code": "assert isinstance(slice_text, str), 'slice_text should be a string (text), got ' + str(type(slice_text).__name__)\nassert len(slice_text) > 0, \"slice_text should not be empty\"\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "str slicing",
            "slicing"
          ]
        },
        {
          "id": "dt_18",
          "title": "String Split Method",
          "difficulty": 2,
          "description": "Split 'apple,banana,orange' by comma using split() and store in `fruits`.",
          "hints": [
            "Use the .split() method with the delimiter",
            "The result should be a list of strings"
          ],
          "solution": "fruits = 'apple,banana,orange'.split(',')\nresult = fruits == ['apple', 'banana', 'orange']",
          "starter_code": "",
          "test_code": "assert isinstance(fruits, list), 'fruits should be a list, got ' + str(type(fruits).__name__)\nassert len(fruits) > 0, \"fruits should not be empty\"\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "str.split()",
            "string parsing"
          ]
        },
        {
          "id": "dt_19",
          "title": "String Join Method",
          "difficulty": 2,
          "description": "Join the list ['one', 'two', 'three'] with hyphens using join() and store in `joined`.",
          "hints": [
            "Use the .join() method on the separator string",
            "The syntax is separator.join(list)"
          ],
          "solution": "joined = '-'.join(['one', 'two', 'three'])\nresult = joined == 'one-two-three'",
          "starter_code": "",
          "test_code": "assert isinstance(joined, str), 'joined should be a string (text), got ' + str(type(joined).__name__)\nassert len(joined) > 0, \"joined should not be empty\"\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "str.join()",
            "list operations"
          ]
        },
        {
          "id": "dt_20",
          "title": "Format with f-string",
          "difficulty": 2,
          "description": "Use an f-string to format 'Hello, Alice!' where 'Alice' is stored in variable `name = 'Alice'`.",
          "hints": [
            "Use the f'' syntax with variables in curly braces",
            "The syntax is f'Hello, {name}!'"
          ],
          "solution": "name = 'Alice'\ngreeting = f'Hello, {name}!'\nresult = greeting == 'Hello, Alice!'",
          "starter_code": "",
          "test_code": "assert name == 'Alice', \"name should be 'Alice', got \" + str(repr(name))\nassert greeting == 'Hello, Alice!', \"greeting should be 'Hello, Alice!', got \" + str(repr(greeting))\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "f-strings",
            "string formatting"
          ]
        },
        {
          "id": "dt_21",
          "title": "Integer Division",
          "difficulty": 3,
          "description": "Divide 17 by 5 using integer division (//) and store the result in `int_div`.",
          "hints": [
            "Use the // operator for integer division",
            "17 // 5 gives 3 (not 3.4)"
          ],
          "solution": "int_div = 17 // 5\nresult = int_div == 3",
          "starter_code": "",
          "test_code": "assert int_div == 3, 'int_div should be 3, got ' + str(repr(int_div))\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "integer division",
            "//",
            "operators"
          ]
        },
        {
          "id": "dt_22",
          "title": "Modulo Operator",
          "difficulty": 3,
          "description": "Find the remainder when 17 is divided by 5 using the modulo operator (%) and store in `remainder`.",
          "hints": [
            "Use the % operator",
            "17 % 5 gives 2 (the remainder)"
          ],
          "solution": "remainder = 17 % 5\nresult = remainder == 2",
          "starter_code": "",
          "test_code": "assert remainder == 2, 'remainder should be 2, got ' + str(repr(remainder))\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "modulo",
            "%",
            "operators"
          ]
        },
        {
          "id": "dt_23",
          "title": "Exponentiation",
          "difficulty": 3,
          "description": "Calculate 2 to the power of 8 using the exponentiation operator (**) and store in `power`.",
          "hints": [
            "Use the ** operator",
            "2 ** 8 equals 256"
          ],
          "solution": "power = 2 ** 8\nresult = power == 256",
          "starter_code": "",
          "test_code": "assert power == 256, 'power should be 256, got ' + str(repr(power))\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "exponentiation",
            "**",
            "operators"
          ]
        },
        {
          "id": "dt_24",
          "title": "Absolute Value Function",
          "difficulty": 3,
          "description": "Find the absolute value of -42 using abs() and store in `absolute`.",
          "hints": [
            "The abs() function returns the non-negative value",
            "abs(-42) is 42"
          ],
          "solution": "absolute = abs(-42)\nresult = absolute == 42",
          "starter_code": "",
          "test_code": "assert absolute == 42, 'absolute should be 42, got ' + str(repr(absolute))\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "abs()",
            "functions"
          ]
        },
        {
          "id": "dt_25",
          "title": "Round Function",
          "difficulty": 3,
          "description": "Round 3.7 to the nearest integer using round() and store in `rounded`.",
          "hints": [
            "The round() function rounds to the nearest integer by default",
            "3.7 rounds to 4"
          ],
          "solution": "rounded = round(3.7)\nresult = rounded == 4",
          "starter_code": "",
          "test_code": "assert isinstance(rounded, (int, float)), 'rounded should be a number, got ' + str(type(rounded).__name__)\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "round()",
            "functions"
          ]
        },
        {
          "id": "dt_26",
          "title": "Round to Decimal Places",
          "difficulty": 3,
          "description": "Round 3.14159 to 2 decimal places using round() and store in `rounded_pi`.",
          "hints": [
            "Use round() with a second argument for decimal places",
            "round(3.14159, 2) gives 3.14"
          ],
          "solution": "rounded_pi = round(3.14159, 2)\nresult = rounded_pi == 3.14",
          "starter_code": "",
          "test_code": "assert rounded_pi == 3.14, 'rounded_pi should be 3.14, got ' + str(repr(rounded_pi))\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "round()",
            "precision"
          ]
        },
        {
          "id": "dt_27",
          "title": "Float String Formatting",
          "difficulty": 3,
          "description": "Format the float 99.5 as a string with 1 decimal place using an f-string.",
          "hints": [
            "Use f-string with format specifier: f'{value:.1f}'",
            "The result should be '99.5'"
          ],
          "solution": "value = 99.5\nformatted = f'{value:.1f}'\nresult = formatted == '99.5'",
          "starter_code": "",
          "test_code": "assert value == 99.5, 'value should be 99.5, got ' + str(repr(value))\nassert isinstance(formatted, str), 'formatted should be a string (text), got ' + str(type(formatted).__name__)\nassert len(formatted) > 0, \"formatted should not be empty\"\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "f-strings",
            "format specifiers"
          ]
        },
        {
          "id": "dt_28",
          "title": "Format Currency",
          "difficulty": 3,
          "description": "Create a function `format_price(amount)` that returns a price formatted as '$X.XX' (e.g., $12.50).",
          "hints": [
            "Use an f-string with the format specifier .2f",
            "Prepend '$' to the formatted number"
          ],
          "solution": "def format_price(amount):\n    return f'${amount:.2f}'",
          "starter_code": "",
          "test_code": "assert 'format_price' in dir(), \"Function 'format_price' not defined. Did you write: def format_price(...)?\"\n_r0 = format_price(12.5)\nassert _r0 == '$12.50', 'Test 1: format_price(12.5) returned ' + str(repr(_r0)) + \", expected '$12.50'\"\n_r1 = format_price(100)\nassert _r1 == '$100.00', 'Test 2: format_price(100) returned ' + str(repr(_r1)) + \", expected '$100.00'\"\n_r2 = format_price(3.1)\nassert _r2 == '$3.10', 'Test 3: format_price(3.1) returned ' + str(repr(_r2)) + \", expected '$3.10'\"",
          "concepts": [
            "f-strings",
            "practical formatting"
          ]
        },
        {
          "id": "dt_29",
          "title": "Escape Characters",
          "difficulty": 3,
          "description": "Create a string with a newline using the escape sequence \\n and store in `multi_line`.",
          "hints": [
            "Use \\n for newline within a single-quoted string",
            "The string should be 'Hello\\nWorld' which displays on two lines"
          ],
          "solution": "multi_line = 'Hello\\nWorld'\nresult = multi_line == 'Hello\\nWorld'",
          "starter_code": "",
          "test_code": "assert isinstance(multi_line, str), 'multi_line should be a string (text), got ' + str(type(multi_line).__name__)\nassert len(multi_line) > 0, \"multi_line should not be empty\"\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "escape sequences",
            "\\n"
          ]
        },
        {
          "id": "dt_30",
          "title": "Tab Escape Sequence",
          "difficulty": 3,
          "description": "Create a string with a tab using \\t between two words and store in `tabbed`.",
          "hints": [
            "Use \\t for tab",
            "'Name\\tAge' displays as 'Name' then tab then 'Age'"
          ],
          "solution": "tabbed = 'Name\\tAge'\nresult = '\\t' in tabbed",
          "starter_code": "",
          "test_code": "assert isinstance(tabbed, str), 'tabbed should be a string (text), got ' + str(type(tabbed).__name__)\nassert len(tabbed) > 0, \"tabbed should not be empty\"\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "escape sequences",
            "\\t"
          ]
        },
        {
          "id": "dt_31",
          "title": "Multiline String with Triple Quotes",
          "difficulty": 3,
          "description": "Create a multiline string using triple quotes (''') that spans 3 lines and store in `poem`.",
          "hints": [
            "Use ''' or triple double quotes",
            "You can press Enter to go to the next line inside triple quotes"
          ],
          "solution": "poem = '''Line one\nLine two\nLine three'''\nresult = poem.count('\\n') >= 2",
          "starter_code": "",
          "test_code": "assert isinstance(poem, str), 'poem should be a string (text), got ' + str(type(poem).__name__)\nassert len(poem) > 0, \"poem should not be empty\"\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "multiline strings",
            "triple quotes"
          ]
        },
        {
          "id": "dt_32",
          "title": "Complex Number Basics",
          "difficulty": 3,
          "description": "Create a complex number with real part 3 and imaginary part 4 and store in `c`.",
          "hints": [
            "Use 3 + 4j notation for complex numbers",
            "The j represents the imaginary unit (not i)"
          ],
          "solution": "c = 3 + 4j\nresult = c.real == 3 and c.imag == 4",
          "starter_code": "",
          "test_code": "assert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "complex numbers",
            "imaginary unit"
          ]
        },
        {
          "id": "dt_33",
          "title": "Check Boolean Truthiness",
          "difficulty": 3,
          "description": "In Python, determine which of these is falsy: 0, '', None, and []. Check if 0 is falsy by storing `bool(0)` in `is_falsy`.",
          "hints": [
            "Use bool() to check truthiness",
            "0 converts to False"
          ],
          "solution": "is_falsy = bool(0) == False\nresult = is_falsy",
          "starter_code": "",
          "test_code": "assert isinstance(is_falsy, bool), 'is_falsy should be a boolean (True/False), got ' + str(type(is_falsy).__name__)\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "truthiness",
            "falsy values"
          ]
        },
        {
          "id": "dt_34",
          "title": "None Type Basics",
          "difficulty": 3,
          "description": "Create a variable `x = None` and check its type using type().",
          "hints": [
            "None is a special keyword in Python",
            "type(None) is NoneType"
          ],
          "solution": "x = None\nresult = x is None and type(x) == type(None)",
          "starter_code": "",
          "test_code": "assert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "None",
            "null value"
          ]
        },
        {
          "id": "dt_35",
          "title": "Character Code with ord()",
          "difficulty": 3,
          "description": "Find the Unicode code point of 'A' using ord() and store in `code`.",
          "hints": [
            "ord() converts a character to its Unicode value",
            "ord('A') is 65"
          ],
          "solution": "code = ord('A')\nresult = code == 65",
          "starter_code": "",
          "test_code": "assert isinstance(code, (int, float)), 'code should be a number, got ' + str(type(code).__name__)\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "ord()",
            "Unicode"
          ]
        },
        {
          "id": "dt_36",
          "title": "Character from Code with chr()",
          "difficulty": 4,
          "description": "Convert the Unicode code point 65 back to a character using chr() and store in `char`.",
          "hints": [
            "chr() is the inverse of ord()",
            "chr(65) gives 'A'"
          ],
          "solution": "char = chr(65)\nresult = char == 'A'",
          "starter_code": "",
          "test_code": "assert isinstance(char, str), 'char should be a string (text), got ' + str(type(char).__name__)\nassert len(char) > 0, \"char should not be empty\"\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "chr()",
            "Unicode"
          ]
        },
        {
          "id": "dt_37",
          "title": "Temperature Conversion Function",
          "difficulty": 4,
          "description": "Create a function `celsius_to_fahrenheit(c)` that converts Celsius to Fahrenheit using the formula F = C * 9/5 + 32.",
          "hints": [
            "Use the exact formula: (celsius * 9/5) + 32",
            "0°C should equal 32°F"
          ],
          "solution": "def celsius_to_fahrenheit(c):\n    return c * 9/5 + 32",
          "starter_code": "",
          "test_code": "assert 'celsius_to_fahrenheit' in dir(), \"Function 'celsius_to_fahrenheit' not defined. Did you write: def celsius_to_fahrenheit(...)?\"\n_r0 = celsius_to_fahrenheit(0)\nassert _r0 == 32, 'Test 1: celsius_to_fahrenheit(0) returned ' + str(repr(_r0)) + ', expected 32'\n_r1 = celsius_to_fahrenheit(100)\nassert _r1 == 212, 'Test 2: celsius_to_fahrenheit(100) returned ' + str(repr(_r1)) + ', expected 212'\n_r2 = celsius_to_fahrenheit(-40)\nassert _r2 == -40, 'Test 3: celsius_to_fahrenheit(-40) returned ' + str(repr(_r2)) + ', expected -40'",
          "concepts": [
            "numeric operations",
            "formulas"
          ]
        },
        {
          "id": "dt_38",
          "title": "Validate Email Format",
          "difficulty": 4,
          "description": "Create a function `is_valid_email(email)` that returns True if the string contains exactly one '@' and at least one '.' after the '@'.",
          "hints": [
            "Use string methods like count() and find()",
            "Check that '@' appears exactly once and '.' appears after it"
          ],
          "solution": "def is_valid_email(email):\n    return email.count('@') == 1 and '.' in email.split('@')[1]",
          "starter_code": "",
          "test_code": "assert 'is_valid_email' in dir(), \"Function 'is_valid_email' not defined. Did you write: def is_valid_email(...)?\"\n_r0 = is_valid_email('test@example.com')\nassert _r0 == True, \"Test 1: is_valid_email('test@example.com') returned \" + str(repr(_r0)) + ', expected True'\n_r1 = is_valid_email('invalid@email')\nassert _r1 == False, \"Test 2: is_valid_email('invalid@email') returned \" + str(repr(_r1)) + ', expected False'\n_r2 = is_valid_email('test@@@example.com')\nassert _r2 == False, \"Test 3: is_valid_email('test@@@example.com') returned \" + str(repr(_r2)) + ', expected False'\n_r3 = is_valid_email('notanemail.com')\nassert _r3 == False, \"Test 4: is_valid_email('notanemail.com') returned \" + str(repr(_r3)) + ', expected False'",
          "concepts": [
            "string validation",
            "string methods"
          ]
        },
        {
          "id": "dt_39",
          "title": "Reverse a String",
          "difficulty": 4,
          "description": "Create a function `reverse_string(s)` that returns the string reversed using slicing.",
          "hints": [
            "Use slice notation with negative step: s[::-1]",
            "'hello' reversed is 'olleh'"
          ],
          "solution": "def reverse_string(s):\n    return s[::-1]",
          "starter_code": "",
          "test_code": "assert 'reverse_string' in dir(), \"Function 'reverse_string' not defined. Did you write: def reverse_string(...)?\"\n_r0 = reverse_string('hello')\nassert _r0 == 'olleh', \"Test 1: reverse_string('hello') returned \" + str(repr(_r0)) + \", expected 'olleh'\"\n_r1 = reverse_string('Python')\nassert _r1 == 'nohtyP', \"Test 2: reverse_string('Python') returned \" + str(repr(_r1)) + \", expected 'nohtyP'\"\n_r2 = reverse_string('a')\nassert _r2 == 'a', \"Test 3: reverse_string('a') returned \" + str(repr(_r2)) + \", expected 'a'\"",
          "concepts": [
            "string slicing",
            "string manipulation"
          ]
        },
        {
          "id": "dt_40",
          "title": "Count Vowels in String",
          "difficulty": 4,
          "description": "Create a function `count_vowels(text)` that returns the number of vowels (a, e, i, o, u) in the text (case-insensitive).",
          "hints": [
            "Convert to lowercase first with .lower()",
            "Loop through characters and count those in 'aeiou'"
          ],
          "solution": "def count_vowels(text):\n    return sum(1 for c in text.lower() if c in 'aeiou')",
          "starter_code": "",
          "test_code": "assert 'count_vowels' in dir(), \"Function 'count_vowels' not defined. Did you write: def count_vowels(...)?\"\n_r0 = count_vowels('Hello')\nassert _r0 == 2, \"Test 1: count_vowels('Hello') returned \" + str(repr(_r0)) + ', expected 2'\n_r1 = count_vowels('AEIOUaeiou')\nassert _r1 == 10, \"Test 2: count_vowels('AEIOUaeiou') returned \" + str(repr(_r1)) + ', expected 10'\n_r2 = count_vowels('xyz')\nassert _r2 == 0, \"Test 3: count_vowels('xyz') returned \" + str(repr(_r2)) + ', expected 0'",
          "concepts": [
            "string iteration",
            "counting"
          ]
        },
        {
          "id": "dt_41",
          "title": "Parse Integer from String with Error Handling",
          "difficulty": 4,
          "description": "Create a function `safe_int(value)` that converts a string to int, returning -1 if conversion fails.",
          "hints": [
            "Use try/except to catch ValueError",
            "Return the converted integer or -1 on error"
          ],
          "solution": "def safe_int(value):\n    try:\n        return int(value)\n    except ValueError:\n        return -1",
          "starter_code": "",
          "test_code": "assert 'safe_int' in dir(), \"Function 'safe_int' not defined. Did you write: def safe_int(...)?\"\n_r0 = safe_int('123')\nassert _r0 == 123, \"Test 1: safe_int('123') returned \" + str(repr(_r0)) + ', expected 123'\n_r1 = safe_int('abc')\nassert _r1 == -1, \"Test 2: safe_int('abc') returned \" + str(repr(_r1)) + ', expected -1'\n_r2 = safe_int('45.6')\nassert _r2 == -1, \"Test 3: safe_int('45.6') returned \" + str(repr(_r2)) + ', expected -1'",
          "concepts": [
            "type conversion",
            "error handling"
          ]
        },
        {
          "id": "dt_42",
          "title": "Truncate Float to N Decimals",
          "difficulty": 4,
          "description": "Create a function `truncate_float(value, decimals)` that truncates (not rounds) a float to N decimal places.",
          "hints": [
            "Use int() and multiplication: int(value * 10**decimals) / 10**decimals",
            "3.14159 truncated to 2 places is 3.14, not 3.15"
          ],
          "solution": "def truncate_float(value, decimals):\n    multiplier = 10 ** decimals\n    return int(value * multiplier) / multiplier",
          "starter_code": "",
          "test_code": "assert 'truncate_float' in dir(), \"Function 'truncate_float' not defined. Did you write: def truncate_float(...)?\"\n_r0 = truncate_float(3.14159, 2)\nassert _r0 == 3.14, 'Test 1: truncate_float(3.14159, 2) returned ' + str(repr(_r0)) + ', expected 3.14'\n_r1 = truncate_float(99.9999, 1)\nassert _r1 == 99.9, 'Test 2: truncate_float(99.9999, 1) returned ' + str(repr(_r1)) + ', expected 99.9'\n_r2 = truncate_float(5, 2)\nassert _r2 == 5.0, 'Test 3: truncate_float(5, 2) returned ' + str(repr(_r2)) + ', expected 5.0'",
          "concepts": [
            "numeric precision",
            "type conversion"
          ]
        },
        {
          "id": "dt_43",
          "title": "Check if String is Numeric",
          "difficulty": 4,
          "description": "Create a function `is_numeric(s)` that returns True if the string can be converted to a float.",
          "hints": [
            "Try converting with float() and catch ValueError",
            "Handle both integers and floats: '123' and '3.14' should both return True"
          ],
          "solution": "def is_numeric(s):\n    try:\n        float(s)\n        return True\n    except ValueError:\n        return False",
          "starter_code": "",
          "test_code": "assert 'is_numeric' in dir(), \"Function 'is_numeric' not defined. Did you write: def is_numeric(...)?\"\n_r0 = is_numeric('123')\nassert _r0 == True, \"Test 1: is_numeric('123') returned \" + str(repr(_r0)) + ', expected True'\n_r1 = is_numeric('3.14')\nassert _r1 == True, \"Test 2: is_numeric('3.14') returned \" + str(repr(_r1)) + ', expected True'\n_r2 = is_numeric('abc')\nassert _r2 == False, \"Test 3: is_numeric('abc') returned \" + str(repr(_r2)) + ', expected False'\n_r3 = is_numeric('12.34.56')\nassert _r3 == False, \"Test 4: is_numeric('12.34.56') returned \" + str(repr(_r3)) + ', expected False'",
          "concepts": [
            "string validation",
            "type conversion"
          ]
        },
        {
          "id": "dt_44",
          "title": "Extract Numbers from String",
          "difficulty": 4,
          "description": "Create a function `extract_digits(text)` that returns a string containing only the digits from the input.",
          "hints": [
            "Use a loop or generator to filter characters",
            "Check if c.isdigit() for each character"
          ],
          "solution": "def extract_digits(text):\n    return ''.join(c for c in text if c.isdigit())",
          "starter_code": "",
          "test_code": "assert 'extract_digits' in dir(), \"Function 'extract_digits' not defined. Did you write: def extract_digits(...)?\"\n_r0 = extract_digits('abc123def456')\nassert _r0 == '123456', \"Test 1: extract_digits('abc123def456') returned \" + str(repr(_r0)) + \", expected '123456'\"\n_r1 = extract_digits('no digits here')\nassert _r1 == '', \"Test 2: extract_digits('no digits here') returned \" + str(repr(_r1)) + \", expected ''\"\n_r2 = extract_digits('2024-04-08')\nassert _r2 == '20240408', \"Test 3: extract_digits('2024-04-08') returned \" + str(repr(_r2)) + \", expected '20240408'\"",
          "concepts": [
            "string filtering",
            "character methods"
          ]
        },
        {
          "id": "dt_45",
          "title": "Capitalize First Letter Only",
          "difficulty": 4,
          "description": "Create a function `capitalize_first(text)` that capitalizes only the first character, leaving the rest unchanged.",
          "hints": [
            "Use indexing and slicing: text[0].upper() + text[1:]",
            "Handle empty strings gracefully"
          ],
          "solution": "def capitalize_first(text):\n    return text[0].upper() + text[1:] if text else text",
          "starter_code": "",
          "test_code": "assert 'capitalize_first' in dir(), \"Function 'capitalize_first' not defined. Did you write: def capitalize_first(...)?\"\n_r0 = capitalize_first('hello world')\nassert _r0 == 'Hello world', \"Test 1: capitalize_first('hello world') returned \" + str(repr(_r0)) + \", expected 'Hello world'\"\n_r1 = capitalize_first('HELLO')\nassert _r1 == 'HELLO', \"Test 2: capitalize_first('HELLO') returned \" + str(repr(_r1)) + \", expected 'HELLO'\"\n_r2 = capitalize_first('a')\nassert _r2 == 'A', \"Test 3: capitalize_first('a') returned \" + str(repr(_r2)) + \", expected 'A'\"",
          "concepts": [
            "string slicing",
            "string methods"
          ]
        },
        {
          "id": "dt_46",
          "title": "Format Large Numbers with Commas",
          "difficulty": 5,
          "description": "Create a function `format_number(n)` that formats an integer with thousand separators, e.g., 1000000 becomes '1,000,000'.",
          "hints": [
            "Use Python's built-in format() function or string method",
            "format(1000000, ',') works, or use f'{n:,}'"
          ],
          "solution": "def format_number(n):\n    return f'{n:,}'",
          "starter_code": "",
          "test_code": "assert 'format_number' in dir(), \"Function 'format_number' not defined. Did you write: def format_number(...)?\"\n_r0 = format_number(1000)\nassert _r0 == '1,000', 'Test 1: format_number(1000) returned ' + str(repr(_r0)) + \", expected '1,000'\"\n_r1 = format_number(1000000)\nassert _r1 == '1,000,000', 'Test 2: format_number(1000000) returned ' + str(repr(_r1)) + \", expected '1,000,000'\"\n_r2 = format_number(42)\nassert _r2 == '42', 'Test 3: format_number(42) returned ' + str(repr(_r2)) + \", expected '42'\"",
          "concepts": [
            "number formatting",
            "format specifiers"
          ]
        },
        {
          "id": "dt_47",
          "title": "Build Query String from Dictionary",
          "difficulty": 5,
          "description": "Create a function `build_query_string(params)` that takes a dictionary and returns a URL query string, e.g., {'name': 'Alice', 'age': 30} becomes 'name=Alice&age=30'.",
          "hints": [
            "Iterate through dictionary items",
            "Join with '&' separator and use '=' between key and value"
          ],
          "solution": "def build_query_string(params):\n    return '&'.join(f'{k}={v}' for k, v in params.items())",
          "starter_code": "",
          "test_code": "assert 'build_query_string' in dir(), \"Function 'build_query_string' not defined. Did you write: def build_query_string(...)?\"\n_r0 = build_query_string({'name': 'Alice', 'age': '30'})\nassert _r0 == 'name=Alice&age=30', \"Test 1: build_query_string({'name': 'Alice', 'age': '30'}) returned \" + str(repr(_r0)) + \", expected 'name=Alice&age=30'\"\n_r1 = build_query_string({'x': '1'})\nassert _r1 == 'x=1', \"Test 2: build_query_string({'x': '1'}) returned \" + str(repr(_r1)) + \", expected 'x=1'\"",
          "concepts": [
            "string building",
            "dict iteration"
          ]
        },
        {
          "id": "dt_48",
          "title": "Type-Based Processing",
          "difficulty": 5,
          "description": "Create a function `describe_value(val)` that returns a description string based on the type: 'int' for int, 'float' for float, 'str' for str, or 'other' for anything else.",
          "hints": [
            "Use type() or isinstance() to check types",
            "Return appropriate strings based on the type"
          ],
          "solution": "def describe_value(val):\n    if isinstance(val, bool):\n        return 'bool'\n    elif isinstance(val, int):\n        return 'int'\n    elif isinstance(val, float):\n        return 'float'\n    elif isinstance(val, str):\n        return 'str'\n    else:\n        return 'other'",
          "starter_code": "",
          "test_code": "assert 'describe_value' in dir(), \"Function 'describe_value' not defined. Did you write: def describe_value(...)?\"\n_r0 = describe_value(42)\nassert _r0 == 'int', 'Test 1: describe_value(42) returned ' + str(repr(_r0)) + \", expected 'int'\"\n_r1 = describe_value(3.14)\nassert _r1 == 'float', 'Test 2: describe_value(3.14) returned ' + str(repr(_r1)) + \", expected 'float'\"\n_r2 = describe_value('hello')\nassert _r2 == 'str', \"Test 3: describe_value('hello') returned \" + str(repr(_r2)) + \", expected 'str'\"\n_r3 = describe_value(True)\nassert _r3 == 'bool', 'Test 4: describe_value(True) returned ' + str(repr(_r3)) + \", expected 'bool'\"\n_r4 = describe_value([])\nassert _r4 == 'other', 'Test 5: describe_value([]) returned ' + str(repr(_r4)) + \", expected 'other'\"",
          "concepts": [
            "type checking",
            "isinstance()"
          ]
        },
        {
          "id": "dt_49",
          "title": "Parse CSV Line into Typed Values",
          "difficulty": 5,
          "description": "Create a function `parse_csv_line(line, types)` that splits a CSV line and converts each field to the specified type. E.g., parse_csv_line('1,3.14,hello', [int, float, str]) returns [1, 3.14, 'hello'].",
          "hints": [
            "Use split(',') to split the line",
            "Use a list comprehension to convert each value with its type",
            "handle the conversion: type(value_string)"
          ],
          "solution": "def parse_csv_line(line, types):\n    values = line.split(',')\n    return [t(v) for t, v in zip(types, values)]",
          "starter_code": "",
          "test_code": "assert 'parse_csv_line' in dir(), \"Function 'parse_csv_line' not defined. Did you write: def parse_csv_line(...)?\"\n_r0 = parse_csv_line('1,3.14,hello', [int, float, str])\nassert _r0 == [1, 3.14, 'hello'], \"Test 1: parse_csv_line('1,3.14,hello', [int, float, str]) returned \" + str(repr(_r0)) + \", expected [1, 3.14, 'hello']\"\n_r1 = parse_csv_line('42,true,test', [int, str, str])\nassert _r1 == [42, 'true', 'test'], \"Test 2: parse_csv_line('42,true,test', [int, str, str]) returned \" + str(repr(_r1)) + \", expected [42, 'true', 'test']\"",
          "concepts": [
            "type conversion",
            "list comprehension"
          ]
        },
        {
          "id": "dt_50",
          "title": "Robust Type Conversion Pipeline",
          "difficulty": 5,
          "description": "Create a function `safe_convert(value, target_type)` that attempts to convert value to target_type, returning None on any error. It should handle int, float, str, and bool types.",
          "hints": [
            "Use try/except for each type conversion",
            "For bool, convert non-empty strings and non-zero numbers to True",
            "Return None if conversion fails"
          ],
          "solution": "def safe_convert(value, target_type):\n    try:\n        if target_type == bool:\n            if isinstance(value, bool):\n                return value\n            if isinstance(value, str):\n                return value.lower() in ('true', '1', 'yes')\n            return bool(value)\n        return target_type(value)\n    except (ValueError, TypeError):\n        return None",
          "starter_code": "",
          "test_code": "assert 'safe_convert' in dir(), \"Function 'safe_convert' not defined. Did you write: def safe_convert(...)?\"\n_r0 = safe_convert('123', int)\nassert _r0 == 123, \"Test 1: safe_convert('123', int) returned \" + str(repr(_r0)) + ', expected 123'\n_r1 = safe_convert('3.14', float)\nassert _r1 == 3.14, \"Test 2: safe_convert('3.14', float) returned \" + str(repr(_r1)) + ', expected 3.14'\n_r2 = safe_convert('hello', str)\nassert _r2 == 'hello', \"Test 3: safe_convert('hello', str) returned \" + str(repr(_r2)) + \", expected 'hello'\"\n_r3 = safe_convert('abc', int)\nassert _r3 == None, \"Test 4: safe_convert('abc', int) returned \" + str(repr(_r3)) + ', expected None'\n_r4 = safe_convert('true', bool)\nassert _r4 == True, \"Test 5: safe_convert('true', bool) returned \" + str(repr(_r4)) + ', expected True'",
          "concepts": [
            "type conversion",
            "error handling",
            "practical processing"
          ]
        }
      ]
    },
    {
      "id": "conditionals",
      "title": "Conditionals",
      "exercise_count": 50,
      "exercises": [
        {
          "id": "cond_01",
          "title": "Simple if statement",
          "difficulty": 1,
          "description": "Write a function that returns True if a number is positive, False otherwise.",
          "hints": [
            "Use the > operator to compare with 0",
            "Return the result of the comparison directly"
          ],
          "solution": "def is_positive(n):\n    return n > 0",
          "starter_code": "",
          "test_code": "assert 'is_positive' in dir(), \"Function 'is_positive' not defined. Did you write: def is_positive(...)?\"\n_r0 = is_positive(5)\nassert _r0 == True, 'Test 1: is_positive(5) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = is_positive(-3)\nassert _r1 == False, 'Test 2: is_positive(-3) returned ' + str(repr(_r1)) + ', expected False'\n_r2 = is_positive(0)\nassert _r2 == False, 'Test 3: is_positive(0) returned ' + str(repr(_r2)) + ', expected False'\n_r3 = is_positive(100)\nassert _r3 == True, 'Test 4: is_positive(100) returned ' + str(repr(_r3)) + ', expected True'",
          "concepts": []
        },
        {
          "id": "cond_02",
          "title": "if/else with equality",
          "difficulty": 1,
          "description": "Write a function that returns 'even' if a number is even, 'odd' if odd.",
          "hints": [
            "Use the modulo operator % to check remainder when divided by 2",
            "n % 2 == 0 means the number is even"
          ],
          "solution": "def even_or_odd(n):\n    if n % 2 == 0:\n        return 'even'\n    else:\n        return 'odd'",
          "starter_code": "",
          "test_code": "assert 'even_or_odd' in dir(), \"Function 'even_or_odd' not defined. Did you write: def even_or_odd(...)?\"\n_r0 = even_or_odd(4)\nassert _r0 == 'even', 'Test 1: even_or_odd(4) returned ' + str(repr(_r0)) + \", expected 'even'\"\n_r1 = even_or_odd(7)\nassert _r1 == 'odd', 'Test 2: even_or_odd(7) returned ' + str(repr(_r1)) + \", expected 'odd'\"\n_r2 = even_or_odd(0)\nassert _r2 == 'even', 'Test 3: even_or_odd(0) returned ' + str(repr(_r2)) + \", expected 'even'\"\n_r3 = even_or_odd(13)\nassert _r3 == 'odd', 'Test 4: even_or_odd(13) returned ' + str(repr(_r3)) + \", expected 'odd'\"",
          "concepts": []
        },
        {
          "id": "cond_03",
          "title": "Comparison: less than and greater than",
          "difficulty": 1,
          "description": "Write a function that returns 'hot' if temperature >= 30, 'cold' if < 10, 'mild' otherwise.",
          "hints": [
            "Use >= for greater-than-or-equal",
            "Use < for less-than",
            "Consider order of conditions carefully"
          ],
          "solution": "def temperature_description(temp):\n    if temp >= 30:\n        return 'hot'\n    elif temp < 10:\n        return 'cold'\n    else:\n        return 'mild'",
          "starter_code": "",
          "test_code": "assert 'temperature_description' in dir(), \"Function 'temperature_description' not defined. Did you write: def temperature_description(...)?\"\n_r0 = temperature_description(35)\nassert _r0 == 'hot', 'Test 1: temperature_description(35) returned ' + str(repr(_r0)) + \", expected 'hot'\"\n_r1 = temperature_description(5)\nassert _r1 == 'cold', 'Test 2: temperature_description(5) returned ' + str(repr(_r1)) + \", expected 'cold'\"\n_r2 = temperature_description(20)\nassert _r2 == 'mild', 'Test 3: temperature_description(20) returned ' + str(repr(_r2)) + \", expected 'mild'\"\n_r3 = temperature_description(30)\nassert _r3 == 'hot', 'Test 4: temperature_description(30) returned ' + str(repr(_r3)) + \", expected 'hot'\"\n_r4 = temperature_description(9)\nassert _r4 == 'cold', 'Test 5: temperature_description(9) returned ' + str(repr(_r4)) + \", expected 'cold'\"",
          "concepts": []
        },
        {
          "id": "cond_04",
          "title": "Inequality operator !=",
          "difficulty": 1,
          "description": "Write a function that returns True if a string is not 'admin', False otherwise.",
          "hints": [
            "Use the != operator for 'not equal'",
            "String comparison with == and != is case-sensitive"
          ],
          "solution": "def is_not_admin(username):\n    return username != 'admin'",
          "starter_code": "",
          "test_code": "assert 'is_not_admin' in dir(), \"Function 'is_not_admin' not defined. Did you write: def is_not_admin(...)?\"\n_r0 = is_not_admin('user')\nassert _r0 == True, \"Test 1: is_not_admin('user') returned \" + str(repr(_r0)) + ', expected True'\n_r1 = is_not_admin('admin')\nassert _r1 == False, \"Test 2: is_not_admin('admin') returned \" + str(repr(_r1)) + ', expected False'\n_r2 = is_not_admin('Admin')\nassert _r2 == True, \"Test 3: is_not_admin('Admin') returned \" + str(repr(_r2)) + ', expected True'\n_r3 = is_not_admin('guest')\nassert _r3 == True, \"Test 4: is_not_admin('guest') returned \" + str(repr(_r3)) + ', expected True'",
          "concepts": []
        },
        {
          "id": "cond_05",
          "title": "if/elif/else chain with multiple conditions",
          "difficulty": 1,
          "description": "Write a function that returns a size category: 'small' (< 5), 'medium' (5-10), 'large' (> 10).",
          "hints": [
            "Use < for less than and > for greater than",
            "elif handles the middle condition",
            "Order matters: check small first, then medium, then large"
          ],
          "solution": "def size_category(value):\n    if value < 5:\n        return 'small'\n    elif value <= 10:\n        return 'medium'\n    else:\n        return 'large'",
          "starter_code": "",
          "test_code": "assert 'size_category' in dir(), \"Function 'size_category' not defined. Did you write: def size_category(...)?\"\n_r0 = size_category(2)\nassert _r0 == 'small', 'Test 1: size_category(2) returned ' + str(repr(_r0)) + \", expected 'small'\"\n_r1 = size_category(5)\nassert _r1 == 'medium', 'Test 2: size_category(5) returned ' + str(repr(_r1)) + \", expected 'medium'\"\n_r2 = size_category(10)\nassert _r2 == 'medium', 'Test 3: size_category(10) returned ' + str(repr(_r2)) + \", expected 'medium'\"\n_r3 = size_category(15)\nassert _r3 == 'large', 'Test 4: size_category(15) returned ' + str(repr(_r3)) + \", expected 'large'\"",
          "concepts": []
        },
        {
          "id": "cond_06",
          "title": "Boolean return from comparison",
          "difficulty": 1,
          "description": "Write a function that returns True if a number is between 1 and 100 inclusive, False otherwise.",
          "hints": [
            "You need to check two conditions: >= 1 AND <= 100",
            "You can use 'and' or write two separate comparisons",
            "Return the boolean result directly"
          ],
          "solution": "def is_in_range(n):\n    return 1 <= n <= 100",
          "starter_code": "",
          "test_code": "assert 'is_in_range' in dir(), \"Function 'is_in_range' not defined. Did you write: def is_in_range(...)?\"\n_r0 = is_in_range(50)\nassert _r0 == True, 'Test 1: is_in_range(50) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = is_in_range(1)\nassert _r1 == True, 'Test 2: is_in_range(1) returned ' + str(repr(_r1)) + ', expected True'\n_r2 = is_in_range(100)\nassert _r2 == True, 'Test 3: is_in_range(100) returned ' + str(repr(_r2)) + ', expected True'\n_r3 = is_in_range(0)\nassert _r3 == False, 'Test 4: is_in_range(0) returned ' + str(repr(_r3)) + ', expected False'\n_r4 = is_in_range(101)\nassert _r4 == False, 'Test 5: is_in_range(101) returned ' + str(repr(_r4)) + ', expected False'",
          "concepts": []
        },
        {
          "id": "cond_07",
          "title": "Basic logical AND",
          "difficulty": 1,
          "description": "Write a function that returns True if a number is even AND positive, False otherwise.",
          "hints": [
            "Use 'and' to combine two conditions",
            "Check n > 0 and n % 2 == 0",
            "Both conditions must be True for the result to be True"
          ],
          "solution": "def even_and_positive(n):\n    return n > 0 and n % 2 == 0",
          "starter_code": "",
          "test_code": "assert 'even_and_positive' in dir(), \"Function 'even_and_positive' not defined. Did you write: def even_and_positive(...)?\"\n_r0 = even_and_positive(4)\nassert _r0 == True, 'Test 1: even_and_positive(4) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = even_and_positive(2)\nassert _r1 == True, 'Test 2: even_and_positive(2) returned ' + str(repr(_r1)) + ', expected True'\n_r2 = even_and_positive(-2)\nassert _r2 == False, 'Test 3: even_and_positive(-2) returned ' + str(repr(_r2)) + ', expected False'\n_r3 = even_and_positive(3)\nassert _r3 == False, 'Test 4: even_and_positive(3) returned ' + str(repr(_r3)) + ', expected False'\n_r4 = even_and_positive(0)\nassert _r4 == False, 'Test 5: even_and_positive(0) returned ' + str(repr(_r4)) + ', expected False'",
          "concepts": []
        },
        {
          "id": "cond_08",
          "title": "Basic logical OR",
          "difficulty": 1,
          "description": "Write a function that returns True if a number is less than 0 OR greater than 100, False otherwise.",
          "hints": [
            "Use 'or' to combine two conditions",
            "Check n < 0 or n > 100",
            "At least one condition needs to be True"
          ],
          "solution": "def outside_range(n):\n    return n < 0 or n > 100",
          "starter_code": "",
          "test_code": "assert 'outside_range' in dir(), \"Function 'outside_range' not defined. Did you write: def outside_range(...)?\"\n_r0 = outside_range(-5)\nassert _r0 == True, 'Test 1: outside_range(-5) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = outside_range(150)\nassert _r1 == True, 'Test 2: outside_range(150) returned ' + str(repr(_r1)) + ', expected True'\n_r2 = outside_range(50)\nassert _r2 == False, 'Test 3: outside_range(50) returned ' + str(repr(_r2)) + ', expected False'\n_r3 = outside_range(0)\nassert _r3 == False, 'Test 4: outside_range(0) returned ' + str(repr(_r3)) + ', expected False'\n_r4 = outside_range(100)\nassert _r4 == False, 'Test 5: outside_range(100) returned ' + str(repr(_r4)) + ', expected False'",
          "concepts": []
        },
        {
          "id": "cond_09",
          "title": "NOT operator",
          "difficulty": 1,
          "description": "Write a function that returns True if a string is empty (length 0), False otherwise.",
          "hints": [
            "Use 'not' to negate a boolean",
            "len(s) == 0 checks if string is empty",
            "You could also use: not s"
          ],
          "solution": "def is_empty(s):\n    return len(s) == 0",
          "starter_code": "",
          "test_code": "assert 'is_empty' in dir(), \"Function 'is_empty' not defined. Did you write: def is_empty(...)?\"\n_r0 = is_empty('')\nassert _r0 == True, \"Test 1: is_empty('') returned \" + str(repr(_r0)) + ', expected True'\n_r1 = is_empty('hello')\nassert _r1 == False, \"Test 2: is_empty('hello') returned \" + str(repr(_r1)) + ', expected False'\n_r2 = is_empty(' ')\nassert _r2 == False, \"Test 3: is_empty(' ') returned \" + str(repr(_r2)) + ', expected False'",
          "concepts": []
        },
        {
          "id": "cond_10",
          "title": "Truthiness of values",
          "difficulty": 1,
          "description": "Write a function that returns True if a value is truthy (0, empty string, None, False are falsy), False if falsy.",
          "hints": [
            "Empty collections, 0, None, and False are falsy",
            "Non-zero numbers and non-empty strings are truthy",
            "Use 'if value:' to check truthiness"
          ],
          "solution": "def is_truthy(value):\n    return bool(value)",
          "starter_code": "",
          "test_code": "assert 'is_truthy' in dir(), \"Function 'is_truthy' not defined. Did you write: def is_truthy(...)?\"\n_r0 = is_truthy(1)\nassert _r0 == True, 'Test 1: is_truthy(1) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = is_truthy(0)\nassert _r1 == False, 'Test 2: is_truthy(0) returned ' + str(repr(_r1)) + ', expected False'\n_r2 = is_truthy('hello')\nassert _r2 == True, \"Test 3: is_truthy('hello') returned \" + str(repr(_r2)) + ', expected True'\n_r3 = is_truthy('')\nassert _r3 == False, \"Test 4: is_truthy('') returned \" + str(repr(_r3)) + ', expected False'\n_r4 = is_truthy(None)\nassert _r4 == False, 'Test 5: is_truthy(None) returned ' + str(repr(_r4)) + ', expected False'",
          "concepts": []
        },
        {
          "id": "cond_11",
          "title": "Nested if statements",
          "difficulty": 2,
          "description": "Write a function that returns 'adult' if age >= 18 and has_id is True, 'minor' otherwise.",
          "hints": [
            "Use a nested if: first check age, then check has_id inside",
            "Both conditions must be True to return 'adult'",
            "Remember boolean parameters are either True or False"
          ],
          "solution": "def check_adult(age, has_id):\n    if age >= 18:\n        if has_id:\n            return 'adult'\n    return 'minor'",
          "starter_code": "",
          "test_code": "assert 'check_adult' in dir(), \"Function 'check_adult' not defined. Did you write: def check_adult(...)?\"\n_r0 = check_adult(25, True)\nassert _r0 == 'adult', 'Test 1: check_adult(25, True) returned ' + str(repr(_r0)) + \", expected 'adult'\"\n_r1 = check_adult(25, False)\nassert _r1 == 'minor', 'Test 2: check_adult(25, False) returned ' + str(repr(_r1)) + \", expected 'minor'\"\n_r2 = check_adult(16, True)\nassert _r2 == 'minor', 'Test 3: check_adult(16, True) returned ' + str(repr(_r2)) + \", expected 'minor'\"\n_r3 = check_adult(18, True)\nassert _r3 == 'adult', 'Test 4: check_adult(18, True) returned ' + str(repr(_r3)) + \", expected 'adult'\"",
          "concepts": []
        },
        {
          "id": "cond_12",
          "title": "Ternary expression (inline if/else)",
          "difficulty": 2,
          "description": "Write a function that returns 'pass' if score >= 50 else 'fail' using a ternary expression.",
          "hints": [
            "Use: x if condition else y syntax",
            "This is a one-liner alternative to if/else",
            "Read it as: 'x (if condition is true) else y'"
          ],
          "solution": "def pass_or_fail(score):\n    return 'pass' if score >= 50 else 'fail'",
          "starter_code": "",
          "test_code": "assert 'pass_or_fail' in dir(), \"Function 'pass_or_fail' not defined. Did you write: def pass_or_fail(...)?\"\n_r0 = pass_or_fail(50)\nassert _r0 == 'pass', 'Test 1: pass_or_fail(50) returned ' + str(repr(_r0)) + \", expected 'pass'\"\n_r1 = pass_or_fail(75)\nassert _r1 == 'pass', 'Test 2: pass_or_fail(75) returned ' + str(repr(_r1)) + \", expected 'pass'\"\n_r2 = pass_or_fail(30)\nassert _r2 == 'fail', 'Test 3: pass_or_fail(30) returned ' + str(repr(_r2)) + \", expected 'fail'\"\n_r3 = pass_or_fail(49)\nassert _r3 == 'fail', 'Test 4: pass_or_fail(49) returned ' + str(repr(_r3)) + \", expected 'fail'\"",
          "concepts": []
        },
        {
          "id": "cond_13",
          "title": "Chained comparisons",
          "difficulty": 2,
          "description": "Write a function that returns True if a number is strictly between 10 and 20 (exclusive), False otherwise.",
          "hints": [
            "Use chained comparison: 10 < n < 20",
            "This is more readable than (n > 10 and n < 20)",
            "Works for any number of comparisons"
          ],
          "solution": "def is_between_10_and_20(n):\n    return 10 < n < 20",
          "starter_code": "",
          "test_code": "assert 'is_between_10_and_20' in dir(), \"Function 'is_between_10_and_20' not defined. Did you write: def is_between_10_and_20(...)?\"\n_r0 = is_between_10_and_20(15)\nassert _r0 == True, 'Test 1: is_between_10_and_20(15) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = is_between_10_and_20(10)\nassert _r1 == False, 'Test 2: is_between_10_and_20(10) returned ' + str(repr(_r1)) + ', expected False'\n_r2 = is_between_10_and_20(20)\nassert _r2 == False, 'Test 3: is_between_10_and_20(20) returned ' + str(repr(_r2)) + ', expected False'\n_r3 = is_between_10_and_20(5)\nassert _r3 == False, 'Test 4: is_between_10_and_20(5) returned ' + str(repr(_r3)) + ', expected False'\n_r4 = is_between_10_and_20(25)\nassert _r4 == False, 'Test 5: is_between_10_and_20(25) returned ' + str(repr(_r4)) + ', expected False'",
          "concepts": []
        },
        {
          "id": "cond_14",
          "title": "Multiple elif branches",
          "difficulty": 2,
          "description": "Write a function that returns a day name given a number 1-7 ('Monday', 'Tuesday', etc.).",
          "hints": [
            "Use if/elif/elif... chain for 7 different cases",
            "1='Monday', 2='Tuesday', ..., 7='Sunday'",
            "Return 'Invalid' if the number is outside 1-7"
          ],
          "solution": "def day_name(day_num):\n    if day_num == 1:\n        return 'Monday'\n    elif day_num == 2:\n        return 'Tuesday'\n    elif day_num == 3:\n        return 'Wednesday'\n    elif day_num == 4:\n        return 'Thursday'\n    elif day_num == 5:\n        return 'Friday'\n    elif day_num == 6:\n        return 'Saturday'\n    elif day_num == 7:\n        return 'Sunday'\n    else:\n        return 'Invalid'",
          "starter_code": "",
          "test_code": "assert 'day_name' in dir(), \"Function 'day_name' not defined. Did you write: def day_name(...)?\"\n_r0 = day_name(1)\nassert _r0 == 'Monday', 'Test 1: day_name(1) returned ' + str(repr(_r0)) + \", expected 'Monday'\"\n_r1 = day_name(7)\nassert _r1 == 'Sunday', 'Test 2: day_name(7) returned ' + str(repr(_r1)) + \", expected 'Sunday'\"\n_r2 = day_name(4)\nassert _r2 == 'Thursday', 'Test 3: day_name(4) returned ' + str(repr(_r2)) + \", expected 'Thursday'\"\n_r3 = day_name(8)\nassert _r3 == 'Invalid', 'Test 4: day_name(8) returned ' + str(repr(_r3)) + \", expected 'Invalid'\"",
          "concepts": []
        },
        {
          "id": "cond_15",
          "title": "Complex boolean logic with AND/OR/NOT",
          "difficulty": 2,
          "description": "Write a function that returns True if (age >= 18 AND has_license) OR age >= 16 AND in_driving_school is True.",
          "hints": [
            "Use 'and' and 'or' operators",
            "Parentheses help clarify order: (A and B) or (C and D)",
            "Remember: 'and' has higher precedence than 'or'"
          ],
          "solution": "def can_drive(age, has_license, in_driving_school):\n    return (age >= 18 and has_license) or (age >= 16 and in_driving_school)",
          "starter_code": "",
          "test_code": "assert 'can_drive' in dir(), \"Function 'can_drive' not defined. Did you write: def can_drive(...)?\"\n_r0 = can_drive(20, True, False)\nassert _r0 == True, 'Test 1: can_drive(20, True, False) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = can_drive(17, False, True)\nassert _r1 == True, 'Test 2: can_drive(17, False, True) returned ' + str(repr(_r1)) + ', expected True'\n_r2 = can_drive(18, False, False)\nassert _r2 == False, 'Test 3: can_drive(18, False, False) returned ' + str(repr(_r2)) + ', expected False'\n_r3 = can_drive(16, False, False)\nassert _r3 == False, 'Test 4: can_drive(16, False, False) returned ' + str(repr(_r3)) + ', expected False'",
          "concepts": []
        },
        {
          "id": "cond_16",
          "title": "Guard clause (early return)",
          "difficulty": 2,
          "description": "Write a function that returns 'invalid' if password is empty or less than 6 chars, otherwise 'valid'.",
          "hints": [
            "Use an early return for the invalid case",
            "Check len(password) < 6 or password == ''",
            "Return immediately if condition is True"
          ],
          "solution": "def validate_password(password):\n    if len(password) < 6:\n        return 'invalid'\n    return 'valid'",
          "starter_code": "",
          "test_code": "assert 'validate_password' in dir(), \"Function 'validate_password' not defined. Did you write: def validate_password(...)?\"\n_r0 = validate_password('')\nassert _r0 == 'invalid', \"Test 1: validate_password('') returned \" + str(repr(_r0)) + \", expected 'invalid'\"\n_r1 = validate_password('abc')\nassert _r1 == 'invalid', \"Test 2: validate_password('abc') returned \" + str(repr(_r1)) + \", expected 'invalid'\"\n_r2 = validate_password('123456')\nassert _r2 == 'valid', \"Test 3: validate_password('123456') returned \" + str(repr(_r2)) + \", expected 'valid'\"\n_r3 = validate_password('password')\nassert _r3 == 'valid', \"Test 4: validate_password('password') returned \" + str(repr(_r3)) + \", expected 'valid'\"",
          "concepts": []
        },
        {
          "id": "cond_17",
          "title": "Membership test with 'in'",
          "difficulty": 2,
          "description": "Write a function that returns True if a character is a vowel (a, e, i, o, u), False otherwise.",
          "hints": [
            "Use the 'in' operator: char in 'aeiou'",
            "The 'in' operator checks if a value exists in a collection",
            "Consider case sensitivity; you might want to use .lower()"
          ],
          "solution": "def is_vowel(char):\n    return char.lower() in 'aeiou'",
          "starter_code": "",
          "test_code": "assert 'is_vowel' in dir(), \"Function 'is_vowel' not defined. Did you write: def is_vowel(...)?\"\n_r0 = is_vowel('a')\nassert _r0 == True, \"Test 1: is_vowel('a') returned \" + str(repr(_r0)) + ', expected True'\n_r1 = is_vowel('E')\nassert _r1 == True, \"Test 2: is_vowel('E') returned \" + str(repr(_r1)) + ', expected True'\n_r2 = is_vowel('b')\nassert _r2 == False, \"Test 3: is_vowel('b') returned \" + str(repr(_r2)) + ', expected False'\n_r3 = is_vowel('i')\nassert _r3 == True, \"Test 4: is_vowel('i') returned \" + str(repr(_r3)) + ', expected True'",
          "concepts": []
        },
        {
          "id": "cond_18",
          "title": "Type checking with type()",
          "difficulty": 2,
          "description": "Write a function that returns 'int' if the value is an integer, 'float' if it's a float, 'other' otherwise.",
          "hints": [
            "Use type(value) to get the type",
            "type(5) == int, type(5.0) == float",
            "Be aware: in Python 3, bool is a subclass of int"
          ],
          "solution": "def value_type(value):\n    if isinstance(value, bool):\n        return 'other'\n    elif isinstance(value, int):\n        return 'int'\n    elif isinstance(value, float):\n        return 'float'\n    else:\n        return 'other'",
          "starter_code": "",
          "test_code": "assert 'value_type' in dir(), \"Function 'value_type' not defined. Did you write: def value_type(...)?\"\n_r0 = value_type(5)\nassert _r0 == 'int', 'Test 1: value_type(5) returned ' + str(repr(_r0)) + \", expected 'int'\"\n_r1 = value_type(5.0)\nassert _r1 == 'float', 'Test 2: value_type(5.0) returned ' + str(repr(_r1)) + \", expected 'float'\"\n_r2 = value_type('hello')\nassert _r2 == 'other', \"Test 3: value_type('hello') returned \" + str(repr(_r2)) + \", expected 'other'\"",
          "concepts": []
        },
        {
          "id": "cond_19",
          "title": "Multiple conditions in if",
          "difficulty": 2,
          "description": "Write a function that returns 'valid' if a person's age is 18-65 inclusive, 'invalid' otherwise.",
          "hints": [
            "Check age >= 18 AND age <= 65",
            "You can use: 18 <= age <= 65",
            "Chained comparisons are elegant"
          ],
          "solution": "def is_working_age(age):\n    return 18 <= age <= 65",
          "starter_code": "",
          "test_code": "assert 'is_working_age' in dir(), \"Function 'is_working_age' not defined. Did you write: def is_working_age(...)?\"\n_r0 = is_working_age(25)\nassert _r0 == True, 'Test 1: is_working_age(25) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = is_working_age(18)\nassert _r1 == True, 'Test 2: is_working_age(18) returned ' + str(repr(_r1)) + ', expected True'\n_r2 = is_working_age(65)\nassert _r2 == True, 'Test 3: is_working_age(65) returned ' + str(repr(_r2)) + ', expected True'\n_r3 = is_working_age(17)\nassert _r3 == False, 'Test 4: is_working_age(17) returned ' + str(repr(_r3)) + ', expected False'\n_r4 = is_working_age(66)\nassert _r4 == False, 'Test 5: is_working_age(66) returned ' + str(repr(_r4)) + ', expected False'",
          "concepts": []
        },
        {
          "id": "cond_20",
          "title": "Short-circuit evaluation",
          "difficulty": 2,
          "description": "Write a function that checks if a list is non-empty AND its first element is positive, without IndexError.",
          "hints": [
            "Use 'and' short-circuit: if lst is empty, the second part won't be checked",
            "len(lst) > 0 and lst[0] > 0 is safe because of short-circuit",
            "This avoids IndexError when list is empty"
          ],
          "solution": "def first_is_positive(lst):\n    return len(lst) > 0 and lst[0] > 0",
          "starter_code": "",
          "test_code": "assert 'first_is_positive' in dir(), \"'first_is_positive' is not defined\"\nassert callable(first_is_positive), \"'first_is_positive' should be a function\"",
          "concepts": []
        },
        {
          "id": "cond_21",
          "title": "Grade calculator",
          "difficulty": 3,
          "description": "Write a function that returns a letter grade (A, B, C, D, F) given a numeric score (0-100).",
          "hints": [
            "A: 90-100, B: 80-89, C: 70-79, D: 60-69, F: < 60",
            "Use if/elif/else chain",
            "Consider boundary cases like 90, 80, 70"
          ],
          "solution": "def letter_grade(score):\n    if score >= 90:\n        return 'A'\n    elif score >= 80:\n        return 'B'\n    elif score >= 70:\n        return 'C'\n    elif score >= 60:\n        return 'D'\n    else:\n        return 'F'",
          "starter_code": "",
          "test_code": "assert 'letter_grade' in dir(), \"Function 'letter_grade' not defined. Did you write: def letter_grade(...)?\"\n_r0 = letter_grade(95)\nassert _r0 == 'A', 'Test 1: letter_grade(95) returned ' + str(repr(_r0)) + \", expected 'A'\"\n_r1 = letter_grade(85)\nassert _r1 == 'B', 'Test 2: letter_grade(85) returned ' + str(repr(_r1)) + \", expected 'B'\"\n_r2 = letter_grade(75)\nassert _r2 == 'C', 'Test 3: letter_grade(75) returned ' + str(repr(_r2)) + \", expected 'C'\"\n_r3 = letter_grade(65)\nassert _r3 == 'D', 'Test 4: letter_grade(65) returned ' + str(repr(_r3)) + \", expected 'D'\"\n_r4 = letter_grade(55)\nassert _r4 == 'F', 'Test 5: letter_grade(55) returned ' + str(repr(_r4)) + \", expected 'F'\"\n_r5 = letter_grade(90)\nassert _r5 == 'A', 'Test 6: letter_grade(90) returned ' + str(repr(_r5)) + \", expected 'A'\"",
          "concepts": []
        },
        {
          "id": "cond_22",
          "title": "FizzBuzz (classic)",
          "difficulty": 3,
          "description": "Write a function that returns 'Fizz' if divisible by 3, 'Buzz' if divisible by 5, 'FizzBuzz' if both, otherwise the number as a string.",
          "hints": [
            "Check divisibility using % operator",
            "Check 'both' first (n % 15 == 0)",
            "Order of conditions matters"
          ],
          "solution": "def fizzbuzz(n):\n    if n % 15 == 0:\n        return 'FizzBuzz'\n    elif n % 3 == 0:\n        return 'Fizz'\n    elif n % 5 == 0:\n        return 'Buzz'\n    else:\n        return str(n)",
          "starter_code": "",
          "test_code": "assert 'fizzbuzz' in dir(), \"Function 'fizzbuzz' not defined. Did you write: def fizzbuzz(...)?\"\n_r0 = fizzbuzz(3)\nassert _r0 == 'Fizz', 'Test 1: fizzbuzz(3) returned ' + str(repr(_r0)) + \", expected 'Fizz'\"\n_r1 = fizzbuzz(5)\nassert _r1 == 'Buzz', 'Test 2: fizzbuzz(5) returned ' + str(repr(_r1)) + \", expected 'Buzz'\"\n_r2 = fizzbuzz(15)\nassert _r2 == 'FizzBuzz', 'Test 3: fizzbuzz(15) returned ' + str(repr(_r2)) + \", expected 'FizzBuzz'\"\n_r3 = fizzbuzz(7)\nassert _r3 == '7', 'Test 4: fizzbuzz(7) returned ' + str(repr(_r3)) + \", expected '7'\"",
          "concepts": []
        },
        {
          "id": "cond_23",
          "title": "Leap year checker",
          "difficulty": 3,
          "description": "Write a function that returns True if a year is a leap year, False otherwise.",
          "hints": [
            "Rule: divisible by 400 -> leap, else divisible by 100 -> not leap, else divisible by 4 -> leap, else not leap",
            "2000 is a leap year (divisible by 400)",
            "1900 is not a leap year (divisible by 100 but not 400)"
          ],
          "solution": "def is_leap_year(year):\n    if year % 400 == 0:\n        return True\n    elif year % 100 == 0:\n        return False\n    elif year % 4 == 0:\n        return True\n    else:\n        return False",
          "starter_code": "",
          "test_code": "assert 'is_leap_year' in dir(), \"Function 'is_leap_year' not defined. Did you write: def is_leap_year(...)?\"\n_r0 = is_leap_year(2000)\nassert _r0 == True, 'Test 1: is_leap_year(2000) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = is_leap_year(1900)\nassert _r1 == False, 'Test 2: is_leap_year(1900) returned ' + str(repr(_r1)) + ', expected False'\n_r2 = is_leap_year(2004)\nassert _r2 == True, 'Test 3: is_leap_year(2004) returned ' + str(repr(_r2)) + ', expected True'\n_r3 = is_leap_year(2001)\nassert _r3 == False, 'Test 4: is_leap_year(2001) returned ' + str(repr(_r3)) + ', expected False'",
          "concepts": []
        },
        {
          "id": "cond_24",
          "title": "BMI category",
          "difficulty": 3,
          "description": "Write a function that calculates BMI (weight/height^2) and returns 'underweight', 'normal', 'overweight', or 'obese'.",
          "hints": [
            "BMI < 18.5: underweight, 18.5-24.9: normal, 25-29.9: overweight, >= 30: obese",
            "weight is in kg, height is in meters",
            "Use nested comparisons or if/elif chain"
          ],
          "solution": "def bmi_category(weight, height):\n    bmi = weight / (height ** 2)\n    if bmi < 18.5:\n        return 'underweight'\n    elif bmi < 25:\n        return 'normal'\n    elif bmi < 30:\n        return 'overweight'\n    else:\n        return 'obese'",
          "starter_code": "",
          "test_code": "assert 'bmi_category' in dir(), \"Function 'bmi_category' not defined. Did you write: def bmi_category(...)?\"\n_r0 = bmi_category(50, 1.8)\nassert _r0 == 'underweight', 'Test 1: bmi_category(50, 1.8) returned ' + str(repr(_r0)) + \", expected 'underweight'\"\n_r1 = bmi_category(70, 1.8)\nassert _r1 == 'normal', 'Test 2: bmi_category(70, 1.8) returned ' + str(repr(_r1)) + \", expected 'normal'\"\n_r2 = bmi_category(80, 1.8)\nassert _r2 == 'normal', 'Test 3: bmi_category(80, 1.8) returned ' + str(repr(_r2)) + \", expected 'normal'\"\n_r3 = bmi_category(100, 1.8)\nassert _r3 == 'obese', 'Test 4: bmi_category(100, 1.8) returned ' + str(repr(_r3)) + \", expected 'obese'\"",
          "concepts": []
        },
        {
          "id": "cond_25",
          "title": "Traffic light color action",
          "difficulty": 3,
          "description": "Write a function that takes a color and returns the action: 'go' (green), 'slow' (yellow), 'stop' (red), 'invalid' otherwise.",
          "hints": [
            "Use if/elif/else",
            "Handle lowercase/uppercase with .lower()",
            "Only three valid colors"
          ],
          "solution": "def traffic_light(color):\n    color = color.lower()\n    if color == 'green':\n        return 'go'\n    elif color == 'yellow':\n        return 'slow'\n    elif color == 'red':\n        return 'stop'\n    else:\n        return 'invalid'",
          "starter_code": "",
          "test_code": "assert 'traffic_light' in dir(), \"Function 'traffic_light' not defined. Did you write: def traffic_light(...)?\"\n_r0 = traffic_light('green')\nassert _r0 == 'go', \"Test 1: traffic_light('green') returned \" + str(repr(_r0)) + \", expected 'go'\"\n_r1 = traffic_light('Yellow')\nassert _r1 == 'slow', \"Test 2: traffic_light('Yellow') returned \" + str(repr(_r1)) + \", expected 'slow'\"\n_r2 = traffic_light('RED')\nassert _r2 == 'stop', \"Test 3: traffic_light('RED') returned \" + str(repr(_r2)) + \", expected 'stop'\"\n_r3 = traffic_light('blue')\nassert _r3 == 'invalid', \"Test 4: traffic_light('blue') returned \" + str(repr(_r3)) + \", expected 'invalid'\"",
          "concepts": []
        },
        {
          "id": "cond_26",
          "title": "Password strength checker",
          "difficulty": 3,
          "description": "Write a function that returns 'weak', 'medium', or 'strong' based on password criteria.",
          "hints": [
            "weak: length < 8",
            "medium: length >= 8 and (has uppercase or has digit)",
            "strong: length >= 12 and has uppercase and has digit",
            "Use any(c.isupper() for c in password) to check for uppercase"
          ],
          "solution": "def password_strength(password):\n    has_upper = any(c.isupper() for c in password)\n    has_digit = any(c.isdigit() for c in password)\n    length = len(password)\n    \n    if length < 8:\n        return 'weak'\n    elif length >= 12 and has_upper and has_digit:\n        return 'strong'\n    elif has_upper or has_digit:\n        return 'medium'\n    else:\n        return 'weak'",
          "starter_code": "",
          "test_code": "assert 'password_strength' in dir(), \"Function 'password_strength' not defined. Did you write: def password_strength(...)?\"\n_r0 = password_strength('abc')\nassert _r0 == 'weak', \"Test 1: password_strength('abc') returned \" + str(repr(_r0)) + \", expected 'weak'\"\n_r1 = password_strength('abcdef12')\nassert _r1 == 'medium', \"Test 2: password_strength('abcdef12') returned \" + str(repr(_r1)) + \", expected 'medium'\"\n_r2 = password_strength('Abcdef12xyz')\nassert _r2 == 'medium', \"Test 3: password_strength('Abcdef12xyz') returned \" + str(repr(_r2)) + \", expected 'medium'\"\n_r3 = password_strength('Password1234')\nassert _r3 == 'strong', \"Test 4: password_strength('Password1234') returned \" + str(repr(_r3)) + \", expected 'strong'\"",
          "concepts": []
        },
        {
          "id": "cond_27",
          "title": "Discount calculator",
          "difficulty": 3,
          "description": "Write a function that applies a discount based on purchase amount: 5% off >= $100, 10% off >= $500, 15% off >= $1000.",
          "hints": [
            "Use if/elif/else for different tiers",
            "Return the final price after discount",
            "Calculate: price * (1 - discount_rate)"
          ],
          "solution": "def apply_discount(price):\n    if price >= 1000:\n        return price * 0.85\n    elif price >= 500:\n        return price * 0.90\n    elif price >= 100:\n        return price * 0.95\n    else:\n        return price",
          "starter_code": "",
          "test_code": "assert 'apply_discount' in dir(), \"Function 'apply_discount' not defined. Did you write: def apply_discount(...)?\"\n_r0 = apply_discount(50)\nassert _r0 == 50, 'Test 1: apply_discount(50) returned ' + str(repr(_r0)) + ', expected 50'\n_r1 = apply_discount(100)\nassert _r1 == 95, 'Test 2: apply_discount(100) returned ' + str(repr(_r1)) + ', expected 95'\n_r2 = apply_discount(500)\nassert _r2 == 450, 'Test 3: apply_discount(500) returned ' + str(repr(_r2)) + ', expected 450'\n_r3 = apply_discount(1000)\nassert _r3 == 850, 'Test 4: apply_discount(1000) returned ' + str(repr(_r3)) + ', expected 850'",
          "concepts": []
        },
        {
          "id": "cond_28",
          "title": "Age category classification",
          "difficulty": 3,
          "description": "Write a function that returns an age category: 'child' (< 13), 'teen' (13-19), 'adult' (20-64), 'senior' (65+).",
          "hints": [
            "Use if/elif/elif/else chain",
            "Remember: 13 <= teen < 20",
            "Boundary cases: 12, 13, 19, 20, 64, 65"
          ],
          "solution": "def age_category(age):\n    if age < 13:\n        return 'child'\n    elif age < 20:\n        return 'teen'\n    elif age < 65:\n        return 'adult'\n    else:\n        return 'senior'",
          "starter_code": "",
          "test_code": "assert 'age_category' in dir(), \"Function 'age_category' not defined. Did you write: def age_category(...)?\"\n_r0 = age_category(5)\nassert _r0 == 'child', 'Test 1: age_category(5) returned ' + str(repr(_r0)) + \", expected 'child'\"\n_r1 = age_category(13)\nassert _r1 == 'teen', 'Test 2: age_category(13) returned ' + str(repr(_r1)) + \", expected 'teen'\"\n_r2 = age_category(19)\nassert _r2 == 'teen', 'Test 3: age_category(19) returned ' + str(repr(_r2)) + \", expected 'teen'\"\n_r3 = age_category(20)\nassert _r3 == 'adult', 'Test 4: age_category(20) returned ' + str(repr(_r3)) + \", expected 'adult'\"\n_r4 = age_category(65)\nassert _r4 == 'senior', 'Test 5: age_category(65) returned ' + str(repr(_r4)) + \", expected 'senior'\"",
          "concepts": []
        },
        {
          "id": "cond_29",
          "title": "Shipping cost calculator",
          "difficulty": 3,
          "description": "Write a function that calculates shipping cost: base $5, +$2 per pound if weight > 5, +$3 if destination is 'international'.",
          "hints": [
            "Start with base cost of $5",
            "Add $2 per pound for each pound over 5",
            "Add $3 if destination == 'international'",
            "Calculate: 5 + extra_weight_cost + international_cost"
          ],
          "solution": "def shipping_cost(weight, destination):\n    cost = 5\n    if weight > 5:\n        cost += (weight - 5) * 2\n    if destination == 'international':\n        cost += 3\n    return cost",
          "starter_code": "",
          "test_code": "assert 'shipping_cost' in dir(), \"Function 'shipping_cost' not defined. Did you write: def shipping_cost(...)?\"\n_r0 = shipping_cost(3, 'domestic')\nassert _r0 == 5, \"Test 1: shipping_cost(3, 'domestic') returned \" + str(repr(_r0)) + ', expected 5'\n_r1 = shipping_cost(6, 'domestic')\nassert _r1 == 7, \"Test 2: shipping_cost(6, 'domestic') returned \" + str(repr(_r1)) + ', expected 7'\n_r2 = shipping_cost(5, 'international')\nassert _r2 == 8, \"Test 3: shipping_cost(5, 'international') returned \" + str(repr(_r2)) + ', expected 8'\n_r3 = shipping_cost(10, 'international')\nassert _r3 == 18, \"Test 4: shipping_cost(10, 'international') returned \" + str(repr(_r3)) + ', expected 18'",
          "concepts": []
        },
        {
          "id": "cond_30",
          "title": "Movie rating classifier",
          "difficulty": 3,
          "description": "Write a function that returns a movie rating category: 'G' (0-5), 'PG' (5-7), 'PG-13' (7-10), 'R' (10+).",
          "hints": [
            "rating is a float from 0-10",
            "G: 0 <= rating <= 5, PG: 5 < rating <= 7, PG-13: 7 < rating <= 10, R: > 10",
            "Boundary: 5.0 is PG, 7.0 is PG-13"
          ],
          "solution": "def movie_rating(rating):\n    if rating <= 5:\n        return 'G'\n    elif rating <= 7:\n        return 'PG'\n    elif rating <= 10:\n        return 'PG-13'\n    else:\n        return 'R'",
          "starter_code": "",
          "test_code": "assert 'movie_rating' in dir(), \"Function 'movie_rating' not defined. Did you write: def movie_rating(...)?\"\n_r0 = movie_rating(3.5)\nassert _r0 == 'G', 'Test 1: movie_rating(3.5) returned ' + str(repr(_r0)) + \", expected 'G'\"\n_r1 = movie_rating(6.0)\nassert _r1 == 'PG', 'Test 2: movie_rating(6.0) returned ' + str(repr(_r1)) + \", expected 'PG'\"\n_r2 = movie_rating(8.5)\nassert _r2 == 'PG-13', 'Test 3: movie_rating(8.5) returned ' + str(repr(_r2)) + \", expected 'PG-13'\"\n_r3 = movie_rating(10)\nassert _r3 == 'PG-13', 'Test 4: movie_rating(10) returned ' + str(repr(_r3)) + \", expected 'PG-13'\"",
          "concepts": []
        },
        {
          "id": "cond_31",
          "title": "Vowel/consonant/other classifier",
          "difficulty": 3,
          "description": "Write a function that returns 'vowel' if the character is a vowel, 'consonant' if a letter, 'other' if not a letter.",
          "hints": [
            "Vowels: a, e, i, o, u (case-insensitive)",
            "Use .isalpha() to check if it's a letter",
            "Use .lower() to handle uppercase"
          ],
          "solution": "def classify_char(char):\n    char = char.lower()\n    if char in 'aeiou':\n        return 'vowel'\n    elif char.isalpha():\n        return 'consonant'\n    else:\n        return 'other'",
          "starter_code": "",
          "test_code": "assert 'classify_char' in dir(), \"Function 'classify_char' not defined. Did you write: def classify_char(...)?\"\n_r0 = classify_char('a')\nassert _r0 == 'vowel', \"Test 1: classify_char('a') returned \" + str(repr(_r0)) + \", expected 'vowel'\"\n_r1 = classify_char('b')\nassert _r1 == 'consonant', \"Test 2: classify_char('b') returned \" + str(repr(_r1)) + \", expected 'consonant'\"\n_r2 = classify_char('3')\nassert _r2 == 'other', \"Test 3: classify_char('3') returned \" + str(repr(_r2)) + \", expected 'other'\"\n_r3 = classify_char('E')\nassert _r3 == 'vowel', \"Test 4: classify_char('E') returned \" + str(repr(_r3)) + \", expected 'vowel'\"",
          "concepts": []
        },
        {
          "id": "cond_32",
          "title": "Triangle type classifier",
          "difficulty": 3,
          "description": "Write a function that returns 'equilateral' (all equal), 'isosceles' (2 equal), 'scalene' (none equal), or 'invalid' if not a valid triangle.",
          "hints": [
            "Valid triangle: sum of any two sides > third side",
            "Check all three conditions for valid triangle",
            "Compare sides: a == b, b == c, a == c"
          ],
          "solution": "def triangle_type(a, b, c):\n    if a + b <= c or b + c <= a or a + c <= b:\n        return 'invalid'\n    if a == b == c:\n        return 'equilateral'\n    elif a == b or b == c or a == c:\n        return 'isosceles'\n    else:\n        return 'scalene'",
          "starter_code": "",
          "test_code": "assert 'triangle_type' in dir(), \"Function 'triangle_type' not defined. Did you write: def triangle_type(...)?\"\n_r0 = triangle_type(3, 3, 3)\nassert _r0 == 'equilateral', 'Test 1: triangle_type(3, 3, 3) returned ' + str(repr(_r0)) + \", expected 'equilateral'\"\n_r1 = triangle_type(3, 3, 4)\nassert _r1 == 'isosceles', 'Test 2: triangle_type(3, 3, 4) returned ' + str(repr(_r1)) + \", expected 'isosceles'\"\n_r2 = triangle_type(3, 4, 5)\nassert _r2 == 'scalene', 'Test 3: triangle_type(3, 4, 5) returned ' + str(repr(_r2)) + \", expected 'scalene'\"\n_r3 = triangle_type(1, 2, 10)\nassert _r3 == 'invalid', 'Test 4: triangle_type(1, 2, 10) returned ' + str(repr(_r3)) + \", expected 'invalid'\"",
          "concepts": []
        },
        {
          "id": "cond_33",
          "title": "Number sign and magnitude",
          "difficulty": 3,
          "description": "Write a function that returns 'zero', 'small_pos', 'large_pos', 'small_neg', 'large_neg' based on the number.",
          "hints": [
            "zero: == 0",
            "small_pos: 0 < n <= 10, large_pos: > 10",
            "small_neg: -10 <= n < 0, large_neg: < -10"
          ],
          "solution": "def classify_number(n):\n    if n == 0:\n        return 'zero'\n    elif n > 0 and n <= 10:\n        return 'small_pos'\n    elif n > 10:\n        return 'large_pos'\n    elif n >= -10:\n        return 'small_neg'\n    else:\n        return 'large_neg'",
          "starter_code": "",
          "test_code": "assert 'classify_number' in dir(), \"Function 'classify_number' not defined. Did you write: def classify_number(...)?\"\n_r0 = classify_number(0)\nassert _r0 == 'zero', 'Test 1: classify_number(0) returned ' + str(repr(_r0)) + \", expected 'zero'\"\n_r1 = classify_number(5)\nassert _r1 == 'small_pos', 'Test 2: classify_number(5) returned ' + str(repr(_r1)) + \", expected 'small_pos'\"\n_r2 = classify_number(20)\nassert _r2 == 'large_pos', 'Test 3: classify_number(20) returned ' + str(repr(_r2)) + \", expected 'large_pos'\"\n_r3 = classify_number(-5)\nassert _r3 == 'small_neg', 'Test 4: classify_number(-5) returned ' + str(repr(_r3)) + \", expected 'small_neg'\"\n_r4 = classify_number(-20)\nassert _r4 == 'large_neg', 'Test 5: classify_number(-20) returned ' + str(repr(_r4)) + \", expected 'large_neg'\"",
          "concepts": []
        },
        {
          "id": "cond_34",
          "title": "Season from month number",
          "difficulty": 3,
          "description": "Write a function that returns the season ('winter', 'spring', 'summer', 'fall') given a month number 1-12.",
          "hints": [
            "Winter: 12, 1, 2",
            "Spring: 3, 4, 5",
            "Summer: 6, 7, 8",
            "Fall: 9, 10, 11"
          ],
          "solution": "def month_to_season(month):\n    if month in [12, 1, 2]:\n        return 'winter'\n    elif month in [3, 4, 5]:\n        return 'spring'\n    elif month in [6, 7, 8]:\n        return 'summer'\n    elif month in [9, 10, 11]:\n        return 'fall'\n    else:\n        return 'invalid'",
          "starter_code": "",
          "test_code": "assert 'month_to_season' in dir(), \"Function 'month_to_season' not defined. Did you write: def month_to_season(...)?\"\n_r0 = month_to_season(1)\nassert _r0 == 'winter', 'Test 1: month_to_season(1) returned ' + str(repr(_r0)) + \", expected 'winter'\"\n_r1 = month_to_season(4)\nassert _r1 == 'spring', 'Test 2: month_to_season(4) returned ' + str(repr(_r1)) + \", expected 'spring'\"\n_r2 = month_to_season(7)\nassert _r2 == 'summer', 'Test 3: month_to_season(7) returned ' + str(repr(_r2)) + \", expected 'summer'\"\n_r3 = month_to_season(10)\nassert _r3 == 'fall', 'Test 4: month_to_season(10) returned ' + str(repr(_r3)) + \", expected 'fall'\"",
          "concepts": []
        },
        {
          "id": "cond_35",
          "title": "Multiple-digit number analysis",
          "difficulty": 3,
          "description": "Write a function that returns 'small' (< 10), 'two_digit' (10-99), 'three_digit' (100-999), 'large' (>= 1000).",
          "hints": [
            "Use absolute value: abs(n) to handle negatives",
            "Chained comparisons help: 10 <= abs(n) < 100",
            "Remember: 10 is two-digit, 100 is three-digit"
          ],
          "solution": "def digit_category(n):\n    n = abs(n)\n    if n < 10:\n        return 'small'\n    elif n < 100:\n        return 'two_digit'\n    elif n < 1000:\n        return 'three_digit'\n    else:\n        return 'large'",
          "starter_code": "",
          "test_code": "assert 'digit_category' in dir(), \"Function 'digit_category' not defined. Did you write: def digit_category(...)?\"\n_r0 = digit_category(5)\nassert _r0 == 'small', 'Test 1: digit_category(5) returned ' + str(repr(_r0)) + \", expected 'small'\"\n_r1 = digit_category(42)\nassert _r1 == 'two_digit', 'Test 2: digit_category(42) returned ' + str(repr(_r1)) + \", expected 'two_digit'\"\n_r2 = digit_category(567)\nassert _r2 == 'three_digit', 'Test 3: digit_category(567) returned ' + str(repr(_r2)) + \", expected 'three_digit'\"\n_r3 = digit_category(1234)\nassert _r3 == 'large', 'Test 4: digit_category(1234) returned ' + str(repr(_r3)) + \", expected 'large'\"",
          "concepts": []
        },
        {
          "id": "cond_36",
          "title": "Tax bracket calculator",
          "difficulty": 4,
          "description": "Write a function that calculates tax on income using brackets: 10% (0-10k), 12% (10k-40k), 22% (40k-85k), 24% (85k+).",
          "hints": [
            "Tax is cumulative: first $10k at 10%, next $30k at 12%, etc.",
            "Use nested conditionals or separate calculations",
            "Example: $15k = (10k * 0.10) + (5k * 0.12) = $1600"
          ],
          "solution": "def calculate_tax(income):\n    if income <= 10000:\n        return income * 0.10\n    elif income <= 40000:\n        return 1000 + (income - 10000) * 0.12\n    elif income <= 85000:\n        return 1000 + 3600 + (income - 40000) * 0.22\n    else:\n        return 1000 + 3600 + 9900 + (income - 85000) * 0.24",
          "starter_code": "",
          "test_code": "assert 'calculate_tax' in dir(), \"Function 'calculate_tax' not defined. Did you write: def calculate_tax(...)?\"\n_r0 = calculate_tax(5000)\nassert _r0 == 500, 'Test 1: calculate_tax(5000) returned ' + str(repr(_r0)) + ', expected 500'\n_r1 = calculate_tax(15000)\nassert _r1 == 1600, 'Test 2: calculate_tax(15000) returned ' + str(repr(_r1)) + ', expected 1600'\n_r2 = calculate_tax(50000)\nassert _r2 == 6800, 'Test 3: calculate_tax(50000) returned ' + str(repr(_r2)) + ', expected 6800'",
          "concepts": []
        },
        {
          "id": "cond_37",
          "title": "Complex eligibility checker",
          "difficulty": 4,
          "description": "Write a function that checks loan eligibility: age >= 21 AND (income >= 30k OR has_collateral) AND credit_score >= 650.",
          "hints": [
            "All three major conditions must be true",
            "Use 'and' and 'or' together",
            "Parentheses: (A and B and C) structure"
          ],
          "solution": "def loan_eligible(age, income, has_collateral, credit_score):\n    return (age >= 21 and \n            (income >= 30000 or has_collateral) and \n            credit_score >= 650)",
          "starter_code": "",
          "test_code": "assert 'loan_eligible' in dir(), \"Function 'loan_eligible' not defined. Did you write: def loan_eligible(...)?\"\n_r0 = loan_eligible(25, 35000, False, 700)\nassert _r0 == True, 'Test 1: loan_eligible(25, 35000, False, 700) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = loan_eligible(25, 25000, True, 700)\nassert _r1 == True, 'Test 2: loan_eligible(25, 25000, True, 700) returned ' + str(repr(_r1)) + ', expected True'\n_r2 = loan_eligible(20, 35000, False, 700)\nassert _r2 == False, 'Test 3: loan_eligible(20, 35000, False, 700) returned ' + str(repr(_r2)) + ', expected False'\n_r3 = loan_eligible(25, 25000, False, 600)\nassert _r3 == False, 'Test 4: loan_eligible(25, 25000, False, 600) returned ' + str(repr(_r3)) + ', expected False'",
          "concepts": []
        },
        {
          "id": "cond_38",
          "title": "Game rock-paper-scissors",
          "difficulty": 4,
          "description": "Write a function that takes player1 and player2 moves and returns 'player1', 'player2', or 'tie'.",
          "hints": [
            "Rock beats scissors, scissors beats paper, paper beats rock",
            "Use if/elif chain for outcomes",
            "Handle tie case separately"
          ],
          "solution": "def rps_winner(p1, p2):\n    if p1 == p2:\n        return 'tie'\n    if (p1 == 'rock' and p2 == 'scissors') or \\\n       (p1 == 'scissors' and p2 == 'paper') or \\\n       (p1 == 'paper' and p2 == 'rock'):\n        return 'player1'\n    return 'player2'",
          "starter_code": "",
          "test_code": "assert 'rps_winner' in dir(), \"Function 'rps_winner' not defined. Did you write: def rps_winner(...)?\"\n_r0 = rps_winner('rock', 'rock')\nassert _r0 == 'tie', \"Test 1: rps_winner('rock', 'rock') returned \" + str(repr(_r0)) + \", expected 'tie'\"\n_r1 = rps_winner('rock', 'scissors')\nassert _r1 == 'player1', \"Test 2: rps_winner('rock', 'scissors') returned \" + str(repr(_r1)) + \", expected 'player1'\"\n_r2 = rps_winner('paper', 'rock')\nassert _r2 == 'player1', \"Test 3: rps_winner('paper', 'rock') returned \" + str(repr(_r2)) + \", expected 'player1'\"\n_r3 = rps_winner('rock', 'paper')\nassert _r3 == 'player2', \"Test 4: rps_winner('rock', 'paper') returned \" + str(repr(_r3)) + \", expected 'player2'\"",
          "concepts": []
        },
        {
          "id": "cond_39",
          "title": "Email validation (basic)",
          "difficulty": 4,
          "description": "Write a function that validates an email: must have @ symbol, must have a dot after @, must have content before @, after @, and after dot.",
          "hints": [
            "Check '@' in email",
            "Check '.' after '@': email.rfind('.') > email.find('@')",
            "Check length constraints: at least 1 char before @, between @&., after ."
          ],
          "solution": "def is_valid_email(email):\n    if '@' not in email:\n        return False\n    if '.' not in email:\n        return False\n    at_pos = email.find('@')\n    dot_pos = email.rfind('.')\n    if at_pos == 0 or at_pos == len(email) - 1:\n        return False\n    if dot_pos <= at_pos + 1 or dot_pos == len(email) - 1:\n        return False\n    return True",
          "starter_code": "",
          "test_code": "assert 'is_valid_email' in dir(), \"Function 'is_valid_email' not defined. Did you write: def is_valid_email(...)?\"\n_r0 = is_valid_email('user@example.com')\nassert _r0 == True, \"Test 1: is_valid_email('user@example.com') returned \" + str(repr(_r0)) + ', expected True'\n_r1 = is_valid_email('invalid.email')\nassert _r1 == False, \"Test 2: is_valid_email('invalid.email') returned \" + str(repr(_r1)) + ', expected False'\n_r2 = is_valid_email('@example.com')\nassert _r2 == False, \"Test 3: is_valid_email('@example.com') returned \" + str(repr(_r2)) + ', expected False'\n_r3 = is_valid_email('user@.com')\nassert _r3 == False, \"Test 4: is_valid_email('user@.com') returned \" + str(repr(_r3)) + ', expected False'",
          "concepts": []
        },
        {
          "id": "cond_40",
          "title": "Nested conditionals with lists",
          "difficulty": 4,
          "description": "Write a function that takes a list and returns 'empty', 'single', or 'multi', and additionally if any element is negative, append '_has_neg'.",
          "hints": [
            "First check length: 0, 1, or multiple",
            "Then check if any element is negative",
            "Use any(x < 0 for x in lst) to check",
            "Return appropriate string with or without '_has_neg'"
          ],
          "solution": "def list_summary(lst):\n    has_neg = any(x < 0 for x in lst)\n    \n    if len(lst) == 0:\n        result = 'empty'\n    elif len(lst) == 1:\n        result = 'single'\n    else:\n        result = 'multi'\n    \n    if has_neg:\n        result += '_has_neg'\n    return result",
          "starter_code": "",
          "test_code": "assert 'list_summary' in dir(), \"'list_summary' is not defined\"\nassert callable(list_summary), \"'list_summary' should be a function\"",
          "concepts": []
        },
        {
          "id": "cond_41",
          "title": "Multi-level nested conditions",
          "difficulty": 4,
          "description": "Write a function that classifies numbers: 'small_even', 'small_odd', 'large_even', 'large_odd', where small is < 100.",
          "hints": [
            "First level: check if < 100 (small) or >= 100 (large)",
            "Second level: check if even (n % 2 == 0) or odd",
            "Combine results into the appropriate category"
          ],
          "solution": "def classify_number_detailed(n):\n    if n < 100:\n        if n % 2 == 0:\n            return 'small_even'\n        else:\n            return 'small_odd'\n    else:\n        if n % 2 == 0:\n            return 'large_even'\n        else:\n            return 'large_odd'",
          "starter_code": "",
          "test_code": "assert 'classify_number_detailed' in dir(), \"Function 'classify_number_detailed' not defined. Did you write: def classify_number_detailed(...)?\"\n_r0 = classify_number_detailed(42)\nassert _r0 == 'small_even', 'Test 1: classify_number_detailed(42) returned ' + str(repr(_r0)) + \", expected 'small_even'\"\n_r1 = classify_number_detailed(53)\nassert _r1 == 'small_odd', 'Test 2: classify_number_detailed(53) returned ' + str(repr(_r1)) + \", expected 'small_odd'\"\n_r2 = classify_number_detailed(200)\nassert _r2 == 'large_even', 'Test 3: classify_number_detailed(200) returned ' + str(repr(_r2)) + \", expected 'large_even'\"\n_r3 = classify_number_detailed(201)\nassert _r3 == 'large_odd', 'Test 4: classify_number_detailed(201) returned ' + str(repr(_r3)) + \", expected 'large_odd'\"",
          "concepts": []
        },
        {
          "id": "cond_42",
          "title": "String properties analysis",
          "difficulty": 4,
          "description": "Write a function that returns 'uppercase', 'lowercase', 'mixed', or 'non_alpha' based on string content.",
          "hints": [
            "Use .isupper(), .islower(), .isalpha() methods",
            "non_alpha: string doesn't contain any letters",
            "mixed: contains both upper and lower case letters"
          ],
          "solution": "def string_case_type(s):\n    if not s:\n        return 'non_alpha'\n    if not any(c.isalpha() for c in s):\n        return 'non_alpha'\n    if s.isupper():\n        return 'uppercase'\n    elif s.islower():\n        return 'lowercase'\n    else:\n        return 'mixed'",
          "starter_code": "",
          "test_code": "assert 'string_case_type' in dir(), \"Function 'string_case_type' not defined. Did you write: def string_case_type(...)?\"\n_r0 = string_case_type('HELLO')\nassert _r0 == 'uppercase', \"Test 1: string_case_type('HELLO') returned \" + str(repr(_r0)) + \", expected 'uppercase'\"\n_r1 = string_case_type('hello')\nassert _r1 == 'lowercase', \"Test 2: string_case_type('hello') returned \" + str(repr(_r1)) + \", expected 'lowercase'\"\n_r2 = string_case_type('Hello')\nassert _r2 == 'mixed', \"Test 3: string_case_type('Hello') returned \" + str(repr(_r2)) + \", expected 'mixed'\"\n_r3 = string_case_type('12345')\nassert _r3 == 'non_alpha', \"Test 4: string_case_type('12345') returned \" + str(repr(_r3)) + \", expected 'non_alpha'\"",
          "concepts": []
        },
        {
          "id": "cond_43",
          "title": "Insurance premium calculator",
          "difficulty": 4,
          "description": "Write a function that calculates insurance premium: base $100, +$10 per year for age > 30, +$50 if high_risk, +15% if has_accidents.",
          "hints": [
            "Base: $100",
            "Add $10 for each year over 30 (age - 30 if age > 30)",
            "Add $50 if high_risk is True",
            "Add 15% of total if has_accidents is True",
            "Order: base + age_surcharge + risk_surcharge, then apply accident multiplier"
          ],
          "solution": "def insurance_premium(age, high_risk, has_accidents):\n    premium = 100\n    if age > 30:\n        premium += (age - 30) * 10\n    if high_risk:\n        premium += 50\n    if has_accidents:\n        premium *= 1.15\n    return premium",
          "starter_code": "",
          "test_code": "assert 'insurance_premium' in dir(), \"Function 'insurance_premium' not defined. Did you write: def insurance_premium(...)?\"\n_r0 = insurance_premium(25, False, False)\nassert _r0 == 100, 'Test 1: insurance_premium(25, False, False) returned ' + str(repr(_r0)) + ', expected 100'\n_r1 = insurance_premium(35, False, False)\nassert _r1 == 150, 'Test 2: insurance_premium(35, False, False) returned ' + str(repr(_r1)) + ', expected 150'\n_r2 = insurance_premium(30, True, False)\nassert _r2 == 150, 'Test 3: insurance_premium(30, True, False) returned ' + str(repr(_r2)) + ', expected 150'\n_r3 = insurance_premium(35, True, True)\nassert _r3 == 229.99999999999997, 'Test 4: insurance_premium(35, True, True) returned ' + str(repr(_r3)) + ', expected 229.99999999999997'",
          "concepts": []
        },
        {
          "id": "cond_44",
          "title": "Conditional string formatting",
          "difficulty": 4,
          "description": "Write a function that returns a message about a score: 'Excellent!' if >= 90, 'Good' if >= 80, 'Okay' if >= 70, 'Needs improvement' otherwise.",
          "hints": [
            "Use if/elif/else with different string messages",
            "Each message is different, not just a grade letter",
            "Include punctuation in the returned strings"
          ],
          "solution": "def score_message(score):\n    if score >= 90:\n        return 'Excellent!'\n    elif score >= 80:\n        return 'Good'\n    elif score >= 70:\n        return 'Okay'\n    else:\n        return 'Needs improvement'",
          "starter_code": "",
          "test_code": "assert 'score_message' in dir(), \"Function 'score_message' not defined. Did you write: def score_message(...)?\"\n_r0 = score_message(95)\nassert _r0 == 'Excellent!', 'Test 1: score_message(95) returned ' + str(repr(_r0)) + \", expected 'Excellent!'\"\n_r1 = score_message(85)\nassert _r1 == 'Good', 'Test 2: score_message(85) returned ' + str(repr(_r1)) + \", expected 'Good'\"\n_r2 = score_message(75)\nassert _r2 == 'Okay', 'Test 3: score_message(75) returned ' + str(repr(_r2)) + \", expected 'Okay'\"\n_r3 = score_message(60)\nassert _r3 == 'Needs improvement', 'Test 4: score_message(60) returned ' + str(repr(_r3)) + \", expected 'Needs improvement'\"",
          "concepts": []
        },
        {
          "id": "cond_45",
          "title": "Range-based categorization",
          "difficulty": 4,
          "description": "Write a function that categorizes a test score into percentile: 'top_10' (90+), 'top_25' (80-89), 'top_50' (70-79), 'below_50' (<70).",
          "hints": [
            "Use >= and < carefully for boundaries",
            "90-99: top_10, 80-89: top_25, 70-79: top_50, 0-69: below_50",
            "Each range is mutually exclusive"
          ],
          "solution": "def percentile_category(score):\n    if score >= 90:\n        return 'top_10'\n    elif score >= 80:\n        return 'top_25'\n    elif score >= 70:\n        return 'top_50'\n    else:\n        return 'below_50'",
          "starter_code": "",
          "test_code": "assert 'percentile_category' in dir(), \"Function 'percentile_category' not defined. Did you write: def percentile_category(...)?\"\n_r0 = percentile_category(95)\nassert _r0 == 'top_10', 'Test 1: percentile_category(95) returned ' + str(repr(_r0)) + \", expected 'top_10'\"\n_r1 = percentile_category(85)\nassert _r1 == 'top_25', 'Test 2: percentile_category(85) returned ' + str(repr(_r1)) + \", expected 'top_25'\"\n_r2 = percentile_category(75)\nassert _r2 == 'top_50', 'Test 3: percentile_category(75) returned ' + str(repr(_r2)) + \", expected 'top_50'\"\n_r3 = percentile_category(65)\nassert _r3 == 'below_50', 'Test 4: percentile_category(65) returned ' + str(repr(_r3)) + \", expected 'below_50'\"",
          "concepts": []
        },
        {
          "id": "cond_46",
          "title": "Comprehensive user access control",
          "difficulty": 5,
          "description": "Write a function that determines access level: 'admin' (role=='admin' AND is_active), 'moderator' (role=='moderator' AND is_active AND reputation>=50), 'user' (is_active), 'denied' otherwise.",
          "hints": [
            "Order matters: check admin first, then moderator, then user",
            "All access levels require is_active == True",
            "Moderator also requires reputation >= 50"
          ],
          "solution": "def determine_access(role, is_active, reputation):\n    if role == 'admin' and is_active:\n        return 'admin'\n    elif role == 'moderator' and is_active and reputation >= 50:\n        return 'moderator'\n    elif is_active:\n        return 'user'\n    else:\n        return 'denied'",
          "starter_code": "",
          "test_code": "assert 'determine_access' in dir(), \"Function 'determine_access' not defined. Did you write: def determine_access(...)?\"\n_r0 = determine_access('admin', True, 100)\nassert _r0 == 'admin', \"Test 1: determine_access('admin', True, 100) returned \" + str(repr(_r0)) + \", expected 'admin'\"\n_r1 = determine_access('moderator', True, 60)\nassert _r1 == 'moderator', \"Test 2: determine_access('moderator', True, 60) returned \" + str(repr(_r1)) + \", expected 'moderator'\"\n_r2 = determine_access('moderator', True, 30)\nassert _r2 == 'user', \"Test 3: determine_access('moderator', True, 30) returned \" + str(repr(_r2)) + \", expected 'user'\"\n_r3 = determine_access('user', True, 0)\nassert _r3 == 'user', \"Test 4: determine_access('user', True, 0) returned \" + str(repr(_r3)) + \", expected 'user'\"\n_r4 = determine_access('user', False, 0)\nassert _r4 == 'denied', \"Test 5: determine_access('user', False, 0) returned \" + str(repr(_r4)) + \", expected 'denied'\"",
          "concepts": []
        },
        {
          "id": "cond_47",
          "title": "Flight ticket pricing with multiple factors",
          "difficulty": 5,
          "description": "Write a function that calculates ticket price: base $200, -20% if advance_booking (>30 days), -10% if is_member, +50% if is_weekend.",
          "hints": [
            "Base price: $200",
            "Discount for advance_booking: advance_days > 30",
            "Discount for membership: is_member == True",
            "Surcharge for weekend: is_weekend == True",
            "Apply discounts first, then surcharge"
          ],
          "solution": "def flight_ticket_price(advance_days, is_member, is_weekend):\n    price = 200\n    if advance_days > 30:\n        price *= 0.8\n    if is_member:\n        price *= 0.9\n    if is_weekend:\n        price *= 1.5\n    return price",
          "starter_code": "",
          "test_code": "assert 'flight_ticket_price' in dir(), \"Function 'flight_ticket_price' not defined. Did you write: def flight_ticket_price(...)?\"\n_r0 = flight_ticket_price(50, False, False)\nassert _r0 == 160, 'Test 1: flight_ticket_price(50, False, False) returned ' + str(repr(_r0)) + ', expected 160'\n_r1 = flight_ticket_price(10, False, False)\nassert _r1 == 200, 'Test 2: flight_ticket_price(10, False, False) returned ' + str(repr(_r1)) + ', expected 200'\n_r2 = flight_ticket_price(50, True, False)\nassert _r2 == 144, 'Test 3: flight_ticket_price(50, True, False) returned ' + str(repr(_r2)) + ', expected 144'\n_r3 = flight_ticket_price(50, True, True)\nassert _r3 == 216, 'Test 4: flight_ticket_price(50, True, True) returned ' + str(repr(_r3)) + ', expected 216'",
          "concepts": []
        },
        {
          "id": "cond_48",
          "title": "Data validation with multiple checks",
          "difficulty": 5,
          "description": "Write a function that validates registration: returns list of errors if any, or ['valid'] if all checks pass.",
          "hints": [
            "Check: age >= 18, email contains '@', password length >= 8, username length 3-20",
            "Collect errors in a list: 'age_error', 'email_error', 'password_error', 'username_error'",
            "Return ['valid'] if no errors, otherwise return the error list"
          ],
          "solution": "def validate_registration(age, email, password, username):\n    errors = []\n    if age < 18:\n        errors.append('age_error')\n    if '@' not in email:\n        errors.append('email_error')\n    if len(password) < 8:\n        errors.append('password_error')\n    if len(username) < 3 or len(username) > 20:\n        errors.append('username_error')\n    return errors if errors else ['valid']",
          "starter_code": "",
          "test_code": "assert 'validate_registration' in dir(), \"Function 'validate_registration' not defined. Did you write: def validate_registration(...)?\"\n_r0 = validate_registration(25, 'user@example.com', 'password123', 'john')\nassert _r0 == ['valid'], \"Test 1: validate_registration(25, 'user@example.com', 'password123', 'john') returned \" + str(repr(_r0)) + \", expected ['valid']\"\n_r1 = validate_registration(17, 'user@example.com', 'password123', 'john')\nassert _r1 == ['age_error'], \"Test 2: validate_registration(17, 'user@example.com', 'password123', 'john') returned \" + str(repr(_r1)) + \", expected ['age_error']\"\n_r2 = validate_registration(25, 'useremailcom', 'short', 'a')\nassert _r2 == ['email_error', 'password_error', 'username_error'], \"Test 3: validate_registration(25, 'useremailcom', 'short', 'a') returned \" + str(repr(_r2)) + \", expected ['email_error', 'password_error', 'username_error']\"",
          "concepts": []
        },
        {
          "id": "cond_49",
          "title": "Match statement (Python 3.10+)",
          "difficulty": 5,
          "description": "Write a function using match/case that maps HTTP status codes to descriptions: 200->'OK', 301->'Moved', 400->'Bad Request', 404->'Not Found', 500->'Server Error', default->'Unknown'.",
          "hints": [
            "Use match status_code: ... case ...",
            "Cases can be single values or ranges (in this case, use if conditions inside case)",
            "Use _ as default case",
            "match/case is structural pattern matching in Python 3.10+"
          ],
          "solution": "def http_status(code):\n    match code:\n        case 200:\n            return 'OK'\n        case 301:\n            return 'Moved'\n        case 400:\n            return 'Bad Request'\n        case 404:\n            return 'Not Found'\n        case 500:\n            return 'Server Error'\n        case _:\n            return 'Unknown'",
          "starter_code": "",
          "test_code": "assert 'http_status' in dir(), \"Function 'http_status' not defined. Did you write: def http_status(...)?\"\n_r0 = http_status(200)\nassert _r0 == 'OK', 'Test 1: http_status(200) returned ' + str(repr(_r0)) + \", expected 'OK'\"\n_r1 = http_status(404)\nassert _r1 == 'Not Found', 'Test 2: http_status(404) returned ' + str(repr(_r1)) + \", expected 'Not Found'\"\n_r2 = http_status(500)\nassert _r2 == 'Server Error', 'Test 3: http_status(500) returned ' + str(repr(_r2)) + \", expected 'Server Error'\"\n_r3 = http_status(999)\nassert _r3 == 'Unknown', 'Test 4: http_status(999) returned ' + str(repr(_r3)) + \", expected 'Unknown'\"",
          "concepts": []
        },
        {
          "id": "cond_50",
          "title": "Complex business logic: subscription tier upgrade",
          "difficulty": 5,
          "description": "Write a function that determines if a user can upgrade from tier1 to tier2: tier1 != tier2, account_age > 30 days, AND (payment_method_verified OR credit_balance > 100).",
          "hints": [
            "Must not be upgrading from the same tier",
            "Account must be at least 31 days old",
            "Must either have verified payment OR sufficient credit balance",
            "All three conditions must be true"
          ],
          "solution": "def can_upgrade_tier(tier1, tier2, account_age, payment_verified, credit_balance):\n    return (tier1 != tier2 and \n            account_age > 30 and \n            (payment_verified or credit_balance > 100))",
          "starter_code": "",
          "test_code": "assert 'can_upgrade_tier' in dir(), \"Function 'can_upgrade_tier' not defined. Did you write: def can_upgrade_tier(...)?\"\n_r0 = can_upgrade_tier('basic', 'premium', 60, True, 0)\nassert _r0 == True, \"Test 1: can_upgrade_tier('basic', 'premium', 60, True, 0) returned \" + str(repr(_r0)) + ', expected True'\n_r1 = can_upgrade_tier('basic', 'premium', 60, False, 150)\nassert _r1 == True, \"Test 2: can_upgrade_tier('basic', 'premium', 60, False, 150) returned \" + str(repr(_r1)) + ', expected True'\n_r2 = can_upgrade_tier('basic', 'premium', 60, False, 50)\nassert _r2 == False, \"Test 3: can_upgrade_tier('basic', 'premium', 60, False, 50) returned \" + str(repr(_r2)) + ', expected False'\n_r3 = can_upgrade_tier('basic', 'basic', 60, True, 0)\nassert _r3 == False, \"Test 4: can_upgrade_tier('basic', 'basic', 60, True, 0) returned \" + str(repr(_r3)) + ', expected False'\n_r4 = can_upgrade_tier('basic', 'premium', 20, True, 0)\nassert _r4 == False, \"Test 5: can_upgrade_tier('basic', 'premium', 20, True, 0) returned \" + str(repr(_r4)) + ', expected False'",
          "concepts": []
        }
      ]
    },
    {
      "id": "loops",
      "title": "Loops",
      "exercise_count": 50,
      "exercises": [
        {
          "id": "loop_01",
          "title": "Count with range",
          "difficulty": 1,
          "description": "Write a function `count_up(n)` that returns a list of the numbers 0 up to but not including `n`.",
          "hints": [
            "range(n) yields 0, 1, ... n-1",
            "Start with an empty list and append inside the loop"
          ],
          "solution": "def count_up(n):\n    result = []\n    for i in range(n):\n        result.append(i)\n    return result",
          "starter_code": "def count_up(n):\n    # build a list of 0..n-1\n",
          "test_code": "assert 'count_up' in dir(), \"Function 'count_up' not defined. Did you write: def count_up(...)?\"\n_r0 = count_up(3)\nassert _r0 == [0, 1, 2], 'Test 1: count_up(3) returned ' + str(repr(_r0)) + ', expected [0, 1, 2]'\n_r1 = count_up(1)\nassert _r1 == [0], 'Test 2: count_up(1) returned ' + str(repr(_r1)) + ', expected [0]'\n_r2 = count_up(0)\nassert _r2 == [], 'Test 3: count_up(0) returned ' + str(repr(_r2)) + ', expected []'\n_r3 = count_up(5)\nassert _r3 == [0, 1, 2, 3, 4], 'Test 4: count_up(5) returned ' + str(repr(_r3)) + ', expected [0, 1, 2, 3, 4]'",
          "concepts": [
            "for loop",
            "range",
            "append"
          ]
        },
        {
          "id": "loop_02",
          "title": "Sum a list",
          "difficulty": 1,
          "description": "Write a function `total(numbers)` that adds up every number in the list using a loop (do not use the built-in sum).",
          "hints": [
            "Start a variable at 0 before the loop",
            "Add each item to it with +="
          ],
          "solution": "def total(numbers):\n    running = 0\n    for n in numbers:\n        running += n\n    return running",
          "starter_code": "def total(numbers):\n    running = 0\n",
          "test_code": "assert 'total' in dir(), \"Function 'total' not defined. Did you write: def total(...)?\"\n_r0 = total([1, 2, 3])\nassert _r0 == 6, 'Test 1: total([1, 2, 3]) returned ' + str(repr(_r0)) + ', expected 6'\n_r1 = total([])\nassert _r1 == 0, 'Test 2: total([]) returned ' + str(repr(_r1)) + ', expected 0'\n_r2 = total([10, -4])\nassert _r2 == 6, 'Test 3: total([10, -4]) returned ' + str(repr(_r2)) + ', expected 6'\n_r3 = total([5])\nassert _r3 == 5, 'Test 4: total([5]) returned ' + str(repr(_r3)) + ', expected 5'",
          "concepts": [
            "for loop",
            "accumulator",
            "augmented assignment"
          ]
        },
        {
          "id": "loop_03",
          "title": "Count the items",
          "difficulty": 1,
          "description": "Write a function `how_many(items)` that counts the items with a loop instead of using len.",
          "hints": [
            "Increase a counter by 1 on every pass",
            "The loop variable itself is not needed"
          ],
          "solution": "def how_many(items):\n    count = 0\n    for _ in items:\n        count += 1\n    return count",
          "starter_code": "def how_many(items):\n    count = 0\n",
          "test_code": "assert 'how_many' in dir(), \"Function 'how_many' not defined. Did you write: def how_many(...)?\"\n_r0 = how_many(['a', 'b'])\nassert _r0 == 2, \"Test 1: how_many(['a', 'b']) returned \" + str(repr(_r0)) + ', expected 2'\n_r1 = how_many([])\nassert _r1 == 0, 'Test 2: how_many([]) returned ' + str(repr(_r1)) + ', expected 0'\n_r2 = how_many([1, 2, 3, 4])\nassert _r2 == 4, 'Test 3: how_many([1, 2, 3, 4]) returned ' + str(repr(_r2)) + ', expected 4'",
          "concepts": [
            "for loop",
            "counter",
            "throwaway variable"
          ]
        },
        {
          "id": "loop_04",
          "title": "Double every number",
          "difficulty": 1,
          "description": "Write a function `double_all(numbers)` that returns a new list with each number multiplied by 2.",
          "hints": [
            "Build a fresh list, do not change the original",
            "append(n * 2) inside the loop"
          ],
          "solution": "def double_all(numbers):\n    result = []\n    for n in numbers:\n        result.append(n * 2)\n    return result",
          "starter_code": "def double_all(numbers):\n    result = []\n",
          "test_code": "assert 'double_all' in dir(), \"Function 'double_all' not defined. Did you write: def double_all(...)?\"\n_r0 = double_all([1, 2, 3])\nassert _r0 == [2, 4, 6], 'Test 1: double_all([1, 2, 3]) returned ' + str(repr(_r0)) + ', expected [2, 4, 6]'\n_r1 = double_all([])\nassert _r1 == [], 'Test 2: double_all([]) returned ' + str(repr(_r1)) + ', expected []'\n_r2 = double_all([-1, 0])\nassert _r2 == [-2, 0], 'Test 3: double_all([-1, 0]) returned ' + str(repr(_r2)) + ', expected [-2, 0]'",
          "concepts": [
            "for loop",
            "transform",
            "append"
          ]
        },
        {
          "id": "loop_05",
          "title": "Range with a start",
          "difficulty": 1,
          "description": "Write a function `span(start, stop)` returning a list of the integers from `start` up to but not including `stop`.",
          "hints": [
            "range takes two arguments: range(start, stop)",
            "list(range(...)) also works, but write the loop"
          ],
          "solution": "def span(start, stop):\n    result = []\n    for i in range(start, stop):\n        result.append(i)\n    return result",
          "starter_code": "def span(start, stop):\n    result = []\n",
          "test_code": "assert 'span' in dir(), \"Function 'span' not defined. Did you write: def span(...)?\"\n_r0 = span(2, 5)\nassert _r0 == [2, 3, 4], 'Test 1: span(2, 5) returned ' + str(repr(_r0)) + ', expected [2, 3, 4]'\n_r1 = span(0, 1)\nassert _r1 == [0], 'Test 2: span(0, 1) returned ' + str(repr(_r1)) + ', expected [0]'\n_r2 = span(3, 3)\nassert _r2 == [], 'Test 3: span(3, 3) returned ' + str(repr(_r2)) + ', expected []'\n_r3 = span(-2, 1)\nassert _r3 == [-2, -1, 0], 'Test 4: span(-2, 1) returned ' + str(repr(_r3)) + ', expected [-2, -1, 0]'",
          "concepts": [
            "range",
            "for loop"
          ]
        },
        {
          "id": "loop_06",
          "title": "Range with a step",
          "difficulty": 1,
          "description": "Write a function `evens_below(n)` returning every even number from 0 up to but not including `n`, using range's third argument.",
          "hints": [
            "range(0, n, 2) counts in twos",
            "The third argument is the step"
          ],
          "solution": "def evens_below(n):\n    result = []\n    for i in range(0, n, 2):\n        result.append(i)\n    return result",
          "starter_code": "def evens_below(n):\n    result = []\n",
          "test_code": "assert 'evens_below' in dir(), \"Function 'evens_below' not defined. Did you write: def evens_below(...)?\"\n_r0 = evens_below(7)\nassert _r0 == [0, 2, 4, 6], 'Test 1: evens_below(7) returned ' + str(repr(_r0)) + ', expected [0, 2, 4, 6]'\n_r1 = evens_below(1)\nassert _r1 == [0], 'Test 2: evens_below(1) returned ' + str(repr(_r1)) + ', expected [0]'\n_r2 = evens_below(0)\nassert _r2 == [], 'Test 3: evens_below(0) returned ' + str(repr(_r2)) + ', expected []'\n_r3 = evens_below(10)\nassert _r3 == [0, 2, 4, 6, 8], 'Test 4: evens_below(10) returned ' + str(repr(_r3)) + ', expected [0, 2, 4, 6, 8]'",
          "concepts": [
            "range step",
            "for loop"
          ]
        },
        {
          "id": "loop_07",
          "title": "Countdown with a negative step",
          "difficulty": 1,
          "description": "Write a function `countdown(n)` returning the numbers from `n` down to 1.",
          "hints": [
            "range(n, 0, -1) counts backwards",
            "The stop value is still excluded"
          ],
          "solution": "def countdown(n):\n    result = []\n    for i in range(n, 0, -1):\n        result.append(i)\n    return result",
          "starter_code": "def countdown(n):\n    result = []\n",
          "test_code": "assert 'countdown' in dir(), \"Function 'countdown' not defined. Did you write: def countdown(...)?\"\n_r0 = countdown(3)\nassert _r0 == [3, 2, 1], 'Test 1: countdown(3) returned ' + str(repr(_r0)) + ', expected [3, 2, 1]'\n_r1 = countdown(1)\nassert _r1 == [1], 'Test 2: countdown(1) returned ' + str(repr(_r1)) + ', expected [1]'\n_r2 = countdown(0)\nassert _r2 == [], 'Test 3: countdown(0) returned ' + str(repr(_r2)) + ', expected []'\n_r3 = countdown(5)\nassert _r3 == [5, 4, 3, 2, 1], 'Test 4: countdown(5) returned ' + str(repr(_r3)) + ', expected [5, 4, 3, 2, 1]'",
          "concepts": [
            "range step",
            "negative step"
          ]
        },
        {
          "id": "loop_08",
          "title": "Loop over a string",
          "difficulty": 1,
          "description": "Write a function `letters(word)` returning a list of the characters in `word`, one per item.",
          "hints": [
            "A string is iterable: for ch in word",
            "Append each character"
          ],
          "solution": "def letters(word):\n    result = []\n    for ch in word:\n        result.append(ch)\n    return result",
          "starter_code": "def letters(word):\n    result = []\n",
          "test_code": "assert 'letters' in dir(), \"Function 'letters' not defined. Did you write: def letters(...)?\"\n_r0 = letters('cat')\nassert _r0 == ['c', 'a', 't'], \"Test 1: letters('cat') returned \" + str(repr(_r0)) + \", expected ['c', 'a', 't']\"\n_r1 = letters('')\nassert _r1 == [], \"Test 2: letters('') returned \" + str(repr(_r1)) + ', expected []'\n_r2 = letters('hi')\nassert _r2 == ['h', 'i'], \"Test 3: letters('hi') returned \" + str(repr(_r2)) + \", expected ['h', 'i']\"",
          "concepts": [
            "iterate string",
            "for loop"
          ]
        },
        {
          "id": "loop_09",
          "title": "Multiply everything together",
          "difficulty": 2,
          "description": "Write a function `product(numbers)` returning the product of all numbers. An empty list gives 1.",
          "hints": [
            "Start the accumulator at 1, not 0",
            "Multiplying by 0 would wipe out the answer"
          ],
          "solution": "def product(numbers):\n    running = 1\n    for n in numbers:\n        running *= n\n    return running",
          "starter_code": "def product(numbers):\n    running = 1\n",
          "test_code": "assert 'product' in dir(), \"Function 'product' not defined. Did you write: def product(...)?\"\n_r0 = product([2, 3, 4])\nassert _r0 == 24, 'Test 1: product([2, 3, 4]) returned ' + str(repr(_r0)) + ', expected 24'\n_r1 = product([])\nassert _r1 == 1, 'Test 2: product([]) returned ' + str(repr(_r1)) + ', expected 1'\n_r2 = product([5])\nassert _r2 == 5, 'Test 3: product([5]) returned ' + str(repr(_r2)) + ', expected 5'\n_r3 = product([2, 0, 9])\nassert _r3 == 0, 'Test 4: product([2, 0, 9]) returned ' + str(repr(_r3)) + ', expected 0'",
          "concepts": [
            "accumulator",
            "identity element"
          ]
        },
        {
          "id": "loop_10",
          "title": "Count matching items",
          "difficulty": 2,
          "description": "Write a function `count_positive(numbers)` returning how many numbers are greater than 0.",
          "hints": [
            "Combine a for loop with an if",
            "Only increase the counter when the test passes"
          ],
          "solution": "def count_positive(numbers):\n    count = 0\n    for n in numbers:\n        if n > 0:\n            count += 1\n    return count",
          "starter_code": "def count_positive(numbers):\n    count = 0\n",
          "test_code": "assert 'count_positive' in dir(), \"Function 'count_positive' not defined. Did you write: def count_positive(...)?\"\n_r0 = count_positive([1, -2, 3])\nassert _r0 == 2, 'Test 1: count_positive([1, -2, 3]) returned ' + str(repr(_r0)) + ', expected 2'\n_r1 = count_positive([])\nassert _r1 == 0, 'Test 2: count_positive([]) returned ' + str(repr(_r1)) + ', expected 0'\n_r2 = count_positive([-1, -5])\nassert _r2 == 0, 'Test 3: count_positive([-1, -5]) returned ' + str(repr(_r2)) + ', expected 0'\n_r3 = count_positive([4, 4, 4])\nassert _r3 == 3, 'Test 4: count_positive([4, 4, 4]) returned ' + str(repr(_r3)) + ', expected 3'",
          "concepts": [
            "for loop",
            "conditional inside loop",
            "counter"
          ]
        },
        {
          "id": "loop_11",
          "title": "Keep only the even ones",
          "difficulty": 2,
          "description": "Write a function `keep_even(numbers)` returning a new list holding only the even numbers, in the original order.",
          "hints": [
            "n % 2 == 0 tests for even",
            "Append only when the test passes"
          ],
          "solution": "def keep_even(numbers):\n    result = []\n    for n in numbers:\n        if n % 2 == 0:\n            result.append(n)\n    return result",
          "starter_code": "def keep_even(numbers):\n    result = []\n",
          "test_code": "assert 'keep_even' in dir(), \"Function 'keep_even' not defined. Did you write: def keep_even(...)?\"\n_r0 = keep_even([1, 2, 3, 4])\nassert _r0 == [2, 4], 'Test 1: keep_even([1, 2, 3, 4]) returned ' + str(repr(_r0)) + ', expected [2, 4]'\n_r1 = keep_even([])\nassert _r1 == [], 'Test 2: keep_even([]) returned ' + str(repr(_r1)) + ', expected []'\n_r2 = keep_even([1, 3])\nassert _r2 == [], 'Test 3: keep_even([1, 3]) returned ' + str(repr(_r2)) + ', expected []'\n_r3 = keep_even([0, -2])\nassert _r3 == [0, -2], 'Test 4: keep_even([0, -2]) returned ' + str(repr(_r3)) + ', expected [0, -2]'",
          "concepts": [
            "filter pattern",
            "modulo"
          ]
        },
        {
          "id": "loop_12",
          "title": "Build a sentence",
          "difficulty": 2,
          "description": "Write a function `join_words(words)` returning the words joined by a single space, built with a loop (do not use str.join).",
          "hints": [
            "Add a space before each word except the first",
            "An empty input returns an empty string"
          ],
          "solution": "def join_words(words):\n    out = ''\n    for word in words:\n        if out:\n            out += ' '\n        out += word\n    return out",
          "starter_code": "def join_words(words):\n    out = ''\n",
          "test_code": "assert 'join_words' in dir(), \"Function 'join_words' not defined. Did you write: def join_words(...)?\"\n_r0 = join_words(['a', 'b'])\nassert _r0 == 'a b', \"Test 1: join_words(['a', 'b']) returned \" + str(repr(_r0)) + \", expected 'a b'\"\n_r1 = join_words([])\nassert _r1 == '', 'Test 2: join_words([]) returned ' + str(repr(_r1)) + \", expected ''\"\n_r2 = join_words(['solo'])\nassert _r2 == 'solo', \"Test 3: join_words(['solo']) returned \" + str(repr(_r2)) + \", expected 'solo'\"\n_r3 = join_words(['x', 'y', 'z'])\nassert _r3 == 'x y z', \"Test 4: join_words(['x', 'y', 'z']) returned \" + str(repr(_r3)) + \", expected 'x y z'\"",
          "concepts": [
            "string accumulation",
            "first-iteration special case"
          ]
        },
        {
          "id": "loop_13",
          "title": "A basic while loop",
          "difficulty": 2,
          "description": "Write a function `sum_to(n)` returning 1 + 2 + ... + n using a while loop.",
          "hints": [
            "Set i = 1 before the loop and increase it inside",
            "Forgetting i += 1 loops forever"
          ],
          "solution": "def sum_to(n):\n    total = 0\n    i = 1\n    while i <= n:\n        total += i\n        i += 1\n    return total",
          "starter_code": "def sum_to(n):\n    total = 0\n    i = 1\n",
          "test_code": "assert 'sum_to' in dir(), \"Function 'sum_to' not defined. Did you write: def sum_to(...)?\"\n_r0 = sum_to(5)\nassert _r0 == 15, 'Test 1: sum_to(5) returned ' + str(repr(_r0)) + ', expected 15'\n_r1 = sum_to(1)\nassert _r1 == 1, 'Test 2: sum_to(1) returned ' + str(repr(_r1)) + ', expected 1'\n_r2 = sum_to(0)\nassert _r2 == 0, 'Test 3: sum_to(0) returned ' + str(repr(_r2)) + ', expected 0'\n_r3 = sum_to(10)\nassert _r3 == 55, 'Test 4: sum_to(10) returned ' + str(repr(_r3)) + ', expected 55'",
          "concepts": [
            "while loop",
            "loop counter",
            "termination"
          ]
        },
        {
          "id": "loop_14",
          "title": "Halve until small",
          "difficulty": 2,
          "description": "Write a function `halvings(n)` counting how many times you can halve `n` with integer division before it reaches 0.",
          "hints": [
            "Use // for integer division",
            "Count each pass through the while loop"
          ],
          "solution": "def halvings(n):\n    steps = 0\n    while n > 0:\n        n = n // 2\n        steps += 1\n    return steps",
          "starter_code": "def halvings(n):\n    steps = 0\n",
          "test_code": "assert 'halvings' in dir(), \"Function 'halvings' not defined. Did you write: def halvings(...)?\"\n_r0 = halvings(8)\nassert _r0 == 4, 'Test 1: halvings(8) returned ' + str(repr(_r0)) + ', expected 4'\n_r1 = halvings(1)\nassert _r1 == 1, 'Test 2: halvings(1) returned ' + str(repr(_r1)) + ', expected 1'\n_r2 = halvings(0)\nassert _r2 == 0, 'Test 3: halvings(0) returned ' + str(repr(_r2)) + ', expected 0'\n_r3 = halvings(5)\nassert _r3 == 3, 'Test 4: halvings(5) returned ' + str(repr(_r3)) + ', expected 3'",
          "concepts": [
            "while loop",
            "integer division"
          ]
        },
        {
          "id": "loop_15",
          "title": "Stop early with break",
          "difficulty": 2,
          "description": "Write a function `first_negative(numbers)` returning the first negative number, or None if there is none.",
          "hints": [
            "return exits the function immediately, no break needed",
            "Return None after the loop if nothing matched"
          ],
          "solution": "def first_negative(numbers):\n    for n in numbers:\n        if n < 0:\n            return n\n    return None",
          "starter_code": "def first_negative(numbers):\n",
          "test_code": "assert 'first_negative' in dir(), \"Function 'first_negative' not defined. Did you write: def first_negative(...)?\"\n_r0 = first_negative([1, -2, -3])\nassert _r0 == -2, 'Test 1: first_negative([1, -2, -3]) returned ' + str(repr(_r0)) + ', expected -2'\n_r1 = first_negative([1, 2])\nassert _r1 == None, 'Test 2: first_negative([1, 2]) returned ' + str(repr(_r1)) + ', expected None'\n_r2 = first_negative([])\nassert _r2 == None, 'Test 3: first_negative([]) returned ' + str(repr(_r2)) + ', expected None'\n_r3 = first_negative([-9])\nassert _r3 == -9, 'Test 4: first_negative([-9]) returned ' + str(repr(_r3)) + ', expected -9'",
          "concepts": [
            "early exit",
            "return inside loop",
            "None"
          ]
        },
        {
          "id": "loop_16",
          "title": "Skip with continue",
          "difficulty": 2,
          "description": "Write a function `sum_skipping_zeros(numbers)` that adds every number except the zeros, using continue.",
          "hints": [
            "continue jumps straight to the next pass",
            "Test for n == 0 first"
          ],
          "solution": "def sum_skipping_zeros(numbers):\n    total = 0\n    for n in numbers:\n        if n == 0:\n            continue\n        total += n\n    return total",
          "starter_code": "def sum_skipping_zeros(numbers):\n    total = 0\n",
          "test_code": "assert 'sum_skipping_zeros' in dir(), \"Function 'sum_skipping_zeros' not defined. Did you write: def sum_skipping_zeros(...)?\"\n_r0 = sum_skipping_zeros([1, 0, 2])\nassert _r0 == 3, 'Test 1: sum_skipping_zeros([1, 0, 2]) returned ' + str(repr(_r0)) + ', expected 3'\n_r1 = sum_skipping_zeros([0, 0])\nassert _r1 == 0, 'Test 2: sum_skipping_zeros([0, 0]) returned ' + str(repr(_r1)) + ', expected 0'\n_r2 = sum_skipping_zeros([])\nassert _r2 == 0, 'Test 3: sum_skipping_zeros([]) returned ' + str(repr(_r2)) + ', expected 0'\n_r3 = sum_skipping_zeros([4])\nassert _r3 == 4, 'Test 4: sum_skipping_zeros([4]) returned ' + str(repr(_r3)) + ', expected 4'",
          "concepts": [
            "continue",
            "accumulator"
          ]
        },
        {
          "id": "loop_17",
          "title": "Index and value with enumerate",
          "difficulty": 2,
          "description": "Write a function `label_items(items)` returning a list of strings like '0:a', '1:b' pairing each index with its value.",
          "hints": [
            "for i, value in enumerate(items)",
            "Build each string with an f-string"
          ],
          "solution": "def label_items(items):\n    result = []\n    for i, value in enumerate(items):\n        result.append(f'{i}:{value}')\n    return result",
          "starter_code": "def label_items(items):\n    result = []\n",
          "test_code": "assert 'label_items' in dir(), \"Function 'label_items' not defined. Did you write: def label_items(...)?\"\n_r0 = label_items(['a', 'b'])\nassert _r0 == ['0:a', '1:b'], \"Test 1: label_items(['a', 'b']) returned \" + str(repr(_r0)) + \", expected ['0:a', '1:b']\"\n_r1 = label_items([])\nassert _r1 == [], 'Test 2: label_items([]) returned ' + str(repr(_r1)) + ', expected []'\n_r2 = label_items(['x'])\nassert _r2 == ['0:x'], \"Test 3: label_items(['x']) returned \" + str(repr(_r2)) + \", expected ['0:x']\"",
          "concepts": [
            "enumerate",
            "tuple unpacking",
            "f-string"
          ]
        },
        {
          "id": "loop_18",
          "title": "Find the index",
          "difficulty": 2,
          "description": "Write a function `index_of(items, target)` returning the position of the first match, or -1 if absent.",
          "hints": [
            "enumerate gives you the index for free",
            "-1 is the conventional not-found answer"
          ],
          "solution": "def index_of(items, target):\n    for i, value in enumerate(items):\n        if value == target:\n            return i\n    return -1",
          "starter_code": "def index_of(items, target):\n",
          "test_code": "assert 'index_of' in dir(), \"Function 'index_of' not defined. Did you write: def index_of(...)?\"\n_r0 = index_of(['a', 'b', 'c'], 'b')\nassert _r0 == 1, \"Test 1: index_of(['a', 'b', 'c'], 'b') returned \" + str(repr(_r0)) + ', expected 1'\n_r1 = index_of(['a'], 'z')\nassert _r1 == -1, \"Test 2: index_of(['a'], 'z') returned \" + str(repr(_r1)) + ', expected -1'\n_r2 = index_of([], 'x')\nassert _r2 == -1, \"Test 3: index_of([], 'x') returned \" + str(repr(_r2)) + ', expected -1'\n_r3 = index_of([1, 2, 2], 2)\nassert _r3 == 1, 'Test 4: index_of([1, 2, 2], 2) returned ' + str(repr(_r3)) + ', expected 1'",
          "concepts": [
            "enumerate",
            "search",
            "sentinel value"
          ]
        },
        {
          "id": "loop_19",
          "title": "Walk two lists with zip",
          "difficulty": 2,
          "description": "Write a function `pair_sums(a, b)` returning a list of the element-wise sums. Stop at the shorter list.",
          "hints": [
            "zip(a, b) yields pairs and stops at the shorter one",
            "for x, y in zip(a, b)"
          ],
          "solution": "def pair_sums(a, b):\n    result = []\n    for x, y in zip(a, b):\n        result.append(x + y)\n    return result",
          "starter_code": "def pair_sums(a, b):\n    result = []\n",
          "test_code": "assert 'pair_sums' in dir(), \"Function 'pair_sums' not defined. Did you write: def pair_sums(...)?\"\n_r0 = pair_sums([1, 2], [10, 20])\nassert _r0 == [11, 22], 'Test 1: pair_sums([1, 2], [10, 20]) returned ' + str(repr(_r0)) + ', expected [11, 22]'\n_r1 = pair_sums([1, 2, 3], [1])\nassert _r1 == [2], 'Test 2: pair_sums([1, 2, 3], [1]) returned ' + str(repr(_r1)) + ', expected [2]'\n_r2 = pair_sums([], [])\nassert _r2 == [], 'Test 3: pair_sums([], []) returned ' + str(repr(_r2)) + ', expected []'",
          "concepts": [
            "zip",
            "parallel iteration"
          ]
        },
        {
          "id": "loop_20",
          "title": "Largest value by hand",
          "difficulty": 2,
          "description": "Write a function `largest(numbers)` returning the biggest number without using max. Return None for an empty list.",
          "hints": [
            "Seed the answer with the first element, not 0",
            "Guard the empty case before the loop"
          ],
          "solution": "def largest(numbers):\n    if not numbers:\n        return None\n    best = numbers[0]\n    for n in numbers:\n        if n > best:\n            best = n\n    return best",
          "starter_code": "def largest(numbers):\n    if not numbers:\n        return None\n",
          "test_code": "assert 'largest' in dir(), \"Function 'largest' not defined. Did you write: def largest(...)?\"\n_r0 = largest([3, 9, 2])\nassert _r0 == 9, 'Test 1: largest([3, 9, 2]) returned ' + str(repr(_r0)) + ', expected 9'\n_r1 = largest([])\nassert _r1 == None, 'Test 2: largest([]) returned ' + str(repr(_r1)) + ', expected None'\n_r2 = largest([-5, -2])\nassert _r2 == -2, 'Test 3: largest([-5, -2]) returned ' + str(repr(_r2)) + ', expected -2'\n_r3 = largest([7])\nassert _r3 == 7, 'Test 4: largest([7]) returned ' + str(repr(_r3)) + ', expected 7'",
          "concepts": [
            "running best",
            "empty guard"
          ]
        },
        {
          "id": "loop_21",
          "title": "Reverse a list by hand",
          "difficulty": 2,
          "description": "Write a function `backwards(items)` returning a new list in reverse order, without using reversed or slicing.",
          "hints": [
            "Loop over the indexes from the end downwards",
            "range(len(items) - 1, -1, -1)"
          ],
          "solution": "def backwards(items):\n    result = []\n    for i in range(len(items) - 1, -1, -1):\n        result.append(items[i])\n    return result",
          "starter_code": "def backwards(items):\n    result = []\n",
          "test_code": "assert 'backwards' in dir(), \"Function 'backwards' not defined. Did you write: def backwards(...)?\"\n_r0 = backwards([1, 2, 3])\nassert _r0 == [3, 2, 1], 'Test 1: backwards([1, 2, 3]) returned ' + str(repr(_r0)) + ', expected [3, 2, 1]'\n_r1 = backwards([])\nassert _r1 == [], 'Test 2: backwards([]) returned ' + str(repr(_r1)) + ', expected []'\n_r2 = backwards(['a'])\nassert _r2 == ['a'], \"Test 3: backwards(['a']) returned \" + str(repr(_r2)) + \", expected ['a']\"",
          "concepts": [
            "index loop",
            "negative step",
            "len"
          ]
        },
        {
          "id": "loop_22",
          "title": "Count the vowels",
          "difficulty": 2,
          "description": "Write a function `count_vowels(text)` counting the vowels a, e, i, o, u, ignoring case.",
          "hints": [
            "Lowercase the character before testing",
            "The in operator tests membership: ch in 'aeiou'"
          ],
          "solution": "def count_vowels(text):\n    count = 0\n    for ch in text:\n        if ch.lower() in 'aeiou':\n            count += 1\n    return count",
          "starter_code": "def count_vowels(text):\n    count = 0\n",
          "test_code": "assert 'count_vowels' in dir(), \"Function 'count_vowels' not defined. Did you write: def count_vowels(...)?\"\n_r0 = count_vowels('hello')\nassert _r0 == 2, \"Test 1: count_vowels('hello') returned \" + str(repr(_r0)) + ', expected 2'\n_r1 = count_vowels('')\nassert _r1 == 0, \"Test 2: count_vowels('') returned \" + str(repr(_r1)) + ', expected 0'\n_r2 = count_vowels('XYZ')\nassert _r2 == 0, \"Test 3: count_vowels('XYZ') returned \" + str(repr(_r2)) + ', expected 0'\n_r3 = count_vowels('AEiou')\nassert _r3 == 5, \"Test 4: count_vowels('AEiou') returned \" + str(repr(_r3)) + ', expected 5'",
          "concepts": [
            "iterate string",
            "membership test",
            "case folding"
          ]
        },
        {
          "id": "loop_23",
          "title": "While with a sentinel",
          "difficulty": 3,
          "description": "Write a function `take_until_zero(numbers)` collecting values from the front until a 0 appears. The 0 is not included.",
          "hints": [
            "A while loop with an index is one way",
            "break also works inside a for loop"
          ],
          "solution": "def take_until_zero(numbers):\n    result = []\n    for n in numbers:\n        if n == 0:\n            break\n        result.append(n)\n    return result",
          "starter_code": "def take_until_zero(numbers):\n    result = []\n",
          "test_code": "assert 'take_until_zero' in dir(), \"Function 'take_until_zero' not defined. Did you write: def take_until_zero(...)?\"\n_r0 = take_until_zero([1, 2, 0, 3])\nassert _r0 == [1, 2], 'Test 1: take_until_zero([1, 2, 0, 3]) returned ' + str(repr(_r0)) + ', expected [1, 2]'\n_r1 = take_until_zero([0])\nassert _r1 == [], 'Test 2: take_until_zero([0]) returned ' + str(repr(_r1)) + ', expected []'\n_r2 = take_until_zero([])\nassert _r2 == [], 'Test 3: take_until_zero([]) returned ' + str(repr(_r2)) + ', expected []'\n_r3 = take_until_zero([4, 5])\nassert _r3 == [4, 5], 'Test 4: take_until_zero([4, 5]) returned ' + str(repr(_r3)) + ', expected [4, 5]'",
          "concepts": [
            "break",
            "sentinel value"
          ]
        },
        {
          "id": "loop_24",
          "title": "Loop over a dictionary",
          "difficulty": 3,
          "description": "Write a function `sum_values(scores)` adding up every value in the dictionary.",
          "hints": [
            "scores.values() yields the values",
            "scores.items() gives key and value pairs"
          ],
          "solution": "def sum_values(scores):\n    total = 0\n    for value in scores.values():\n        total += value\n    return total",
          "starter_code": "def sum_values(scores):\n    total = 0\n",
          "test_code": "assert 'sum_values' in dir(), \"Function 'sum_values' not defined. Did you write: def sum_values(...)?\"\n_r0 = sum_values({'a': 1, 'b': 2})\nassert _r0 == 3, \"Test 1: sum_values({'a': 1, 'b': 2}) returned \" + str(repr(_r0)) + ', expected 3'\n_r1 = sum_values({})\nassert _r1 == 0, 'Test 2: sum_values({}) returned ' + str(repr(_r1)) + ', expected 0'\n_r2 = sum_values({'x': -5})\nassert _r2 == -5, \"Test 3: sum_values({'x': -5}) returned \" + str(repr(_r2)) + ', expected -5'",
          "concepts": [
            "dict iteration",
            "values()"
          ]
        },
        {
          "id": "loop_25",
          "title": "Multiplication row",
          "difficulty": 3,
          "description": "Write a function `times_table(n, upto)` returning the list n*1, n*2, ... n*upto.",
          "hints": [
            "range(1, upto + 1) starts at 1 and includes upto",
            "Off-by-one errors live here"
          ],
          "solution": "def times_table(n, upto):\n    result = []\n    for i in range(1, upto + 1):\n        result.append(n * i)\n    return result",
          "starter_code": "def times_table(n, upto):\n    result = []\n",
          "test_code": "assert 'times_table' in dir(), \"Function 'times_table' not defined. Did you write: def times_table(...)?\"\n_r0 = times_table(3, 4)\nassert _r0 == [3, 6, 9, 12], 'Test 1: times_table(3, 4) returned ' + str(repr(_r0)) + ', expected [3, 6, 9, 12]'\n_r1 = times_table(5, 1)\nassert _r1 == [5], 'Test 2: times_table(5, 1) returned ' + str(repr(_r1)) + ', expected [5]'\n_r2 = times_table(2, 0)\nassert _r2 == [], 'Test 3: times_table(2, 0) returned ' + str(repr(_r2)) + ', expected []'\n_r3 = times_table(-1, 3)\nassert _r3 == [-1, -2, -3], 'Test 4: times_table(-1, 3) returned ' + str(repr(_r3)) + ', expected [-1, -2, -3]'",
          "concepts": [
            "range bounds",
            "off-by-one"
          ]
        },
        {
          "id": "loop_26",
          "title": "Nested loops make pairs",
          "difficulty": 3,
          "description": "Write a function `all_pairs(a, b)` returning every (x, y) tuple pairing each item of `a` with each item of `b`.",
          "hints": [
            "Put one for loop inside another",
            "The inner loop restarts on every outer pass"
          ],
          "solution": "def all_pairs(a, b):\n    result = []\n    for x in a:\n        for y in b:\n            result.append((x, y))\n    return result",
          "starter_code": "def all_pairs(a, b):\n    result = []\n",
          "test_code": "assert 'all_pairs' in dir(), \"Function 'all_pairs' not defined. Did you write: def all_pairs(...)?\"\n_r0 = all_pairs([1, 2], ['a'])\nassert _r0 == [(1, 'a'), (2, 'a')], \"Test 1: all_pairs([1, 2], ['a']) returned \" + str(repr(_r0)) + \", expected [(1, 'a'), (2, 'a')]\"\n_r1 = all_pairs([], [1])\nassert _r1 == [], 'Test 2: all_pairs([], [1]) returned ' + str(repr(_r1)) + ', expected []'\n_r2 = all_pairs([1], [2, 3])\nassert _r2 == [(1, 2), (1, 3)], 'Test 3: all_pairs([1], [2, 3]) returned ' + str(repr(_r2)) + ', expected [(1, 2), (1, 3)]'",
          "concepts": [
            "nested loop",
            "tuple",
            "cartesian product"
          ]
        },
        {
          "id": "loop_27",
          "title": "FizzBuzz",
          "difficulty": 3,
          "description": "Write a function `fizzbuzz(n)` returning a list for 1..n where multiples of 3 become 'Fizz', of 5 become 'Buzz', of both become 'FizzBuzz', and everything else stays the number.",
          "hints": [
            "Test the both-case first, or it never fires",
            "Numbers stay as ints, not strings"
          ],
          "solution": "def fizzbuzz(n):\n    result = []\n    for i in range(1, n + 1):\n        if i % 15 == 0:\n            result.append('FizzBuzz')\n        elif i % 3 == 0:\n            result.append('Fizz')\n        elif i % 5 == 0:\n            result.append('Buzz')\n        else:\n            result.append(i)\n    return result",
          "starter_code": "def fizzbuzz(n):\n    result = []\n",
          "test_code": "assert 'fizzbuzz' in dir(), \"Function 'fizzbuzz' not defined. Did you write: def fizzbuzz(...)?\"\n_r0 = fizzbuzz(5)\nassert _r0 == [1, 2, 'Fizz', 4, 'Buzz'], 'Test 1: fizzbuzz(5) returned ' + str(repr(_r0)) + \", expected [1, 2, 'Fizz', 4, 'Buzz']\"\n_r1 = fizzbuzz(3)\nassert _r1 == [1, 2, 'Fizz'], 'Test 2: fizzbuzz(3) returned ' + str(repr(_r1)) + \", expected [1, 2, 'Fizz']\"\n_r2 = fizzbuzz(0)\nassert _r2 == [], 'Test 3: fizzbuzz(0) returned ' + str(repr(_r2)) + ', expected []'\n_r3 = fizzbuzz(15)\nassert _r3 == [1, 2, 'Fizz', 4, 'Buzz', 'Fizz', 7, 8, 'Fizz', 'Buzz', 11, 'Fizz', 13, 14, 'FizzBuzz'], 'Test 4: fizzbuzz(15) returned ' + str(repr(_r3)) + \", expected [1, 2, 'Fizz', 4, 'Buzz', 'Fizz', 7, 8, 'Fizz', 'Buzz', 11, 'Fizz', 13, 14, 'FizzBuzz']\"",
          "concepts": [
            "elif ordering",
            "modulo",
            "for loop"
          ]
        },
        {
          "id": "loop_28",
          "title": "Factorial",
          "difficulty": 3,
          "description": "Write a function `factorial(n)` returning n! using a loop. factorial(0) is 1.",
          "hints": [
            "Start at 1 and multiply up to n",
            "range(1, n + 1) is empty when n is 0, which gives the right answer"
          ],
          "solution": "def factorial(n):\n    result = 1\n    for i in range(1, n + 1):\n        result *= i\n    return result",
          "starter_code": "def factorial(n):\n    result = 1\n",
          "test_code": "assert 'factorial' in dir(), \"Function 'factorial' not defined. Did you write: def factorial(...)?\"\n_r0 = factorial(5)\nassert _r0 == 120, 'Test 1: factorial(5) returned ' + str(repr(_r0)) + ', expected 120'\n_r1 = factorial(0)\nassert _r1 == 1, 'Test 2: factorial(0) returned ' + str(repr(_r1)) + ', expected 1'\n_r2 = factorial(1)\nassert _r2 == 1, 'Test 3: factorial(1) returned ' + str(repr(_r2)) + ', expected 1'\n_r3 = factorial(6)\nassert _r3 == 720, 'Test 4: factorial(6) returned ' + str(repr(_r3)) + ', expected 720'",
          "concepts": [
            "accumulator",
            "range bounds"
          ]
        },
        {
          "id": "loop_29",
          "title": "Fibonacci sequence",
          "difficulty": 3,
          "description": "Write a function `fib(n)` returning the first `n` Fibonacci numbers starting 0, 1.",
          "hints": [
            "Track the previous two values in two variables",
            "a, b = b, a + b updates both at once"
          ],
          "solution": "def fib(n):\n    result = []\n    a, b = 0, 1\n    for _ in range(n):\n        result.append(a)\n        a, b = b, a + b\n    return result",
          "starter_code": "def fib(n):\n    result = []\n    a, b = 0, 1\n",
          "test_code": "assert 'fib' in dir(), \"Function 'fib' not defined. Did you write: def fib(...)?\"\n_r0 = fib(5)\nassert _r0 == [0, 1, 1, 2, 3], 'Test 1: fib(5) returned ' + str(repr(_r0)) + ', expected [0, 1, 1, 2, 3]'\n_r1 = fib(1)\nassert _r1 == [0], 'Test 2: fib(1) returned ' + str(repr(_r1)) + ', expected [0]'\n_r2 = fib(0)\nassert _r2 == [], 'Test 3: fib(0) returned ' + str(repr(_r2)) + ', expected []'\n_r3 = fib(7)\nassert _r3 == [0, 1, 1, 2, 3, 5, 8], 'Test 4: fib(7) returned ' + str(repr(_r3)) + ', expected [0, 1, 1, 2, 3, 5, 8]'",
          "concepts": [
            "multiple assignment",
            "state in a loop"
          ]
        },
        {
          "id": "loop_30",
          "title": "Digit sum",
          "difficulty": 3,
          "description": "Write a function `digit_sum(n)` adding the decimal digits of a non-negative integer.",
          "hints": [
            "n % 10 peels off the last digit",
            "n //= 10 drops it, and the loop ends at 0"
          ],
          "solution": "def digit_sum(n):\n    total = 0\n    while n > 0:\n        total += n % 10\n        n //= 10\n    return total",
          "starter_code": "def digit_sum(n):\n    total = 0\n",
          "test_code": "assert 'digit_sum' in dir(), \"Function 'digit_sum' not defined. Did you write: def digit_sum(...)?\"\n_r0 = digit_sum(123)\nassert _r0 == 6, 'Test 1: digit_sum(123) returned ' + str(repr(_r0)) + ', expected 6'\n_r1 = digit_sum(0)\nassert _r1 == 0, 'Test 2: digit_sum(0) returned ' + str(repr(_r1)) + ', expected 0'\n_r2 = digit_sum(9)\nassert _r2 == 9, 'Test 3: digit_sum(9) returned ' + str(repr(_r2)) + ', expected 9'\n_r3 = digit_sum(1010)\nassert _r3 == 2, 'Test 4: digit_sum(1010) returned ' + str(repr(_r3)) + ', expected 2'",
          "concepts": [
            "while loop",
            "modulo",
            "integer division"
          ]
        },
        {
          "id": "loop_31",
          "title": "Reverse a number",
          "difficulty": 3,
          "description": "Write a function `reverse_number(n)` turning 123 into 321 using arithmetic, not strings.",
          "hints": [
            "Build the answer as reversed = reversed * 10 + digit",
            "Peel digits with % 10 and // 10"
          ],
          "solution": "def reverse_number(n):\n    out = 0\n    while n > 0:\n        out = out * 10 + n % 10\n        n //= 10\n    return out",
          "starter_code": "def reverse_number(n):\n    out = 0\n",
          "test_code": "assert 'reverse_number' in dir(), \"Function 'reverse_number' not defined. Did you write: def reverse_number(...)?\"\n_r0 = reverse_number(123)\nassert _r0 == 321, 'Test 1: reverse_number(123) returned ' + str(repr(_r0)) + ', expected 321'\n_r1 = reverse_number(0)\nassert _r1 == 0, 'Test 2: reverse_number(0) returned ' + str(repr(_r1)) + ', expected 0'\n_r2 = reverse_number(100)\nassert _r2 == 1, 'Test 3: reverse_number(100) returned ' + str(repr(_r2)) + ', expected 1'\n_r3 = reverse_number(7)\nassert _r3 == 7, 'Test 4: reverse_number(7) returned ' + str(repr(_r3)) + ', expected 7'",
          "concepts": [
            "while loop",
            "digit arithmetic"
          ]
        },
        {
          "id": "loop_32",
          "title": "Prime check",
          "difficulty": 3,
          "description": "Write a function `is_prime(n)` returning True when n is prime. Numbers below 2 are not prime.",
          "hints": [
            "Test divisors from 2 up to n - 1",
            "Return False the moment a divisor divides evenly"
          ],
          "solution": "def is_prime(n):\n    if n < 2:\n        return False\n    for d in range(2, n):\n        if n % d == 0:\n            return False\n    return True",
          "starter_code": "def is_prime(n):\n    if n < 2:\n        return False\n",
          "test_code": "assert 'is_prime' in dir(), \"Function 'is_prime' not defined. Did you write: def is_prime(...)?\"\n_r0 = is_prime(7)\nassert _r0 == True, 'Test 1: is_prime(7) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = is_prime(1)\nassert _r1 == False, 'Test 2: is_prime(1) returned ' + str(repr(_r1)) + ', expected False'\n_r2 = is_prime(9)\nassert _r2 == False, 'Test 3: is_prime(9) returned ' + str(repr(_r2)) + ', expected False'\n_r3 = is_prime(2)\nassert _r3 == True, 'Test 4: is_prime(2) returned ' + str(repr(_r3)) + ', expected True'\n_r4 = is_prime(0)\nassert _r4 == False, 'Test 5: is_prime(0) returned ' + str(repr(_r4)) + ', expected False'",
          "concepts": [
            "early return",
            "modulo",
            "guard clause"
          ]
        },
        {
          "id": "loop_33",
          "title": "Remove duplicates, keep order",
          "difficulty": 3,
          "description": "Write a function `dedupe(items)` returning a list with later repeats removed, preserving first-seen order.",
          "hints": [
            "Keep a set of what you have already seen",
            "Membership in a set is the test"
          ],
          "solution": "def dedupe(items):\n    seen = set()\n    result = []\n    for item in items:\n        if item not in seen:\n            seen.add(item)\n            result.append(item)\n    return result",
          "starter_code": "def dedupe(items):\n    seen = set()\n    result = []\n",
          "test_code": "assert 'dedupe' in dir(), \"Function 'dedupe' not defined. Did you write: def dedupe(...)?\"\n_r0 = dedupe([1, 2, 1, 3])\nassert _r0 == [1, 2, 3], 'Test 1: dedupe([1, 2, 1, 3]) returned ' + str(repr(_r0)) + ', expected [1, 2, 3]'\n_r1 = dedupe([])\nassert _r1 == [], 'Test 2: dedupe([]) returned ' + str(repr(_r1)) + ', expected []'\n_r2 = dedupe(['a', 'a'])\nassert _r2 == ['a'], \"Test 3: dedupe(['a', 'a']) returned \" + str(repr(_r2)) + \", expected ['a']\"\n_r3 = dedupe([3, 2, 1])\nassert _r3 == [3, 2, 1], 'Test 4: dedupe([3, 2, 1]) returned ' + str(repr(_r3)) + ', expected [3, 2, 1]'",
          "concepts": [
            "set membership",
            "order preservation"
          ]
        },
        {
          "id": "loop_34",
          "title": "Count each item",
          "difficulty": 3,
          "description": "Write a function `tally(items)` returning a dictionary mapping each item to how many times it appears.",
          "hints": [
            "counts.get(item, 0) gives 0 for a first sighting",
            "Assign back into the dictionary"
          ],
          "solution": "def tally(items):\n    counts = {}\n    for item in items:\n        counts[item] = counts.get(item, 0) + 1\n    return counts",
          "starter_code": "def tally(items):\n    counts = {}\n",
          "test_code": "assert 'tally' in dir(), \"Function 'tally' not defined. Did you write: def tally(...)?\"\n_r0 = tally(['a', 'b', 'a'])\nassert _r0 == {'a': 2, 'b': 1}, \"Test 1: tally(['a', 'b', 'a']) returned \" + str(repr(_r0)) + \", expected {'a': 2, 'b': 1}\"\n_r1 = tally([])\nassert _r1 == {}, 'Test 2: tally([]) returned ' + str(repr(_r1)) + ', expected {}'\n_r2 = tally([1, 1, 1])\nassert _r2 == {1: 3}, 'Test 3: tally([1, 1, 1]) returned ' + str(repr(_r2)) + ', expected {1: 3}'",
          "concepts": [
            "dict accumulation",
            "get with default"
          ]
        },
        {
          "id": "loop_35",
          "title": "Flatten one level",
          "difficulty": 3,
          "description": "Write a function `flatten(rows)` turning a list of lists into a single flat list.",
          "hints": [
            "Loop over the rows, then over each row",
            "extend or an inner append both work"
          ],
          "solution": "def flatten(rows):\n    result = []\n    for row in rows:\n        for item in row:\n            result.append(item)\n    return result",
          "starter_code": "def flatten(rows):\n    result = []\n",
          "test_code": "assert 'flatten' in dir(), \"Function 'flatten' not defined. Did you write: def flatten(...)?\"\n_r0 = flatten([[1, 2], [3]])\nassert _r0 == [1, 2, 3], 'Test 1: flatten([[1, 2], [3]]) returned ' + str(repr(_r0)) + ', expected [1, 2, 3]'\n_r1 = flatten([])\nassert _r1 == [], 'Test 2: flatten([]) returned ' + str(repr(_r1)) + ', expected []'\n_r2 = flatten([[], []])\nassert _r2 == [], 'Test 3: flatten([[], []]) returned ' + str(repr(_r2)) + ', expected []'\n_r3 = flatten([['a'], ['b', 'c']])\nassert _r3 == ['a', 'b', 'c'], \"Test 4: flatten([['a'], ['b', 'c']]) returned \" + str(repr(_r3)) + \", expected ['a', 'b', 'c']\"",
          "concepts": [
            "nested loop",
            "flatten"
          ]
        },
        {
          "id": "loop_36",
          "title": "Running totals",
          "difficulty": 3,
          "description": "Write a function `running_total(numbers)` returning the cumulative sum after each item.",
          "hints": [
            "Keep one accumulator and append it every pass",
            "The output is the same length as the input"
          ],
          "solution": "def running_total(numbers):\n    result = []\n    total = 0\n    for n in numbers:\n        total += n\n        result.append(total)\n    return result",
          "starter_code": "def running_total(numbers):\n    result = []\n    total = 0\n",
          "test_code": "assert 'running_total' in dir(), \"Function 'running_total' not defined. Did you write: def running_total(...)?\"\n_r0 = running_total([1, 2, 3])\nassert _r0 == [1, 3, 6], 'Test 1: running_total([1, 2, 3]) returned ' + str(repr(_r0)) + ', expected [1, 3, 6]'\n_r1 = running_total([])\nassert _r1 == [], 'Test 2: running_total([]) returned ' + str(repr(_r1)) + ', expected []'\n_r2 = running_total([5])\nassert _r2 == [5], 'Test 3: running_total([5]) returned ' + str(repr(_r2)) + ', expected [5]'\n_r3 = running_total([1, -1])\nassert _r3 == [1, 0], 'Test 4: running_total([1, -1]) returned ' + str(repr(_r3)) + ', expected [1, 0]'",
          "concepts": [
            "accumulator",
            "cumulative sum"
          ]
        },
        {
          "id": "loop_37",
          "title": "Chunk a list",
          "difficulty": 4,
          "description": "Write a function `chunk(items, size)` splitting the list into pieces of length `size`. The final piece may be shorter.",
          "hints": [
            "Step through the indexes with range(0, len(items), size)",
            "Slice items[i:i + size]"
          ],
          "solution": "def chunk(items, size):\n    result = []\n    for i in range(0, len(items), size):\n        result.append(items[i:i + size])\n    return result",
          "starter_code": "def chunk(items, size):\n    result = []\n",
          "test_code": "assert 'chunk' in dir(), \"Function 'chunk' not defined. Did you write: def chunk(...)?\"\n_r0 = chunk([1, 2, 3, 4, 5], 2)\nassert _r0 == [[1, 2], [3, 4], [5]], 'Test 1: chunk([1, 2, 3, 4, 5], 2) returned ' + str(repr(_r0)) + ', expected [[1, 2], [3, 4], [5]]'\n_r1 = chunk([], 3)\nassert _r1 == [], 'Test 2: chunk([], 3) returned ' + str(repr(_r1)) + ', expected []'\n_r2 = chunk([1, 2], 5)\nassert _r2 == [[1, 2]], 'Test 3: chunk([1, 2], 5) returned ' + str(repr(_r2)) + ', expected [[1, 2]]'",
          "concepts": [
            "range step",
            "slicing",
            "index loop"
          ]
        },
        {
          "id": "loop_38",
          "title": "Moving average",
          "difficulty": 4,
          "description": "Write a function `moving_average(values, window)` returning the mean of each consecutive window. Return an empty list when the input is shorter than the window.",
          "hints": [
            "The last start index is len(values) - window",
            "sum(slice) / window gives each average"
          ],
          "solution": "def moving_average(values, window):\n    result = []\n    for i in range(len(values) - window + 1):\n        piece = values[i:i + window]\n        result.append(sum(piece) / window)\n    return result",
          "starter_code": "def moving_average(values, window):\n    result = []\n",
          "test_code": "assert 'moving_average' in dir(), \"Function 'moving_average' not defined. Did you write: def moving_average(...)?\"\n_r0 = moving_average([1, 2, 3, 4], 2)\nassert _r0 == [1.5, 2.5, 3.5], 'Test 1: moving_average([1, 2, 3, 4], 2) returned ' + str(repr(_r0)) + ', expected [1.5, 2.5, 3.5]'\n_r1 = moving_average([1], 3)\nassert _r1 == [], 'Test 2: moving_average([1], 3) returned ' + str(repr(_r1)) + ', expected []'\n_r2 = moving_average([2, 4, 6], 3)\nassert _r2 == [4.0], 'Test 3: moving_average([2, 4, 6], 3) returned ' + str(repr(_r2)) + ', expected [4.0]'",
          "concepts": [
            "sliding window",
            "slicing",
            "range bounds"
          ]
        },
        {
          "id": "loop_39",
          "title": "Star pyramid",
          "difficulty": 4,
          "description": "Write a function `pyramid(n)` returning a list of n strings: one star, then two, and so on.",
          "hints": [
            "'*' * i repeats the character",
            "range(1, n + 1) gives the widths"
          ],
          "solution": "def pyramid(n):\n    result = []\n    for i in range(1, n + 1):\n        result.append('*' * i)\n    return result",
          "starter_code": "def pyramid(n):\n    result = []\n",
          "test_code": "assert 'pyramid' in dir(), \"Function 'pyramid' not defined. Did you write: def pyramid(...)?\"\n_r0 = pyramid(3)\nassert _r0 == ['*', '**', '***'], 'Test 1: pyramid(3) returned ' + str(repr(_r0)) + \", expected ['*', '**', '***']\"\n_r1 = pyramid(1)\nassert _r1 == ['*'], 'Test 2: pyramid(1) returned ' + str(repr(_r1)) + \", expected ['*']\"\n_r2 = pyramid(0)\nassert _r2 == [], 'Test 3: pyramid(0) returned ' + str(repr(_r2)) + ', expected []'",
          "concepts": [
            "string repetition",
            "range bounds"
          ]
        },
        {
          "id": "loop_40",
          "title": "Transpose a grid",
          "difficulty": 4,
          "description": "Write a function `transpose(grid)` swapping rows and columns of a rectangular list of lists.",
          "hints": [
            "The new row count equals the old column count",
            "Index grid[r][c] inside two loops"
          ],
          "solution": "def transpose(grid):\n    if not grid:\n        return []\n    result = []\n    for c in range(len(grid[0])):\n        row = []\n        for r in range(len(grid)):\n            row.append(grid[r][c])\n        result.append(row)\n    return result",
          "starter_code": "def transpose(grid):\n    if not grid:\n        return []\n    result = []\n",
          "test_code": "assert 'transpose' in dir(), \"Function 'transpose' not defined. Did you write: def transpose(...)?\"\n_r0 = transpose([[1, 2], [3, 4]])\nassert _r0 == [[1, 3], [2, 4]], 'Test 1: transpose([[1, 2], [3, 4]]) returned ' + str(repr(_r0)) + ', expected [[1, 3], [2, 4]]'\n_r1 = transpose([])\nassert _r1 == [], 'Test 2: transpose([]) returned ' + str(repr(_r1)) + ', expected []'\n_r2 = transpose([[1, 2, 3]])\nassert _r2 == [[1], [2], [3]], 'Test 3: transpose([[1, 2, 3]]) returned ' + str(repr(_r2)) + ', expected [[1], [2], [3]]'",
          "concepts": [
            "nested index loop",
            "matrix"
          ]
        },
        {
          "id": "loop_41",
          "title": "Bubble sort",
          "difficulty": 4,
          "description": "Write a function `bubble_sort(numbers)` returning a new sorted list using repeated neighbour swaps. Do not call sorted.",
          "hints": [
            "Copy the input first with list(numbers)",
            "Swap with items[j], items[j+1] = items[j+1], items[j]"
          ],
          "solution": "def bubble_sort(numbers):\n    items = list(numbers)\n    for i in range(len(items)):\n        for j in range(len(items) - i - 1):\n            if items[j] > items[j + 1]:\n                items[j], items[j + 1] = items[j + 1], items[j]\n    return items",
          "starter_code": "def bubble_sort(numbers):\n    items = list(numbers)\n",
          "test_code": "assert 'bubble_sort' in dir(), \"Function 'bubble_sort' not defined. Did you write: def bubble_sort(...)?\"\n_r0 = bubble_sort([3, 1, 2])\nassert _r0 == [1, 2, 3], 'Test 1: bubble_sort([3, 1, 2]) returned ' + str(repr(_r0)) + ', expected [1, 2, 3]'\n_r1 = bubble_sort([])\nassert _r1 == [], 'Test 2: bubble_sort([]) returned ' + str(repr(_r1)) + ', expected []'\n_r2 = bubble_sort([5])\nassert _r2 == [5], 'Test 3: bubble_sort([5]) returned ' + str(repr(_r2)) + ', expected [5]'\n_r3 = bubble_sort([2, 2, 1])\nassert _r3 == [1, 2, 2], 'Test 4: bubble_sort([2, 2, 1]) returned ' + str(repr(_r3)) + ', expected [1, 2, 2]'",
          "concepts": [
            "nested loop",
            "swap",
            "in-place mutation"
          ]
        },
        {
          "id": "loop_42",
          "title": "Binary search",
          "difficulty": 4,
          "description": "Write a function `binary_search(sorted_items, target)` returning the index of `target`, or -1. Halve the range each pass.",
          "hints": [
            "Track low and high bounds, then compare against the midpoint",
            "mid = (low + high) // 2"
          ],
          "solution": "def binary_search(sorted_items, target):\n    low = 0\n    high = len(sorted_items) - 1\n    while low <= high:\n        mid = (low + high) // 2\n        if sorted_items[mid] == target:\n            return mid\n        if sorted_items[mid] < target:\n            low = mid + 1\n        else:\n            high = mid - 1\n    return -1",
          "starter_code": "def binary_search(sorted_items, target):\n    low = 0\n    high = len(sorted_items) - 1\n",
          "test_code": "assert 'binary_search' in dir(), \"Function 'binary_search' not defined. Did you write: def binary_search(...)?\"\n_r0 = binary_search([1, 3, 5, 7], 5)\nassert _r0 == 2, 'Test 1: binary_search([1, 3, 5, 7], 5) returned ' + str(repr(_r0)) + ', expected 2'\n_r1 = binary_search([1, 3, 5, 7], 2)\nassert _r1 == -1, 'Test 2: binary_search([1, 3, 5, 7], 2) returned ' + str(repr(_r1)) + ', expected -1'\n_r2 = binary_search([], 1)\nassert _r2 == -1, 'Test 3: binary_search([], 1) returned ' + str(repr(_r2)) + ', expected -1'\n_r3 = binary_search([4], 4)\nassert _r3 == 0, 'Test 4: binary_search([4], 4) returned ' + str(repr(_r3)) + ', expected 0'",
          "concepts": [
            "while loop",
            "two bounds",
            "integer division"
          ]
        },
        {
          "id": "loop_43",
          "title": "Run-length encode",
          "difficulty": 4,
          "description": "Write a function `encode(text)` turning 'aaab' into [('a', 3), ('b', 1)].",
          "hints": [
            "Track the current character and how many in a row",
            "Flush the last run after the loop ends"
          ],
          "solution": "def encode(text):\n    result = []\n    current = None\n    count = 0\n    for ch in text:\n        if ch == current:\n            count += 1\n        else:\n            if current is not None:\n                result.append((current, count))\n            current = ch\n            count = 1\n    if current is not None:\n        result.append((current, count))\n    return result",
          "starter_code": "def encode(text):\n    result = []\n    current = None\n    count = 0\n",
          "test_code": "assert 'encode' in dir(), \"Function 'encode' not defined. Did you write: def encode(...)?\"\n_r0 = encode('aaab')\nassert _r0 == [('a', 3), ('b', 1)], \"Test 1: encode('aaab') returned \" + str(repr(_r0)) + \", expected [('a', 3), ('b', 1)]\"\n_r1 = encode('')\nassert _r1 == [], \"Test 2: encode('') returned \" + str(repr(_r1)) + ', expected []'\n_r2 = encode('ab')\nassert _r2 == [('a', 1), ('b', 1)], \"Test 3: encode('ab') returned \" + str(repr(_r2)) + \", expected [('a', 1), ('b', 1)]\"\n_r3 = encode('cc')\nassert _r3 == [('c', 2)], \"Test 4: encode('cc') returned \" + str(repr(_r3)) + \", expected [('c', 2)]\"",
          "concepts": [
            "state across passes",
            "flush after loop",
            "tuple"
          ]
        },
        {
          "id": "loop_44",
          "title": "Two-sum with nested loops",
          "difficulty": 4,
          "description": "Write a function `two_sum(numbers, target)` returning the first (i, j) index pair whose values add to `target`, or None.",
          "hints": [
            "The inner loop starts at i + 1 to avoid reusing an index",
            "Return as soon as a pair matches"
          ],
          "solution": "def two_sum(numbers, target):\n    for i in range(len(numbers)):\n        for j in range(i + 1, len(numbers)):\n            if numbers[i] + numbers[j] == target:\n                return (i, j)\n    return None",
          "starter_code": "def two_sum(numbers, target):\n",
          "test_code": "assert 'two_sum' in dir(), \"Function 'two_sum' not defined. Did you write: def two_sum(...)?\"\n_r0 = two_sum([1, 2, 3], 5)\nassert _r0 == (1, 2), 'Test 1: two_sum([1, 2, 3], 5) returned ' + str(repr(_r0)) + ', expected (1, 2)'\n_r1 = two_sum([1, 2], 9)\nassert _r1 == None, 'Test 2: two_sum([1, 2], 9) returned ' + str(repr(_r1)) + ', expected None'\n_r2 = two_sum([], 0)\nassert _r2 == None, 'Test 3: two_sum([], 0) returned ' + str(repr(_r2)) + ', expected None'\n_r3 = two_sum([3, 3], 6)\nassert _r3 == (0, 1), 'Test 4: two_sum([3, 3], 6) returned ' + str(repr(_r3)) + ', expected (0, 1)'",
          "concepts": [
            "nested loop",
            "index pairs",
            "early return"
          ]
        },
        {
          "id": "loop_45",
          "title": "Collatz steps",
          "difficulty": 4,
          "description": "Write a function `collatz_steps(n)` counting how many halve-or-triple steps it takes to reach 1.",
          "hints": [
            "Even numbers halve, odd numbers become 3n + 1",
            "n = 1 needs zero steps"
          ],
          "solution": "def collatz_steps(n):\n    steps = 0\n    while n != 1:\n        if n % 2 == 0:\n            n //= 2\n        else:\n            n = 3 * n + 1\n        steps += 1\n    return steps",
          "starter_code": "def collatz_steps(n):\n    steps = 0\n",
          "test_code": "assert 'collatz_steps' in dir(), \"Function 'collatz_steps' not defined. Did you write: def collatz_steps(...)?\"\n_r0 = collatz_steps(1)\nassert _r0 == 0, 'Test 1: collatz_steps(1) returned ' + str(repr(_r0)) + ', expected 0'\n_r1 = collatz_steps(2)\nassert _r1 == 1, 'Test 2: collatz_steps(2) returned ' + str(repr(_r1)) + ', expected 1'\n_r2 = collatz_steps(3)\nassert _r2 == 7, 'Test 3: collatz_steps(3) returned ' + str(repr(_r2)) + ', expected 7'\n_r3 = collatz_steps(6)\nassert _r3 == 8, 'Test 4: collatz_steps(6) returned ' + str(repr(_r3)) + ', expected 8'",
          "concepts": [
            "while loop",
            "branching inside a loop"
          ]
        },
        {
          "id": "loop_46",
          "title": "Greatest common divisor",
          "difficulty": 4,
          "description": "Write a function `gcd(a, b)` using Euclid's method: replace the pair with (b, a % b) until b is 0.",
          "hints": [
            "a, b = b, a % b updates both in one line",
            "The answer is a once b hits 0"
          ],
          "solution": "def gcd(a, b):\n    while b != 0:\n        a, b = b, a % b\n    return a",
          "starter_code": "def gcd(a, b):\n",
          "test_code": "assert 'gcd' in dir(), \"Function 'gcd' not defined. Did you write: def gcd(...)?\"\n_r0 = gcd(12, 8)\nassert _r0 == 4, 'Test 1: gcd(12, 8) returned ' + str(repr(_r0)) + ', expected 4'\n_r1 = gcd(7, 13)\nassert _r1 == 1, 'Test 2: gcd(7, 13) returned ' + str(repr(_r1)) + ', expected 1'\n_r2 = gcd(9, 0)\nassert _r2 == 9, 'Test 3: gcd(9, 0) returned ' + str(repr(_r2)) + ', expected 9'\n_r3 = gcd(100, 75)\nassert _r3 == 25, 'Test 4: gcd(100, 75) returned ' + str(repr(_r3)) + ', expected 25'",
          "concepts": [
            "while loop",
            "multiple assignment",
            "modulo"
          ]
        },
        {
          "id": "loop_47",
          "title": "The loop else clause",
          "difficulty": 5,
          "description": "Write a function `all_positive(numbers)` returning True only when every number is above 0, using a for loop with an else clause.",
          "hints": [
            "The else after a for runs only when no break fired",
            "Break on the first failure"
          ],
          "solution": "def all_positive(numbers):\n    for n in numbers:\n        if n <= 0:\n            break\n    else:\n        return True\n    return False",
          "starter_code": "def all_positive(numbers):\n    for n in numbers:\n",
          "test_code": "assert 'all_positive' in dir(), \"Function 'all_positive' not defined. Did you write: def all_positive(...)?\"\n_r0 = all_positive([1, 2])\nassert _r0 == True, 'Test 1: all_positive([1, 2]) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = all_positive([1, -1])\nassert _r1 == False, 'Test 2: all_positive([1, -1]) returned ' + str(repr(_r1)) + ', expected False'\n_r2 = all_positive([])\nassert _r2 == True, 'Test 3: all_positive([]) returned ' + str(repr(_r2)) + ', expected True'\n_r3 = all_positive([0])\nassert _r3 == False, 'Test 4: all_positive([0]) returned ' + str(repr(_r3)) + ', expected False'",
          "concepts": [
            "for-else",
            "break",
            "no-break semantics"
          ]
        },
        {
          "id": "loop_48",
          "title": "Longest winning streak",
          "difficulty": 5,
          "description": "Write a function `longest_streak(results)` returning the longest run of consecutive 'W' entries.",
          "hints": [
            "Track the current run and the best run separately",
            "Reset the current run on any non-W"
          ],
          "solution": "def longest_streak(results):\n    best = 0\n    current = 0\n    for r in results:\n        if r == 'W':\n            current += 1\n            if current > best:\n                best = current\n        else:\n            current = 0\n    return best",
          "starter_code": "def longest_streak(results):\n    best = 0\n    current = 0\n",
          "test_code": "assert 'longest_streak' in dir(), \"Function 'longest_streak' not defined. Did you write: def longest_streak(...)?\"\n_r0 = longest_streak(['W', 'W', 'L', 'W'])\nassert _r0 == 2, \"Test 1: longest_streak(['W', 'W', 'L', 'W']) returned \" + str(repr(_r0)) + ', expected 2'\n_r1 = longest_streak([])\nassert _r1 == 0, 'Test 2: longest_streak([]) returned ' + str(repr(_r1)) + ', expected 0'\n_r2 = longest_streak(['L'])\nassert _r2 == 0, \"Test 3: longest_streak(['L']) returned \" + str(repr(_r2)) + ', expected 0'\n_r3 = longest_streak(['W', 'W', 'W'])\nassert _r3 == 3, \"Test 4: longest_streak(['W', 'W', 'W']) returned \" + str(repr(_r3)) + ', expected 3'",
          "concepts": [
            "two accumulators",
            "reset on failure",
            "streak"
          ]
        },
        {
          "id": "loop_49",
          "title": "Peak drawdown",
          "difficulty": 5,
          "description": "Write a function `max_drawdown(equity)` returning the largest drop from any prior peak, as a positive number.",
          "hints": [
            "Carry the highest value seen so far",
            "The drop is peak minus the current value"
          ],
          "solution": "def max_drawdown(equity):\n    peak = None\n    worst = 0\n    for value in equity:\n        if peak is None or value > peak:\n            peak = value\n        drop = peak - value\n        if drop > worst:\n            worst = drop\n    return worst",
          "starter_code": "def max_drawdown(equity):\n    peak = None\n    worst = 0\n",
          "test_code": "assert 'max_drawdown' in dir(), \"Function 'max_drawdown' not defined. Did you write: def max_drawdown(...)?\"\n_r0 = max_drawdown([100, 120, 90, 110])\nassert _r0 == 30, 'Test 1: max_drawdown([100, 120, 90, 110]) returned ' + str(repr(_r0)) + ', expected 30'\n_r1 = max_drawdown([])\nassert _r1 == 0, 'Test 2: max_drawdown([]) returned ' + str(repr(_r1)) + ', expected 0'\n_r2 = max_drawdown([50])\nassert _r2 == 0, 'Test 3: max_drawdown([50]) returned ' + str(repr(_r2)) + ', expected 0'\n_r3 = max_drawdown([10, 5, 20, 1])\nassert _r3 == 19, 'Test 4: max_drawdown([10, 5, 20, 1]) returned ' + str(repr(_r3)) + ', expected 19'",
          "concepts": [
            "running peak",
            "state across passes",
            "real-world accumulation"
          ]
        },
        {
          "id": "loop_50",
          "title": "Group consecutive runs",
          "difficulty": 5,
          "description": "Write a function `group_runs(items)` splitting a list into sublists of equal neighbouring values.",
          "hints": [
            "Start a new group whenever the value changes",
            "Append the final group after the loop"
          ],
          "solution": "def group_runs(items):\n    groups = []\n    current = []\n    for item in items:\n        if current and item != current[-1]:\n            groups.append(current)\n            current = []\n        current.append(item)\n    if current:\n        groups.append(current)\n    return groups",
          "starter_code": "def group_runs(items):\n    groups = []\n    current = []\n",
          "test_code": "assert 'group_runs' in dir(), \"Function 'group_runs' not defined. Did you write: def group_runs(...)?\"\n_r0 = group_runs([1, 1, 2, 3, 3])\nassert _r0 == [[1, 1], [2], [3, 3]], 'Test 1: group_runs([1, 1, 2, 3, 3]) returned ' + str(repr(_r0)) + ', expected [[1, 1], [2], [3, 3]]'\n_r1 = group_runs([])\nassert _r1 == [], 'Test 2: group_runs([]) returned ' + str(repr(_r1)) + ', expected []'\n_r2 = group_runs([4])\nassert _r2 == [[4]], 'Test 3: group_runs([4]) returned ' + str(repr(_r2)) + ', expected [[4]]'\n_r3 = group_runs(['a', 'b', 'b'])\nassert _r3 == [['a'], ['b', 'b']], \"Test 4: group_runs(['a', 'b', 'b']) returned \" + str(repr(_r3)) + \", expected [['a'], ['b', 'b']]\"",
          "concepts": [
            "grouping",
            "flush after loop",
            "look-back with index -1"
          ]
        }
      ]
    },
    {
      "id": "functions",
      "title": "Functions",
      "exercise_count": 50,
      "exercises": [
        {
          "id": "func_01",
          "title": "Define a Simple Function",
          "difficulty": 1,
          "description": "Define a function named `greet` that takes a name parameter and returns 'Hello, {name}!'",
          "hints": [
            "Use the `def` keyword to define a function",
            "Use an f-string to interpolate the name into the greeting"
          ],
          "solution": "def greet(name):\n    return f'Hello, {name}!'",
          "starter_code": "",
          "test_code": "assert 'greet' in dir(), \"Function 'greet' not defined. Did you write: def greet(...)?\"\n_r0 = greet('Alice')\nassert _r0 == 'Hello, Alice!', \"Test 1: greet('Alice') returned \" + str(repr(_r0)) + \", expected 'Hello, Alice!'\"\n_r1 = greet('Bob')\nassert _r1 == 'Hello, Bob!', \"Test 2: greet('Bob') returned \" + str(repr(_r1)) + \", expected 'Hello, Bob!'\"\n_r2 = greet('World')\nassert _r2 == 'Hello, World!', \"Test 3: greet('World') returned \" + str(repr(_r2)) + \", expected 'Hello, World!'\"",
          "concepts": [
            "function definition",
            "parameters",
            "return values",
            "f-strings"
          ]
        },
        {
          "id": "func_02",
          "title": "Function with Multiple Parameters",
          "difficulty": 1,
          "description": "Define a function `add` that takes two numbers and returns their sum.",
          "hints": [
            "Define the function with two parameters",
            "Use the + operator to add them"
          ],
          "solution": "def add(a, b):\n    return a + b",
          "starter_code": "",
          "test_code": "assert 'add' in dir(), \"Function 'add' not defined. Did you write: def add(...)?\"\n_r0 = add(2, 3)\nassert _r0 == 5, 'Test 1: add(2, 3) returned ' + str(repr(_r0)) + ', expected 5'\n_r1 = add(10, 20)\nassert _r1 == 30, 'Test 2: add(10, 20) returned ' + str(repr(_r1)) + ', expected 30'\n_r2 = add(-5, 3)\nassert _r2 == -2, 'Test 3: add(-5, 3) returned ' + str(repr(_r2)) + ', expected -2'\n_r3 = add(0, 0)\nassert _r3 == 0, 'Test 4: add(0, 0) returned ' + str(repr(_r3)) + ', expected 0'",
          "concepts": [
            "parameters",
            "return values",
            "arithmetic"
          ]
        },
        {
          "id": "func_03",
          "title": "Function with No Return Value",
          "difficulty": 1,
          "description": "Define a function `print_twice` that prints a message twice. It should not return anything.",
          "hints": [
            "Use `print()` twice",
            "A function without an explicit return returns None"
          ],
          "solution": "def print_twice(msg):\n    print(msg)\n    print(msg)",
          "starter_code": "",
          "test_code": "assert 'print_twice' in dir(), \"Function 'print_twice' not defined. Did you write: def print_twice(...)?\"\n_r0 = print_twice('Hello')\nassert _r0 == None, \"Test 1: print_twice('Hello') returned \" + str(repr(_r0)) + ', expected None'\n_r1 = print_twice('Test')\nassert _r1 == None, \"Test 2: print_twice('Test') returned \" + str(repr(_r1)) + ', expected None'\n_r2 = print_twice('Python')\nassert _r2 == None, \"Test 3: print_twice('Python') returned \" + str(repr(_r2)) + ', expected None'",
          "concepts": [
            "side effects",
            "print",
            "None return"
          ]
        },
        {
          "id": "func_04",
          "title": "Function Returning Boolean",
          "difficulty": 1,
          "description": "Define a function `is_even` that takes an integer and returns True if it's even, False otherwise.",
          "hints": [
            "Use the modulo operator % to check if a number is divisible by 2",
            "Return True if n % 2 == 0"
          ],
          "solution": "def is_even(n):\n    return n % 2 == 0",
          "starter_code": "",
          "test_code": "assert 'is_even' in dir(), \"Function 'is_even' not defined. Did you write: def is_even(...)?\"\n_r0 = is_even(2)\nassert _r0 == True, 'Test 1: is_even(2) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = is_even(3)\nassert _r1 == False, 'Test 2: is_even(3) returned ' + str(repr(_r1)) + ', expected False'\n_r2 = is_even(0)\nassert _r2 == True, 'Test 3: is_even(0) returned ' + str(repr(_r2)) + ', expected True'\n_r3 = is_even(100)\nassert _r3 == True, 'Test 4: is_even(100) returned ' + str(repr(_r3)) + ', expected True'\n_r4 = is_even(99)\nassert _r4 == False, 'Test 5: is_even(99) returned ' + str(repr(_r4)) + ', expected False'",
          "concepts": [
            "return values",
            "booleans",
            "conditionals"
          ]
        },
        {
          "id": "func_05",
          "title": "Function with Conditional Logic",
          "difficulty": 1,
          "description": "Define a function `absolute_value` that returns the absolute value of a number without using abs().",
          "hints": [
            "Use an if-else statement",
            "Return -n if n < 0, otherwise return n"
          ],
          "solution": "def absolute_value(n):\n    if n < 0:\n        return -n\n    else:\n        return n",
          "starter_code": "",
          "test_code": "assert 'absolute_value' in dir(), \"Function 'absolute_value' not defined. Did you write: def absolute_value(...)?\"\n_r0 = absolute_value(5)\nassert _r0 == 5, 'Test 1: absolute_value(5) returned ' + str(repr(_r0)) + ', expected 5'\n_r1 = absolute_value(-5)\nassert _r1 == 5, 'Test 2: absolute_value(-5) returned ' + str(repr(_r1)) + ', expected 5'\n_r2 = absolute_value(0)\nassert _r2 == 0, 'Test 3: absolute_value(0) returned ' + str(repr(_r2)) + ', expected 0'\n_r3 = absolute_value(-100)\nassert _r3 == 100, 'Test 4: absolute_value(-100) returned ' + str(repr(_r3)) + ', expected 100'",
          "concepts": [
            "conditional logic",
            "if-else"
          ]
        },
        {
          "id": "func_06",
          "title": "Default Parameter Values",
          "difficulty": 1,
          "description": "Define a function `greet_formal` that takes a name and an optional greeting. Default greeting is 'Hello'. Example: greet_formal('Alice', 'Hi') returns 'Hi, Alice!'",
          "hints": [
            "Use a default parameter with =",
            "greeting='Hello' makes greeting optional"
          ],
          "solution": "def greet_formal(name, greeting='Hello'):\n    return f'{greeting}, {name}!'",
          "starter_code": "",
          "test_code": "assert 'greet_formal' in dir(), \"Function 'greet_formal' not defined. Did you write: def greet_formal(...)?\"\n_r0 = greet_formal('Alice', 'Hi')\nassert _r0 == 'Hi, Alice!', \"Test 1: greet_formal('Alice', 'Hi') returned \" + str(repr(_r0)) + \", expected 'Hi, Alice!'\"\n_r1 = greet_formal('Bob')\nassert _r1 == 'Hello, Bob!', \"Test 2: greet_formal('Bob') returned \" + str(repr(_r1)) + \", expected 'Hello, Bob!'\"\n_r2 = greet_formal('Eve', 'Hey')\nassert _r2 == 'Hey, Eve!', \"Test 3: greet_formal('Eve', 'Hey') returned \" + str(repr(_r2)) + \", expected 'Hey, Eve!'\"",
          "concepts": [
            "default parameters",
            "optional arguments"
          ]
        },
        {
          "id": "func_07",
          "title": "Function Returning Multiple Values",
          "difficulty": 1,
          "description": "Define a function `swap` that takes two values and returns them swapped as a tuple.",
          "hints": [
            "Return a tuple with both values in reversed order",
            "Use parentheses or just comma-separate the return values"
          ],
          "solution": "def swap(a, b):\n    return (b, a)",
          "starter_code": "",
          "test_code": "assert 'swap' in dir(), \"Function 'swap' not defined. Did you write: def swap(...)?\"\n_r0 = swap(1, 2)\nassert _r0 == (2, 1), 'Test 1: swap(1, 2) returned ' + str(repr(_r0)) + ', expected (2, 1)'\n_r1 = swap('x', 'y')\nassert _r1 == ('y', 'x'), \"Test 2: swap('x', 'y') returned \" + str(repr(_r1)) + \", expected ('y', 'x')\"\n_r2 = swap(10, 20)\nassert _r2 == (20, 10), 'Test 3: swap(10, 20) returned ' + str(repr(_r2)) + ', expected (20, 10)'",
          "concepts": [
            "multiple return values",
            "tuples"
          ]
        },
        {
          "id": "func_08",
          "title": "Function with String Operations",
          "difficulty": 1,
          "description": "Define a function `reverse_string` that takes a string and returns it reversed.",
          "hints": [
            "Use string slicing with [::-1]",
            "Or iterate through and build the reversed string"
          ],
          "solution": "def reverse_string(s):\n    return s[::-1]",
          "starter_code": "",
          "test_code": "assert 'reverse_string' in dir(), \"Function 'reverse_string' not defined. Did you write: def reverse_string(...)?\"\n_r0 = reverse_string('hello')\nassert _r0 == 'olleh', \"Test 1: reverse_string('hello') returned \" + str(repr(_r0)) + \", expected 'olleh'\"\n_r1 = reverse_string('Python')\nassert _r1 == 'nohtyP', \"Test 2: reverse_string('Python') returned \" + str(repr(_r1)) + \", expected 'nohtyP'\"\n_r2 = reverse_string('a')\nassert _r2 == 'a', \"Test 3: reverse_string('a') returned \" + str(repr(_r2)) + \", expected 'a'\"\n_r3 = reverse_string('')\nassert _r3 == '', \"Test 4: reverse_string('') returned \" + str(repr(_r3)) + \", expected ''\"",
          "concepts": [
            "string slicing",
            "strings"
          ]
        },
        {
          "id": "func_09",
          "title": "Function with List Operations",
          "difficulty": 1,
          "description": "Define a function `sum_list` that takes a list of numbers and returns their sum.",
          "hints": [
            "Use the built-in sum() function",
            "Or iterate through the list with a for loop and accumulate"
          ],
          "solution": "def sum_list(numbers):\n    return sum(numbers)",
          "starter_code": "",
          "test_code": "assert 'sum_list' in dir(), \"Function 'sum_list' not defined. Did you write: def sum_list(...)?\"\n_r0 = sum_list([1, 2, 3])\nassert _r0 == 6, 'Test 1: sum_list([1, 2, 3]) returned ' + str(repr(_r0)) + ', expected 6'\n_r1 = sum_list([10, 20])\nassert _r1 == 30, 'Test 2: sum_list([10, 20]) returned ' + str(repr(_r1)) + ', expected 30'\n_r2 = sum_list([-1, 1])\nassert _r2 == 0, 'Test 3: sum_list([-1, 1]) returned ' + str(repr(_r2)) + ', expected 0'\n_r3 = sum_list([])\nassert _r3 == 0, 'Test 4: sum_list([]) returned ' + str(repr(_r3)) + ', expected 0'",
          "concepts": [
            "lists",
            "iteration",
            "sum"
          ]
        },
        {
          "id": "func_10",
          "title": "Function with Dictionary Return",
          "difficulty": 1,
          "description": "Define a function `person_dict` that takes name and age, returning a dictionary with keys 'name' and 'age'.",
          "hints": [
            "Create a dictionary with {'name': name, 'age': age}",
            "Return the dictionary"
          ],
          "solution": "def person_dict(name, age):\n    return {'name': name, 'age': age}",
          "starter_code": "",
          "test_code": "assert 'person_dict' in dir(), \"Function 'person_dict' not defined. Did you write: def person_dict(...)?\"\n_r0 = person_dict('Alice', 30)\nassert _r0 == {'name': 'Alice', 'age': 30}, \"Test 1: person_dict('Alice', 30) returned \" + str(repr(_r0)) + \", expected {'name': 'Alice', 'age': 30}\"\n_r1 = person_dict('Bob', 25)\nassert _r1 == {'name': 'Bob', 'age': 25}, \"Test 2: person_dict('Bob', 25) returned \" + str(repr(_r1)) + \", expected {'name': 'Bob', 'age': 25}\"",
          "concepts": [
            "dictionaries",
            "return values"
          ]
        },
        {
          "id": "func_11",
          "title": "Keyword Arguments",
          "difficulty": 2,
          "description": "Define a function `describe_pet` that takes breed and name as keyword arguments and returns '{name} is a {breed}'. Must work with describe_pet(breed='dog', name='Buddy').",
          "hints": [
            "Define parameters that can be passed as keyword arguments",
            "Arguments with names can be passed in any order when using keywords"
          ],
          "solution": "def describe_pet(breed, name):\n    return f'{name} is a {breed}'",
          "starter_code": "",
          "test_code": "assert 'describe_pet' in dir(), \"Function 'describe_pet' not defined. Did you write: def describe_pet(...)?\"\n_r0 = describe_pet('dog', 'Buddy')\nassert _r0 == 'Buddy is a dog', \"Test 1: describe_pet('dog', 'Buddy') returned \" + str(repr(_r0)) + \", expected 'Buddy is a dog'\"\n_r1 = describe_pet('cat', 'Whiskers')\nassert _r1 == 'Whiskers is a cat', \"Test 2: describe_pet('cat', 'Whiskers') returned \" + str(repr(_r1)) + \", expected 'Whiskers is a cat'\"",
          "concepts": [
            "keyword arguments",
            "named parameters"
          ]
        },
        {
          "id": "func_12",
          "title": "*args: Variable Arguments",
          "difficulty": 2,
          "description": "Define a function `multiply_all` that takes any number of arguments and returns their product.",
          "hints": [
            "Use *args to capture variable positional arguments",
            "*args is a tuple, so you can iterate over it"
          ],
          "solution": "def multiply_all(*args):\n    result = 1\n    for n in args:\n        result *= n\n    return result",
          "starter_code": "",
          "test_code": "assert 'multiply_all' in dir(), \"'multiply_all' is not defined\"\nassert callable(multiply_all), \"'multiply_all' should be a function\"",
          "concepts": [
            "*args",
            "variable arguments",
            "iteration"
          ]
        },
        {
          "id": "func_13",
          "title": "**kwargs: Keyword Arguments Dict",
          "difficulty": 2,
          "description": "Define a function `build_query` that takes **kwargs and returns a string of 'key=value' pairs joined by '&'. Example: build_query(name='Alice', age=30) returns 'name=Alice&age=30'.",
          "hints": [
            "Use **kwargs to capture keyword arguments as a dictionary",
            "Iterate over kwargs.items() to get key-value pairs"
          ],
          "solution": "def build_query(**kwargs):\n    pairs = [f'{k}={v}' for k, v in kwargs.items()]\n    return '&'.join(pairs)",
          "starter_code": "",
          "test_code": "assert 'build_query' in dir(), \"'build_query' is not defined\"\nassert callable(build_query), \"'build_query' should be a function\"",
          "concepts": [
            "**kwargs",
            "keyword arguments",
            "dictionaries"
          ]
        },
        {
          "id": "func_14",
          "title": "Combining *args and **kwargs",
          "difficulty": 2,
          "description": "Define a function `print_all` that takes *args and **kwargs, and returns a string: 'Args: {args_list}\\nKwargs: {kwargs_dict}'.",
          "hints": [
            "Define both *args and **kwargs in the function signature",
            "Convert them to strings for the output"
          ],
          "solution": "def print_all(*args, **kwargs):\n    return f'Args: {list(args)}\\nKwargs: {kwargs}'",
          "starter_code": "",
          "test_code": "assert 'print_all' in dir(), \"'print_all' is not defined\"\nassert callable(print_all), \"'print_all' should be a function\"",
          "concepts": [
            "*args",
            "**kwargs",
            "combined arguments"
          ]
        },
        {
          "id": "func_15",
          "title": "Scope: Local vs Global",
          "difficulty": 2,
          "description": "Define a function `modify_outer` that takes x and returns x + y where y = 5 is defined outside the function. The outer y should be accessible.",
          "hints": [
            "Variables defined outside a function are in the global scope",
            "A function can read global variables directly"
          ],
          "solution": "def modify_outer(x):\n    y = 5\n    return x + y",
          "starter_code": "",
          "test_code": "assert 'modify_outer' in dir(), \"Function 'modify_outer' not defined. Did you write: def modify_outer(...)?\"\n_r0 = modify_outer(10)\nassert _r0 == 15, 'Test 1: modify_outer(10) returned ' + str(repr(_r0)) + ', expected 15'\n_r1 = modify_outer(20)\nassert _r1 == 25, 'Test 2: modify_outer(20) returned ' + str(repr(_r1)) + ', expected 25'",
          "concepts": [
            "scope",
            "local variables",
            "function variables"
          ]
        },
        {
          "id": "func_16",
          "title": "Unpacking Arguments",
          "difficulty": 2,
          "description": "Define a function `add_three` that takes three numbers and returns their sum. Test it by unpacking a list: add_three(*[1, 2, 3]).",
          "hints": [
            "Define the function normally with three parameters",
            "The * operator unpacks an iterable into positional arguments"
          ],
          "solution": "def add_three(a, b, c):\n    return a + b + c",
          "starter_code": "",
          "test_code": "assert 'add_three' in dir(), \"Function 'add_three' not defined. Did you write: def add_three(...)?\"\n_r0 = add_three(1, 2, 3)\nassert _r0 == 6, 'Test 1: add_three(1, 2, 3) returned ' + str(repr(_r0)) + ', expected 6'\n_r1 = add_three(10, 20, 30)\nassert _r1 == 60, 'Test 2: add_three(10, 20, 30) returned ' + str(repr(_r1)) + ', expected 60'",
          "concepts": [
            "argument unpacking",
            "parameter passing"
          ]
        },
        {
          "id": "func_17",
          "title": "Function with Type Checking in Check",
          "difficulty": 2,
          "description": "Write a function `is_positive_number` that checks if input is a number > 0.",
          "hints": [
            "Use isinstance() to check if the value is int or float",
            "Check if the value is greater than 0"
          ],
          "solution": "def is_positive_number(x):\n    return isinstance(x, (int, float)) and x > 0",
          "starter_code": "",
          "test_code": "assert 'is_positive_number' in dir(), \"Function 'is_positive_number' not defined. Did you write: def is_positive_number(...)?\"\n_r0 = is_positive_number(5)\nassert _r0 == True, 'Test 1: is_positive_number(5) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = is_positive_number(0)\nassert _r1 == False, 'Test 2: is_positive_number(0) returned ' + str(repr(_r1)) + ', expected False'\n_r2 = is_positive_number(-3)\nassert _r2 == False, 'Test 3: is_positive_number(-3) returned ' + str(repr(_r2)) + ', expected False'\n_r3 = is_positive_number(3.5)\nassert _r3 == True, 'Test 4: is_positive_number(3.5) returned ' + str(repr(_r3)) + ', expected True'",
          "concepts": [
            "type checking",
            "isinstance"
          ]
        },
        {
          "id": "func_18",
          "title": "Function Returning Function Result",
          "difficulty": 2,
          "description": "Define `call_twice` that takes a function and a value, calls the function twice on the value, and returns the final result. Example: call_twice(lambda x: x * 2, 3) should return 12.",
          "hints": [
            "Call the function once to get an intermediate result",
            "Call the function again with the intermediate result"
          ],
          "solution": "def call_twice(func, x):\n    x = func(x)\n    return func(x)",
          "starter_code": "",
          "test_code": "assert 'call_twice' in dir(), \"'call_twice' is not defined\"\nassert callable(call_twice), \"'call_twice' should be a function\"",
          "concepts": [
            "higher-order functions",
            "function arguments"
          ]
        },
        {
          "id": "func_19",
          "title": "List Comprehension with Function",
          "difficulty": 2,
          "description": "Define a function `square_even_numbers` that takes a list and returns a list of squares of only the even numbers.",
          "hints": [
            "Use a list comprehension with a condition",
            "Check if n % 2 == 0 to filter even numbers"
          ],
          "solution": "def square_even_numbers(numbers):\n    return [n**2 for n in numbers if n % 2 == 0]",
          "starter_code": "",
          "test_code": "assert 'square_even_numbers' in dir(), \"Function 'square_even_numbers' not defined. Did you write: def square_even_numbers(...)?\"\n_r0 = square_even_numbers([1, 2, 3, 4, 5, 6])\nassert _r0 == [4, 16, 36], 'Test 1: square_even_numbers([1, 2, 3, 4, 5, 6]) returned ' + str(repr(_r0)) + ', expected [4, 16, 36]'\n_r1 = square_even_numbers([2, 4, 6])\nassert _r1 == [4, 16, 36], 'Test 2: square_even_numbers([2, 4, 6]) returned ' + str(repr(_r1)) + ', expected [4, 16, 36]'",
          "concepts": [
            "list comprehension",
            "filtering",
            "lambda"
          ]
        },
        {
          "id": "func_20",
          "title": "Docstring and Help",
          "difficulty": 2,
          "description": "Define a function `divide` that takes two numbers and returns a / b. Include a docstring: 'Return a divided by b.'",
          "hints": [
            "Add a docstring as the first line inside the function",
            "Use triple quotes for docstrings"
          ],
          "solution": "def divide(a, b):\n    \"\"\"Return a divided by b.\"\"\"\n    return a / b",
          "starter_code": "",
          "test_code": "assert 'divide' in dir(), \"Function 'divide' not defined. Did you write: def divide(...)?\"\n_r0 = divide(10, 2)\nassert _r0 == 5.0, 'Test 1: divide(10, 2) returned ' + str(repr(_r0)) + ', expected 5.0'\n_r1 = divide(15, 3)\nassert _r1 == 5.0, 'Test 2: divide(15, 3) returned ' + str(repr(_r1)) + ', expected 5.0'",
          "concepts": [
            "docstrings",
            "documentation"
          ]
        },
        {
          "id": "func_21",
          "title": "Lambda Functions",
          "difficulty": 3,
          "description": "Use `map()` with a lambda to square all numbers in a list [1, 2, 3, 4]. Return as a list.",
          "hints": [
            "Lambda syntax: lambda x: x**2",
            "map() returns an iterator, convert to list"
          ],
          "solution": "def square_with_map(numbers):\n    return list(map(lambda x: x**2, numbers))",
          "starter_code": "",
          "test_code": "assert 'square_with_map' in dir(), \"Function 'square_with_map' not defined. Did you write: def square_with_map(...)?\"\n_r0 = square_with_map([1, 2, 3, 4])\nassert _r0 == [1, 4, 9, 16], 'Test 1: square_with_map([1, 2, 3, 4]) returned ' + str(repr(_r0)) + ', expected [1, 4, 9, 16]'\n_r1 = square_with_map([5, 10])\nassert _r1 == [25, 100], 'Test 2: square_with_map([5, 10]) returned ' + str(repr(_r1)) + ', expected [25, 100]'",
          "concepts": [
            "lambda functions",
            "map",
            "functional programming"
          ]
        },
        {
          "id": "func_22",
          "title": "Filter with Lambda",
          "difficulty": 3,
          "description": "Use `filter()` with a lambda to keep only words longer than 3 characters from a list.",
          "hints": [
            "Lambda syntax: lambda word: len(word) > 3",
            "filter() returns an iterator, convert to list"
          ],
          "solution": "def filter_long_words(words):\n    return list(filter(lambda word: len(word) > 3, words))",
          "starter_code": "",
          "test_code": "assert 'filter_long_words' in dir(), \"Function 'filter_long_words' not defined. Did you write: def filter_long_words(...)?\"\n_r0 = filter_long_words(['cat', 'elephant', 'dog', 'ant'])\nassert _r0 == ['elephant'], \"Test 1: filter_long_words(['cat', 'elephant', 'dog', 'ant']) returned \" + str(repr(_r0)) + \", expected ['elephant']\"\n_r1 = filter_long_words(['hi', 'hello', 'hey', 'python'])\nassert _r1 == ['hello', 'python'], \"Test 2: filter_long_words(['hi', 'hello', 'hey', 'python']) returned \" + str(repr(_r1)) + \", expected ['hello', 'python']\"",
          "concepts": [
            "filter",
            "lambda",
            "functional programming"
          ]
        },
        {
          "id": "func_23",
          "title": "Reduce with Lambda",
          "difficulty": 3,
          "description": "Use `functools.reduce()` with a lambda to multiply all numbers in a list [2, 3, 4].",
          "hints": [
            "Import reduce from functools",
            "Lambda syntax: lambda a, b: a * b"
          ],
          "solution": "from functools import reduce\ndef multiply_list(numbers):\n    return reduce(lambda a, b: a * b, numbers)",
          "starter_code": "",
          "test_code": "assert 'multiply_list' in dir(), \"Function 'multiply_list' not defined. Did you write: def multiply_list(...)?\"\n_r0 = multiply_list([2, 3, 4])\nassert _r0 == 24, 'Test 1: multiply_list([2, 3, 4]) returned ' + str(repr(_r0)) + ', expected 24'\n_r1 = multiply_list([5, 2])\nassert _r1 == 10, 'Test 2: multiply_list([5, 2]) returned ' + str(repr(_r1)) + ', expected 10'",
          "concepts": [
            "reduce",
            "lambda",
            "functools"
          ]
        },
        {
          "id": "func_24",
          "title": "Closure: Inner Function",
          "difficulty": 3,
          "description": "Define a function `make_adder` that takes x and returns a function that adds x to any number. Example: add_5 = make_adder(5); add_5(3) returns 8.",
          "hints": [
            "Define an inner function inside make_adder",
            "The inner function uses the outer function's variable x"
          ],
          "solution": "def make_adder(x):\n    def adder(y):\n        return x + y\n    return adder",
          "starter_code": "",
          "test_code": "assert 'make_adder' in dir(), \"'make_adder' is not defined\"\nassert callable(make_adder), \"'make_adder' should be a function\"",
          "concepts": [
            "closures",
            "nested functions",
            "lexical scope"
          ]
        },
        {
          "id": "func_25",
          "title": "Closure with Counter",
          "difficulty": 3,
          "description": "Define a function `make_counter` that returns a function that increments and returns a counter each time it's called.",
          "hints": [
            "Use a nonlocal variable to modify the counter in the outer scope",
            "Return the inner function"
          ],
          "solution": "def make_counter():\n    count = 0\n    def increment():\n        nonlocal count\n        count += 1\n        return count\n    return increment",
          "starter_code": "",
          "test_code": "assert 'make_counter' in dir(), \"'make_counter' is not defined\"\nassert callable(make_counter), \"'make_counter' should be a function\"",
          "concepts": [
            "closures",
            "nonlocal",
            "state management"
          ]
        },
        {
          "id": "func_26",
          "title": "Simple Decorator",
          "difficulty": 3,
          "description": "Write a decorator `add_exclamation` that wraps a function and adds '!' to its return value. Apply it to a function that returns 'hello'.",
          "hints": [
            "A decorator is a function that takes a function and returns a modified function",
            "Use def decorator(func): ... return wrapper"
          ],
          "solution": "def add_exclamation(func):\n    def wrapper(*args, **kwargs):\n        result = func(*args, **kwargs)\n        return result + '!'\n    return wrapper",
          "starter_code": "",
          "test_code": "assert 'add_exclamation' in dir(), \"'add_exclamation' is not defined\"\nassert callable(add_exclamation), \"'add_exclamation' should be a function\"",
          "concepts": [
            "decorators",
            "higher-order functions",
            "function wrapping"
          ]
        },
        {
          "id": "func_27",
          "title": "Decorator with Arguments",
          "difficulty": 3,
          "description": "Write a decorator `repeat` that takes n and repeats a function's return value n times. Example: @repeat(3) on func returning 'hi' would return 'hihihi'.",
          "hints": [
            "Use nested functions: decorator(n) returns a decorator that takes func",
            "The innermost function is the actual wrapper"
          ],
          "solution": "def repeat(n):\n    def decorator(func):\n        def wrapper(*args, **kwargs):\n            return func(*args, **kwargs) * n\n        return wrapper\n    return decorator",
          "starter_code": "",
          "test_code": "assert 'repeat' in dir(), \"'repeat' is not defined\"\nassert callable(repeat), \"'repeat' should be a function\"",
          "concepts": [
            "decorators with arguments",
            "nested decorators"
          ]
        },
        {
          "id": "func_28",
          "title": "Recursive Function: Factorial",
          "difficulty": 3,
          "description": "Define a function `factorial` that computes n! recursively. 5! = 5 * 4 * 3 * 2 * 1 = 120.",
          "hints": [
            "Base case: factorial(0) = 1 or factorial(1) = 1",
            "Recursive case: factorial(n) = n * factorial(n-1)"
          ],
          "solution": "def factorial(n):\n    if n <= 1:\n        return 1\n    return n * factorial(n - 1)",
          "starter_code": "",
          "test_code": "assert 'factorial' in dir(), \"Function 'factorial' not defined. Did you write: def factorial(...)?\"\n_r0 = factorial(0)\nassert _r0 == 1, 'Test 1: factorial(0) returned ' + str(repr(_r0)) + ', expected 1'\n_r1 = factorial(1)\nassert _r1 == 1, 'Test 2: factorial(1) returned ' + str(repr(_r1)) + ', expected 1'\n_r2 = factorial(5)\nassert _r2 == 120, 'Test 3: factorial(5) returned ' + str(repr(_r2)) + ', expected 120'\n_r3 = factorial(6)\nassert _r3 == 720, 'Test 4: factorial(6) returned ' + str(repr(_r3)) + ', expected 720'",
          "concepts": [
            "recursion",
            "base case",
            "recursive calls"
          ]
        },
        {
          "id": "func_29",
          "title": "Recursive Function: Fibonacci",
          "difficulty": 3,
          "description": "Define a function `fibonacci` that returns the nth Fibonacci number recursively. fibonacci(5) = 5.",
          "hints": [
            "Base cases: fib(0) = 0, fib(1) = 1",
            "Recursive case: fib(n) = fib(n-1) + fib(n-2)"
          ],
          "solution": "def fibonacci(n):\n    if n <= 1:\n        return n\n    return fibonacci(n - 1) + fibonacci(n - 2)",
          "starter_code": "",
          "test_code": "assert 'fibonacci' in dir(), \"Function 'fibonacci' not defined. Did you write: def fibonacci(...)?\"\n_r0 = fibonacci(0)\nassert _r0 == 0, 'Test 1: fibonacci(0) returned ' + str(repr(_r0)) + ', expected 0'\n_r1 = fibonacci(1)\nassert _r1 == 1, 'Test 2: fibonacci(1) returned ' + str(repr(_r1)) + ', expected 1'\n_r2 = fibonacci(5)\nassert _r2 == 5, 'Test 3: fibonacci(5) returned ' + str(repr(_r2)) + ', expected 5'\n_r3 = fibonacci(6)\nassert _r3 == 8, 'Test 4: fibonacci(6) returned ' + str(repr(_r3)) + ', expected 8'",
          "concepts": [
            "recursion",
            "fibonacci"
          ]
        },
        {
          "id": "func_30",
          "title": "Recursive Function: Power",
          "difficulty": 3,
          "description": "Define a function `power` that computes x^n recursively without using **.",
          "hints": [
            "Base case: power(x, 0) = 1",
            "Recursive case: power(x, n) = x * power(x, n-1)"
          ],
          "solution": "def power(x, n):\n    if n == 0:\n        return 1\n    return x * power(x, n - 1)",
          "starter_code": "",
          "test_code": "assert 'power' in dir(), \"Function 'power' not defined. Did you write: def power(...)?\"\n_r0 = power(2, 0)\nassert _r0 == 1, 'Test 1: power(2, 0) returned ' + str(repr(_r0)) + ', expected 1'\n_r1 = power(2, 3)\nassert _r1 == 8, 'Test 2: power(2, 3) returned ' + str(repr(_r1)) + ', expected 8'\n_r2 = power(3, 4)\nassert _r2 == 81, 'Test 3: power(3, 4) returned ' + str(repr(_r2)) + ', expected 81'",
          "concepts": [
            "recursion",
            "exponentiation"
          ]
        },
        {
          "id": "func_31",
          "title": "Generator Function: Simple",
          "difficulty": 3,
          "description": "Define a generator function `count_up` that yields numbers from 1 to n (inclusive).",
          "hints": [
            "Use the `yield` keyword to make it a generator",
            "yield produces values one at a time"
          ],
          "solution": "def count_up(n):\n    i = 1\n    while i <= n:\n        yield i\n        i += 1",
          "starter_code": "",
          "test_code": "assert 'count_up' in dir(), \"'count_up' is not defined\"\nassert callable(count_up), \"'count_up' should be a function\"",
          "concepts": [
            "generators",
            "yield",
            "iterators"
          ]
        },
        {
          "id": "func_32",
          "title": "Generator Expression",
          "difficulty": 3,
          "description": "Use a generator expression (like list comprehension but with parens) to generate squares of numbers 1-5. Convert to list.",
          "hints": [
            "Syntax: (x**2 for x in range(1, 6))",
            "Convert to list with list()"
          ],
          "solution": "def squares_generator():\n    return list(x**2 for x in range(1, 6))",
          "starter_code": "",
          "test_code": "assert 'squares_generator' in dir(), \"Function 'squares_generator' not defined. Did you write: def squares_generator(...)?\"\n_r0 = squares_generator()\nassert _r0 == [1, 4, 9, 16, 25], 'Test 1: squares_generator() returned ' + str(repr(_r0)) + ', expected [1, 4, 9, 16, 25]'",
          "concepts": [
            "generators",
            "generator expressions"
          ]
        },
        {
          "id": "func_33",
          "title": "Type Hints: Basic",
          "difficulty": 3,
          "description": "Define a function `add_numbers(a: int, b: int) -> int:` that adds two integers and returns an int.",
          "hints": [
            "Use : type for parameters and -> type for return",
            "Type hints are for documentation, not enforcement"
          ],
          "solution": "def add_numbers(a: int, b: int) -> int:\n    return a + b",
          "starter_code": "",
          "test_code": "assert 'add_numbers' in dir(), \"Function 'add_numbers' not defined. Did you write: def add_numbers(...)?\"\n_r0 = add_numbers(3, 5)\nassert _r0 == 8, 'Test 1: add_numbers(3, 5) returned ' + str(repr(_r0)) + ', expected 8'\n_r1 = add_numbers(10, -2)\nassert _r1 == 8, 'Test 2: add_numbers(10, -2) returned ' + str(repr(_r1)) + ', expected 8'",
          "concepts": [
            "type hints",
            "annotations"
          ]
        },
        {
          "id": "func_34",
          "title": "Type Hints with Collections",
          "difficulty": 3,
          "description": "Define a function `sum_numbers(numbers: list[int]) -> int:` that sums a list of integers.",
          "hints": [
            "Use list[int] for a list of integers",
            "Return type is int"
          ],
          "solution": "def sum_numbers(numbers: list[int]) -> int:\n    return sum(numbers)",
          "starter_code": "",
          "test_code": "assert 'sum_numbers' in dir(), \"Function 'sum_numbers' not defined. Did you write: def sum_numbers(...)?\"\n_r0 = sum_numbers([1, 2, 3])\nassert _r0 == 6, 'Test 1: sum_numbers([1, 2, 3]) returned ' + str(repr(_r0)) + ', expected 6'\n_r1 = sum_numbers([10, 20])\nassert _r1 == 30, 'Test 2: sum_numbers([10, 20]) returned ' + str(repr(_r1)) + ', expected 30'",
          "concepts": [
            "type hints",
            "generics"
          ]
        },
        {
          "id": "func_35",
          "title": "Nonlocal Scope",
          "difficulty": 3,
          "description": "Define a function `make_multiplier` that returns a function multiplying by a factor. Use nonlocal to modify a variable from the outer scope.",
          "hints": [
            "Use nonlocal to allow inner function to modify outer variable",
            "Return the inner function"
          ],
          "solution": "def make_multiplier(factor):\n    def multiply(x):\n        return x * factor\n    return multiply",
          "starter_code": "",
          "test_code": "assert 'make_multiplier' in dir(), \"'make_multiplier' is not defined\"\nassert callable(make_multiplier), \"'make_multiplier' should be a function\"",
          "concepts": [
            "nonlocal",
            "closures",
            "scope"
          ]
        },
        {
          "id": "func_36",
          "title": "Retry Decorator",
          "difficulty": 4,
          "description": "Write a decorator `retry(n)` that retries a function up to n times if it raises an exception. On the nth failure, re-raise the exception.",
          "hints": [
            "Use a loop to retry",
            "Catch exceptions and check if retries remain",
            "Use try-except"
          ],
          "solution": "def retry(n):\n    def decorator(func):\n        def wrapper(*args, **kwargs):\n            for i in range(n):\n                try:\n                    return func(*args, **kwargs)\n                except:\n                    if i == n - 1:\n                        raise\n        return wrapper\n    return decorator",
          "starter_code": "",
          "test_code": "assert 'retry' in dir(), \"'retry' is not defined\"\nassert callable(retry), \"'retry' should be a function\"",
          "concepts": [
            "decorators",
            "exception handling",
            "retry logic"
          ]
        },
        {
          "id": "func_37",
          "title": "Memoize Decorator",
          "difficulty": 4,
          "description": "Write a decorator `memoize` using a closure to cache function results. fibonacci(100) should be instant on second call.",
          "hints": [
            "Use a dictionary to cache (args -> result)",
            "Check cache before calling the function"
          ],
          "solution": "def memoize(func):\n    cache = {}\n    def wrapper(*args):\n        if args not in cache:\n            cache[args] = func(*args)\n        return cache[args]\n    return wrapper",
          "starter_code": "",
          "test_code": "assert 'memoize' in dir(), \"'memoize' is not defined\"\nassert callable(memoize), \"'memoize' should be a function\"",
          "concepts": [
            "memoization",
            "decorators",
            "closures",
            "performance"
          ]
        },
        {
          "id": "func_38",
          "title": "Pipeline Function Composition",
          "difficulty": 4,
          "description": "Write a function `pipeline` that takes multiple functions and returns a function that applies them left-to-right. pipeline([str.upper, str.reverse]) should uppercase then reverse.",
          "hints": [
            "Create a wrapper function that applies each function in order",
            "Use functools.reduce if desired"
          ],
          "solution": "def pipeline(functions):\n    def composed(x):\n        for func in functions:\n            x = func(x)\n        return x\n    return composed",
          "starter_code": "",
          "test_code": "assert 'pipeline' in dir(), \"'pipeline' is not defined\"\nassert callable(pipeline), \"'pipeline' should be a function\"",
          "concepts": [
            "function composition",
            "higher-order functions"
          ]
        },
        {
          "id": "func_39",
          "title": "Compound Interest Calculator",
          "difficulty": 4,
          "description": "Write a function `compound_interest(principal, rate, time, n=1)` that calculates final amount using A = P(1 + r/n)^(nt). Default n=1 (annual).",
          "hints": [
            "Use ** for exponentiation",
            "rate should be decimal (5% = 0.05)"
          ],
          "solution": "def compound_interest(principal, rate, time, n=1):\n    return principal * (1 + rate / n) ** (n * time)",
          "starter_code": "",
          "test_code": "assert 'compound_interest' in dir(), \"Function 'compound_interest' not defined. Did you write: def compound_interest(...)?\"\n_r0 = compound_interest(1000, 0.05, 1)\nassert _r0 == 1050.0, 'Test 1: compound_interest(1000, 0.05, 1) returned ' + str(repr(_r0)) + ', expected 1050.0'\n_r1 = compound_interest(1000, 0.05, 2, 4)\nassert _r1 == 1104.486101181412, 'Test 2: compound_interest(1000, 0.05, 2, 4) returned ' + str(repr(_r1)) + ', expected 1104.486101181412'",
          "concepts": [
            "mathematical functions",
            "parameters",
            "formulas"
          ]
        },
        {
          "id": "func_40",
          "title": "Email Validator Function",
          "difficulty": 4,
          "description": "Write a function `is_valid_email(email)` that returns True if email has format 'something@domain.com'. Use regex or simple string checks.",
          "hints": [
            "Check for @ symbol",
            "Check for . after @",
            "Simple validation: '@' in email and '.' in email.split('@')[1]"
          ],
          "solution": "def is_valid_email(email):\n    return '@' in email and '.' in email.split('@')[1] if '@' in email else False",
          "starter_code": "",
          "test_code": "assert 'is_valid_email' in dir(), \"Function 'is_valid_email' not defined. Did you write: def is_valid_email(...)?\"\n_r0 = is_valid_email('user@example.com')\nassert _r0 == True, \"Test 1: is_valid_email('user@example.com') returned \" + str(repr(_r0)) + ', expected True'\n_r1 = is_valid_email('user@example')\nassert _r1 == False, \"Test 2: is_valid_email('user@example') returned \" + str(repr(_r1)) + ', expected False'\n_r2 = is_valid_email('invalid.email')\nassert _r2 == False, \"Test 3: is_valid_email('invalid.email') returned \" + str(repr(_r2)) + ', expected False'",
          "concepts": [
            "validation",
            "string operations"
          ]
        },
        {
          "id": "func_41",
          "title": "Text Processor: Title Case",
          "difficulty": 4,
          "description": "Write a function `title_case_words` that takes a sentence and returns it with each word capitalized, using title() or manual capitalization.",
          "hints": [
            "Use str.title() or capitalize each word",
            "split() to get words, join() to reassemble"
          ],
          "solution": "def title_case_words(sentence):\n    return ' '.join(word.capitalize() for word in sentence.split())",
          "starter_code": "",
          "test_code": "assert 'title_case_words' in dir(), \"Function 'title_case_words' not defined. Did you write: def title_case_words(...)?\"\n_r0 = title_case_words('hello world')\nassert _r0 == 'Hello World', \"Test 1: title_case_words('hello world') returned \" + str(repr(_r0)) + \", expected 'Hello World'\"\n_r1 = title_case_words('python is fun')\nassert _r1 == 'Python Is Fun', \"Test 2: title_case_words('python is fun') returned \" + str(repr(_r1)) + \", expected 'Python Is Fun'\"",
          "concepts": [
            "string processing",
            "text transformation"
          ]
        },
        {
          "id": "func_42",
          "title": "Data Transformer: Parse CSV",
          "difficulty": 4,
          "description": "Write a function `parse_csv_line(line)` that takes 'name,age,city' and returns {'name': val, 'age': val, 'city': val}. Assume headers are ['name', 'age', 'city'].",
          "hints": [
            "split() by comma to get values",
            "zip with headers to pair them"
          ],
          "solution": "def parse_csv_line(line, headers=['name', 'age', 'city']):\n    values = line.split(',')\n    return dict(zip(headers, values))",
          "starter_code": "",
          "test_code": "assert 'parse_csv_line' in dir(), \"Function 'parse_csv_line' not defined. Did you write: def parse_csv_line(...)?\"\n_r0 = parse_csv_line('Alice,30,NYC')\nassert _r0 == {'name': 'Alice', 'age': '30', 'city': 'NYC'}, \"Test 1: parse_csv_line('Alice,30,NYC') returned \" + str(repr(_r0)) + \", expected {'name': 'Alice', 'age': '30', 'city': 'NYC'}\"",
          "concepts": [
            "data parsing",
            "dictionaries",
            "zip"
          ]
        },
        {
          "id": "func_43",
          "title": "Higher-Order Function: Apply Twice",
          "difficulty": 4,
          "description": "Write a function `apply_twice(func, x)` that applies a function to x twice. Example: apply_twice(lambda x: x*2, 3) returns 12.",
          "hints": [
            "Call func(x) to get intermediate result",
            "Call func again on the intermediate result"
          ],
          "solution": "def apply_twice(func, x):\n    return func(func(x))",
          "starter_code": "",
          "test_code": "assert 'apply_twice' in dir(), \"'apply_twice' is not defined\"\nassert callable(apply_twice), \"'apply_twice' should be a function\"",
          "concepts": [
            "higher-order functions",
            "function arguments"
          ]
        },
        {
          "id": "func_44",
          "title": "Partition Function",
          "difficulty": 4,
          "description": "Write a function `partition(pred, iterable)` that splits an iterable into two lists: items where pred is True and where it's False.",
          "hints": [
            "Create two lists, true_list and false_list",
            "Iterate and append based on pred(item)"
          ],
          "solution": "def partition(pred, iterable):\n    true_list, false_list = [], []\n    for item in iterable:\n        if pred(item):\n            true_list.append(item)\n        else:\n            false_list.append(item)\n    return true_list, false_list",
          "starter_code": "",
          "test_code": "assert 'partition' in dir(), \"'partition' is not defined\"\nassert callable(partition), \"'partition' should be a function\"",
          "concepts": [
            "higher-order functions",
            "filtering"
          ]
        },
        {
          "id": "func_45",
          "title": "Function as Dictionary Value",
          "difficulty": 4,
          "description": "Create a function `calculate` that uses a dictionary of operations ('+': add, '-': subtract, '*': multiply) and returns the result of op(a, b).",
          "hints": [
            "Store lambda or named functions in a dict",
            "Look up the operation by key"
          ],
          "solution": "def calculate(a, op, b):\n    operations = {'+': lambda x, y: x + y, '-': lambda x, y: x - y, '*': lambda x, y: x * y}\n    return operations[op](a, b)",
          "starter_code": "",
          "test_code": "assert 'calculate' in dir(), \"'calculate' is not defined\"\nassert callable(calculate), \"'calculate' should be a function\"",
          "concepts": [
            "functions as values",
            "dictionaries",
            "operations"
          ]
        },
        {
          "id": "func_46",
          "title": "Currying Function",
          "difficulty": 5,
          "description": "Write a function `curry(func)` that converts a function of multiple arguments into nested single-argument functions. curry(add)(5)(3) should return 8.",
          "hints": [
            "Return a function that takes one arg and returns another function",
            "The innermost function performs the actual operation"
          ],
          "solution": "def curry(func):\n    def curried(a):\n        def inner(b):\n            return func(a, b)\n        return inner\n    return curried",
          "starter_code": "",
          "test_code": "assert 'curry' in dir(), \"'curry' is not defined\"\nassert callable(curry), \"'curry' should be a function\"",
          "concepts": [
            "currying",
            "function composition",
            "closures"
          ]
        },
        {
          "id": "func_47",
          "title": "Recursive Tree Sum",
          "difficulty": 5,
          "description": "Write a function `sum_tree` that recursively sums all values in a nested list structure. Example: sum_tree([1, [2, [3, 4]]]) returns 10.",
          "hints": [
            "Base case: if item is not a list, return its value",
            "Recursive case: sum the results of sum_tree on each element"
          ],
          "solution": "def sum_tree(tree):\n    total = 0\n    for item in tree:\n        if isinstance(item, list):\n            total += sum_tree(item)\n        else:\n            total += item\n    return total",
          "starter_code": "",
          "test_code": "assert 'sum_tree' in dir(), \"Function 'sum_tree' not defined. Did you write: def sum_tree(...)?\"\n_r0 = sum_tree([1, [2, [3, 4]]])\nassert _r0 == 10, 'Test 1: sum_tree([1, [2, [3, 4]]]) returned ' + str(repr(_r0)) + ', expected 10'\n_r1 = sum_tree([5, [10]])\nassert _r1 == 15, 'Test 2: sum_tree([5, [10]]) returned ' + str(repr(_r1)) + ', expected 15'",
          "concepts": [
            "recursion",
            "nested structures",
            "type checking"
          ]
        },
        {
          "id": "func_48",
          "title": "Context Manager Decorator",
          "difficulty": 5,
          "description": "Write a decorator `measure_time` that wraps a function and prints the time it took to execute (in seconds).",
          "hints": [
            "Import time module and use time.time()",
            "Record time before and after function call"
          ],
          "solution": "import time\ndef measure_time(func):\n    def wrapper(*args, **kwargs):\n        start = time.time()\n        result = func(*args, **kwargs)\n        end = time.time()\n        print(f'{func.__name__} took {end - start:.4f} seconds')\n        return result\n    return wrapper",
          "starter_code": "",
          "test_code": "assert 'measure_time' in dir(), \"'measure_time' is not defined\"\nassert callable(measure_time), \"'measure_time' should be a function\"",
          "concepts": [
            "decorators",
            "profiling",
            "side effects"
          ]
        },
        {
          "id": "func_49",
          "title": "Chain Multiple Decorators",
          "difficulty": 5,
          "description": "Apply multiple decorators: @add_exclamation and @str.upper (or custom upper) to a function that returns 'hello'. Result should be 'HELLO!'.",
          "hints": [
            "Decorators are applied bottom-to-top",
            "The first decorator applied receives the original function"
          ],
          "solution": "def to_upper(func):\n    def wrapper(*args, **kwargs):\n        return func(*args, **kwargs).upper()\n    return wrapper\n\ndef add_exclamation(func):\n    def wrapper(*args, **kwargs):\n        return func(*args, **kwargs) + '!'\n    return wrapper",
          "starter_code": "",
          "test_code": "assert 'to_upper' in dir(), \"'to_upper' is not defined\"\nassert callable(to_upper), \"'to_upper' should be a function\"\nassert 'add_exclamation' in dir(), \"'add_exclamation' is not defined\"\nassert callable(add_exclamation), \"'add_exclamation' should be a function\"",
          "concepts": [
            "multiple decorators",
            "composition",
            "order of execution"
          ]
        },
        {
          "id": "func_50",
          "title": "Flexible Argument Unpacking",
          "difficulty": 5,
          "description": "Write a function `flexible_sum(*args, **kwargs)` that sums all positional arguments and all values in kwargs. Example: flexible_sum(1, 2, a=3, b=4) returns 10.",
          "hints": [
            "Sum the args tuple",
            "Sum the values of kwargs dict",
            "Add them together"
          ],
          "solution": "def flexible_sum(*args, **kwargs):\n    return sum(args) + sum(kwargs.values())",
          "starter_code": "",
          "test_code": "assert 'flexible_sum' in dir(), \"'flexible_sum' is not defined\"\nassert callable(flexible_sum), \"'flexible_sum' should be a function\"",
          "concepts": [
            "*args",
            "**kwargs",
            "argument unpacking"
          ]
        }
      ]
    },
    {
      "id": "lists_sets",
      "title": "Lists & Sets",
      "exercise_count": 50,
      "exercises": [
        {
          "id": "ls_01",
          "title": "Create a list",
          "difficulty": 1,
          "description": "Create a list containing the integers 1, 2, 3, 4, 5 and assign it to a variable called 'my_list'.",
          "hints": [
            "Use square brackets [] to create a list.",
            "Separate elements with commas."
          ],
          "solution": "my_list = [1, 2, 3, 4, 5]",
          "starter_code": "my_list = ",
          "test_code": "assert isinstance(my_list, list), 'my_list should be a list, got ' + str(type(my_list).__name__)\nassert len(my_list) > 0, \"my_list should not be empty\"",
          "concepts": [
            "list literals",
            "variable assignment"
          ]
        },
        {
          "id": "ls_02",
          "title": "Access list elements by index",
          "difficulty": 1,
          "description": "Given the list items = ['apple', 'banana', 'cherry'], get the first element.",
          "hints": [
            "List indices start at 0 in Python.",
            "Use square brackets with the index number to access an element."
          ],
          "solution": "items = ['apple', 'banana', 'cherry']\nfirst = items[0]",
          "starter_code": "items = ['apple', 'banana', 'cherry']\nfirst = ",
          "test_code": "assert isinstance(items, list), 'items should be a list, got ' + str(type(items).__name__)\nassert len(items) > 0, \"items should not be empty\"\nassert first == 'apple', \"first should be 'apple', got \" + str(repr(first))",
          "concepts": [
            "indexing",
            "zero-based indexing"
          ]
        },
        {
          "id": "ls_03",
          "title": "Negative indexing",
          "difficulty": 1,
          "description": "Given the list colors = ['red', 'green', 'blue', 'yellow'], get the last element using negative indexing.",
          "hints": [
            "Negative indices count from the end of the list.",
            "-1 refers to the last element, -2 to the second-to-last, etc."
          ],
          "solution": "colors = ['red', 'green', 'blue', 'yellow']\nlast = colors[-1]",
          "starter_code": "colors = ['red', 'green', 'blue', 'yellow']\nlast = ",
          "test_code": "assert isinstance(colors, list), 'colors should be a list, got ' + str(type(colors).__name__)\nassert len(colors) > 0, \"colors should not be empty\"\nassert last == 'yellow', \"last should be 'yellow', got \" + str(repr(last))",
          "concepts": [
            "negative indexing"
          ]
        },
        {
          "id": "ls_04",
          "title": "Get list length",
          "difficulty": 1,
          "description": "Write a function that returns the number of elements in a list.",
          "hints": [
            "Use the len() function to get the length.",
            "Don't count manually."
          ],
          "solution": "def get_length(items):\n    return len(items)",
          "starter_code": "def get_length(items):\n    pass",
          "test_code": "assert 'get_length' in dir(), \"Function 'get_length' not defined. Did you write: def get_length(...)?\"\n_r0 = get_length([1, 2, 3])\nassert _r0 == 3, 'Test 1: get_length([1, 2, 3]) returned ' + str(repr(_r0)) + ', expected 3'\n_r1 = get_length([])\nassert _r1 == 0, 'Test 2: get_length([]) returned ' + str(repr(_r1)) + ', expected 0'\n_r2 = get_length(['a', 'b', 'c', 'd'])\nassert _r2 == 4, \"Test 3: get_length(['a', 'b', 'c', 'd']) returned \" + str(repr(_r2)) + ', expected 4'",
          "concepts": [
            "len() function"
          ]
        },
        {
          "id": "ls_05",
          "title": "Append to a list",
          "difficulty": 1,
          "description": "Write a function that appends an element to a list and returns the modified list.",
          "hints": [
            "Use the .append() method to add an element to the end.",
            "The method modifies the list in place."
          ],
          "solution": "def add_element(items, element):\n    items.append(element)\n    return items",
          "starter_code": "def add_element(items, element):\n    pass",
          "test_code": "assert 'add_element' in dir(), \"Function 'add_element' not defined. Did you write: def add_element(...)?\"\n_r0 = add_element([1, 2, 3], 4)\nassert _r0 == [1, 2, 3, 4], 'Test 1: add_element([1, 2, 3], 4) returned ' + str(repr(_r0)) + ', expected [1, 2, 3, 4]'\n_r1 = add_element([], 'first')\nassert _r1 == ['first'], \"Test 2: add_element([], 'first') returned \" + str(repr(_r1)) + \", expected ['first']\"\n_r2 = add_element(['a', 'b'], 'c')\nassert _r2 == ['a', 'b', 'c'], \"Test 3: add_element(['a', 'b'], 'c') returned \" + str(repr(_r2)) + \", expected ['a', 'b', 'c']\"",
          "concepts": [
            "append() method"
          ]
        },
        {
          "id": "ls_06",
          "title": "Remove an element",
          "difficulty": 1,
          "description": "Write a function that removes the first occurrence of an element from a list and returns the modified list.",
          "hints": [
            "Use the .remove() method.",
            "If the element is not found, it raises an error."
          ],
          "solution": "def remove_element(items, element):\n    items.remove(element)\n    return items",
          "starter_code": "def remove_element(items, element):\n    pass",
          "test_code": "assert 'remove_element' in dir(), \"Function 'remove_element' not defined. Did you write: def remove_element(...)?\"\n_r0 = remove_element([1, 2, 3, 2], 2)\nassert _r0 == [1, 3, 2], 'Test 1: remove_element([1, 2, 3, 2], 2) returned ' + str(repr(_r0)) + ', expected [1, 3, 2]'\n_r1 = remove_element(['a', 'b', 'c'], 'b')\nassert _r1 == ['a', 'c'], \"Test 2: remove_element(['a', 'b', 'c'], 'b') returned \" + str(repr(_r1)) + \", expected ['a', 'c']\"\n_r2 = remove_element([5], 5)\nassert _r2 == [], 'Test 3: remove_element([5], 5) returned ' + str(repr(_r2)) + ', expected []'",
          "concepts": [
            "remove() method"
          ]
        },
        {
          "id": "ls_07",
          "title": "Pop an element by index",
          "difficulty": 1,
          "description": "Write a function that removes and returns an element at a specific index.",
          "hints": [
            "Use the .pop() method with an index.",
            "pop() both removes and returns the element."
          ],
          "solution": "def pop_at_index(items, index):\n    return items.pop(index)",
          "starter_code": "def pop_at_index(items, index):\n    pass",
          "test_code": "assert 'pop_at_index' in dir(), \"Function 'pop_at_index' not defined. Did you write: def pop_at_index(...)?\"\n_r0 = pop_at_index([1, 2, 3], 1)\nassert _r0 == 2, 'Test 1: pop_at_index([1, 2, 3], 1) returned ' + str(repr(_r0)) + ', expected 2'\n_r1 = pop_at_index(['a', 'b', 'c'], 0)\nassert _r1 == 'a', \"Test 2: pop_at_index(['a', 'b', 'c'], 0) returned \" + str(repr(_r1)) + \", expected 'a'\"\n_r2 = pop_at_index([10, 20, 30], 2)\nassert _r2 == 30, 'Test 3: pop_at_index([10, 20, 30], 2) returned ' + str(repr(_r2)) + ', expected 30'",
          "concepts": [
            "pop() method"
          ]
        },
        {
          "id": "ls_08",
          "title": "Check if element in list",
          "difficulty": 1,
          "description": "Write a function that checks if an element exists in a list and returns True or False.",
          "hints": [
            "Use the 'in' operator.",
            "It returns a boolean value."
          ],
          "solution": "def is_in_list(items, element):\n    return element in items",
          "starter_code": "def is_in_list(items, element):\n    pass",
          "test_code": "assert 'is_in_list' in dir(), \"Function 'is_in_list' not defined. Did you write: def is_in_list(...)?\"\n_r0 = is_in_list([1, 2, 3], 2)\nassert _r0 == True, 'Test 1: is_in_list([1, 2, 3], 2) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = is_in_list([1, 2, 3], 5)\nassert _r1 == False, 'Test 2: is_in_list([1, 2, 3], 5) returned ' + str(repr(_r1)) + ', expected False'\n_r2 = is_in_list(['a', 'b'], 'a')\nassert _r2 == True, \"Test 3: is_in_list(['a', 'b'], 'a') returned \" + str(repr(_r2)) + ', expected True'",
          "concepts": [
            "membership test",
            "in operator"
          ]
        },
        {
          "id": "ls_09",
          "title": "List index of element",
          "difficulty": 1,
          "description": "Write a function that returns the index of the first occurrence of an element in a list.",
          "hints": [
            "Use the .index() method.",
            "It raises an error if the element is not found."
          ],
          "solution": "def find_index(items, element):\n    return items.index(element)",
          "starter_code": "def find_index(items, element):\n    pass",
          "test_code": "assert 'find_index' in dir(), \"Function 'find_index' not defined. Did you write: def find_index(...)?\"\n_r0 = find_index([1, 2, 3, 2], 2)\nassert _r0 == 1, 'Test 1: find_index([1, 2, 3, 2], 2) returned ' + str(repr(_r0)) + ', expected 1'\n_r1 = find_index(['a', 'b', 'c'], 'c')\nassert _r1 == 2, \"Test 2: find_index(['a', 'b', 'c'], 'c') returned \" + str(repr(_r1)) + ', expected 2'\n_r2 = find_index([10, 20, 30], 10)\nassert _r2 == 0, 'Test 3: find_index([10, 20, 30], 10) returned ' + str(repr(_r2)) + ', expected 0'",
          "concepts": [
            "index() method"
          ]
        },
        {
          "id": "ls_10",
          "title": "Insert element at position",
          "difficulty": 1,
          "description": "Write a function that inserts an element at a specific index in a list.",
          "hints": [
            "Use the .insert() method with index and element.",
            "insert(index, element) adds the element BEFORE the given index."
          ],
          "solution": "def insert_at(items, index, element):\n    items.insert(index, element)\n    return items",
          "starter_code": "def insert_at(items, index, element):\n    pass",
          "test_code": "assert 'insert_at' in dir(), \"Function 'insert_at' not defined. Did you write: def insert_at(...)?\"\n_r0 = insert_at([1, 2, 3], 1, 10)\nassert _r0 == [1, 10, 2, 3], 'Test 1: insert_at([1, 2, 3], 1, 10) returned ' + str(repr(_r0)) + ', expected [1, 10, 2, 3]'\n_r1 = insert_at([1, 2], 0, 0)\nassert _r1 == [0, 1, 2], 'Test 2: insert_at([1, 2], 0, 0) returned ' + str(repr(_r1)) + ', expected [0, 1, 2]'\n_r2 = insert_at(['a', 'b'], 2, 'c')\nassert _r2 == ['a', 'b', 'c'], \"Test 3: insert_at(['a', 'b'], 2, 'c') returned \" + str(repr(_r2)) + \", expected ['a', 'b', 'c']\"",
          "concepts": [
            "insert() method"
          ]
        },
        {
          "id": "ls_11",
          "title": "List slicing basics",
          "difficulty": 2,
          "description": "Write a function that returns elements from index 1 to 2 (inclusive of 1, exclusive of 2).",
          "hints": [
            "Use slicing syntax: list[start:stop].",
            "start is inclusive, stop is exclusive."
          ],
          "solution": "def slice_list(items):\n    return items[1:2]",
          "starter_code": "def slice_list(items):\n    pass",
          "test_code": "assert 'slice_list' in dir(), \"Function 'slice_list' not defined. Did you write: def slice_list(...)?\"\n_r0 = slice_list([1, 2, 3, 4, 5])\nassert _r0 == [2], 'Test 1: slice_list([1, 2, 3, 4, 5]) returned ' + str(repr(_r0)) + ', expected [2]'\n_r1 = slice_list(['a', 'b', 'c', 'd'])\nassert _r1 == ['b'], \"Test 2: slice_list(['a', 'b', 'c', 'd']) returned \" + str(repr(_r1)) + \", expected ['b']\"\n_r2 = slice_list([10, 20, 30])\nassert _r2 == [20], 'Test 3: slice_list([10, 20, 30]) returned ' + str(repr(_r2)) + ', expected [20]'",
          "concepts": [
            "list slicing",
            "slice syntax"
          ]
        },
        {
          "id": "ls_12",
          "title": "Slice with step",
          "difficulty": 2,
          "description": "Write a function that returns every second element from a list using slicing.",
          "hints": [
            "Use slicing with a step: list[start:stop:step].",
            "step=2 means every second element."
          ],
          "solution": "def every_second(items):\n    return items[::2]",
          "starter_code": "def every_second(items):\n    pass",
          "test_code": "assert 'every_second' in dir(), \"Function 'every_second' not defined. Did you write: def every_second(...)?\"\n_r0 = every_second([1, 2, 3, 4, 5])\nassert _r0 == [1, 3, 5], 'Test 1: every_second([1, 2, 3, 4, 5]) returned ' + str(repr(_r0)) + ', expected [1, 3, 5]'\n_r1 = every_second([0, 1, 2, 3, 4, 5, 6])\nassert _r1 == [0, 2, 4, 6], 'Test 2: every_second([0, 1, 2, 3, 4, 5, 6]) returned ' + str(repr(_r1)) + ', expected [0, 2, 4, 6]'\n_r2 = every_second(['a', 'b', 'c', 'd'])\nassert _r2 == ['a', 'c'], \"Test 3: every_second(['a', 'b', 'c', 'd']) returned \" + str(repr(_r2)) + \", expected ['a', 'c']\"",
          "concepts": [
            "step in slicing"
          ]
        },
        {
          "id": "ls_13",
          "title": "Reverse a list with slicing",
          "difficulty": 2,
          "description": "Write a function that reverses a list using slicing (not the reverse() method).",
          "hints": [
            "Use negative step: [::-1].",
            "This creates a new reversed list without modifying the original."
          ],
          "solution": "def reverse_list(items):\n    return items[::-1]",
          "starter_code": "def reverse_list(items):\n    pass",
          "test_code": "assert 'reverse_list' in dir(), \"Function 'reverse_list' not defined. Did you write: def reverse_list(...)?\"\n_r0 = reverse_list([1, 2, 3, 4, 5])\nassert _r0 == [5, 4, 3, 2, 1], 'Test 1: reverse_list([1, 2, 3, 4, 5]) returned ' + str(repr(_r0)) + ', expected [5, 4, 3, 2, 1]'\n_r1 = reverse_list(['a', 'b', 'c'])\nassert _r1 == ['c', 'b', 'a'], \"Test 2: reverse_list(['a', 'b', 'c']) returned \" + str(repr(_r1)) + \", expected ['c', 'b', 'a']\"\n_r2 = reverse_list([1])\nassert _r2 == [1], 'Test 3: reverse_list([1]) returned ' + str(repr(_r2)) + ', expected [1]'",
          "concepts": [
            "negative step slicing"
          ]
        },
        {
          "id": "ls_14",
          "title": "Basic list comprehension",
          "difficulty": 2,
          "description": "Write a list comprehension that squares all numbers in a list.",
          "hints": [
            "Use the syntax [expression for item in iterable].",
            "The expression here is x**2."
          ],
          "solution": "def square_all(numbers):\n    return [x**2 for x in numbers]",
          "starter_code": "def square_all(numbers):\n    pass",
          "test_code": "assert 'square_all' in dir(), \"Function 'square_all' not defined. Did you write: def square_all(...)?\"\n_r0 = square_all([1, 2, 3])\nassert _r0 == [1, 4, 9], 'Test 1: square_all([1, 2, 3]) returned ' + str(repr(_r0)) + ', expected [1, 4, 9]'\n_r1 = square_all([0, 1, 2, 3])\nassert _r1 == [0, 1, 4, 9], 'Test 2: square_all([0, 1, 2, 3]) returned ' + str(repr(_r1)) + ', expected [0, 1, 4, 9]'\n_r2 = square_all([5])\nassert _r2 == [25], 'Test 3: square_all([5]) returned ' + str(repr(_r2)) + ', expected [25]'",
          "concepts": [
            "list comprehension"
          ]
        },
        {
          "id": "ls_15",
          "title": "List comprehension with condition",
          "difficulty": 2,
          "description": "Write a list comprehension that filters a list to keep only even numbers.",
          "hints": [
            "Use [expression for item in iterable if condition].",
            "The condition is x % 2 == 0."
          ],
          "solution": "def filter_even(numbers):\n    return [x for x in numbers if x % 2 == 0]",
          "starter_code": "def filter_even(numbers):\n    pass",
          "test_code": "assert 'filter_even' in dir(), \"Function 'filter_even' not defined. Did you write: def filter_even(...)?\"\n_r0 = filter_even([1, 2, 3, 4, 5])\nassert _r0 == [2, 4], 'Test 1: filter_even([1, 2, 3, 4, 5]) returned ' + str(repr(_r0)) + ', expected [2, 4]'\n_r1 = filter_even([2, 4, 6, 8])\nassert _r1 == [2, 4, 6, 8], 'Test 2: filter_even([2, 4, 6, 8]) returned ' + str(repr(_r1)) + ', expected [2, 4, 6, 8]'\n_r2 = filter_even([1, 3, 5])\nassert _r2 == [], 'Test 3: filter_even([1, 3, 5]) returned ' + str(repr(_r2)) + ', expected []'",
          "concepts": [
            "list comprehension with if"
          ]
        },
        {
          "id": "ls_16",
          "title": "Nested lists",
          "difficulty": 2,
          "description": "Write a function that accesses the element at position [1][2] in a 2D list (matrix).",
          "hints": [
            "Use nested indexing: list[row][col].",
            "First index is the row, second is the column."
          ],
          "solution": "def get_element_2d(matrix):\n    return matrix[1][2]",
          "starter_code": "def get_element_2d(matrix):\n    pass",
          "test_code": "assert 'get_element_2d' in dir(), \"Function 'get_element_2d' not defined. Did you write: def get_element_2d(...)?\"\n_r0 = get_element_2d([[1, 2, 3], [4, 5, 6], [7, 8, 9]])\nassert _r0 == 6, 'Test 1: get_element_2d([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) returned ' + str(repr(_r0)) + ', expected 6'\n_r1 = get_element_2d([[0, 1, 10], [2, 3, 5], [4, 5, 6]])\nassert _r1 == 5, 'Test 2: get_element_2d([[0, 1, 10], [2, 3, 5], [4, 5, 6]]) returned ' + str(repr(_r1)) + ', expected 5'",
          "concepts": [
            "nested lists",
            "2D indexing"
          ]
        },
        {
          "id": "ls_17",
          "title": "Sum of list elements",
          "difficulty": 2,
          "description": "Write a function that returns the sum of all elements in a list.",
          "hints": [
            "Use the sum() built-in function.",
            "Or use a loop or comprehension."
          ],
          "solution": "def sum_list(numbers):\n    return sum(numbers)",
          "starter_code": "def sum_list(numbers):\n    pass",
          "test_code": "assert 'sum_list' in dir(), \"Function 'sum_list' not defined. Did you write: def sum_list(...)?\"\n_r0 = sum_list([1, 2, 3, 4])\nassert _r0 == 10, 'Test 1: sum_list([1, 2, 3, 4]) returned ' + str(repr(_r0)) + ', expected 10'\n_r1 = sum_list([0])\nassert _r1 == 0, 'Test 2: sum_list([0]) returned ' + str(repr(_r1)) + ', expected 0'\n_r2 = sum_list([10, 20, 30])\nassert _r2 == 60, 'Test 3: sum_list([10, 20, 30]) returned ' + str(repr(_r2)) + ', expected 60'",
          "concepts": [
            "sum() function"
          ]
        },
        {
          "id": "ls_18",
          "title": "Min and max of list",
          "difficulty": 2,
          "description": "Write a function that returns a tuple of (min, max) from a list.",
          "hints": [
            "Use min() and max() built-in functions.",
            "They work on any iterable."
          ],
          "solution": "def min_max(numbers):\n    return (min(numbers), max(numbers))",
          "starter_code": "def min_max(numbers):\n    pass",
          "test_code": "assert 'min_max' in dir(), \"Function 'min_max' not defined. Did you write: def min_max(...)?\"\n_r0 = min_max([1, 5, 3, 9, 2])\nassert _r0 == (1, 9), 'Test 1: min_max([1, 5, 3, 9, 2]) returned ' + str(repr(_r0)) + ', expected (1, 9)'\n_r1 = min_max([100])\nassert _r1 == (100, 100), 'Test 2: min_max([100]) returned ' + str(repr(_r1)) + ', expected (100, 100)'\n_r2 = min_max([0, -5, 10])\nassert _r2 == (-5, 10), 'Test 3: min_max([0, -5, 10]) returned ' + str(repr(_r2)) + ', expected (-5, 10)'",
          "concepts": [
            "min() and max() functions"
          ]
        },
        {
          "id": "ls_19",
          "title": "Count occurrences",
          "difficulty": 2,
          "description": "Write a function that counts how many times an element appears in a list.",
          "hints": [
            "Use the .count() method.",
            "It returns an integer."
          ],
          "solution": "def count_element(items, element):\n    return items.count(element)",
          "starter_code": "def count_element(items, element):\n    pass",
          "test_code": "assert 'count_element' in dir(), \"Function 'count_element' not defined. Did you write: def count_element(...)?\"\n_r0 = count_element([1, 2, 2, 3, 2], 2)\nassert _r0 == 3, 'Test 1: count_element([1, 2, 2, 3, 2], 2) returned ' + str(repr(_r0)) + ', expected 3'\n_r1 = count_element(['a', 'b', 'a'], 'a')\nassert _r1 == 2, \"Test 2: count_element(['a', 'b', 'a'], 'a') returned \" + str(repr(_r1)) + ', expected 2'\n_r2 = count_element([1, 1, 1], 1)\nassert _r2 == 3, 'Test 3: count_element([1, 1, 1], 1) returned ' + str(repr(_r2)) + ', expected 3'",
          "concepts": [
            "count() method"
          ]
        },
        {
          "id": "ls_20",
          "title": "Copy a list",
          "difficulty": 2,
          "description": "Write a function that creates a shallow copy of a list.",
          "hints": [
            "Use .copy() method or slicing [:].",
            "A copy is independent from the original."
          ],
          "solution": "def copy_list(items):\n    return items.copy()",
          "starter_code": "def copy_list(items):\n    pass",
          "test_code": "assert 'copy_list' in dir(), \"Function 'copy_list' not defined. Did you write: def copy_list(...)?\"\n_r0 = copy_list([1, 2, 3])\nassert _r0 == [1, 2, 3], 'Test 1: copy_list([1, 2, 3]) returned ' + str(repr(_r0)) + ', expected [1, 2, 3]'\n_r1 = copy_list([])\nassert _r1 == [], 'Test 2: copy_list([]) returned ' + str(repr(_r1)) + ', expected []'\n_r2 = copy_list(['a', 'b'])\nassert _r2 == ['a', 'b'], \"Test 3: copy_list(['a', 'b']) returned \" + str(repr(_r2)) + \", expected ['a', 'b']\"",
          "concepts": [
            "shallow copy",
            "copy() method"
          ]
        },
        {
          "id": "ls_21",
          "title": "Sort a list",
          "difficulty": 3,
          "description": "Write a function that sorts a list in ascending order and returns it.",
          "hints": [
            "Use .sort() method (modifies in place) or sorted() function (returns new list).",
            "For this exercise, use sorted()."
          ],
          "solution": "def sort_list(items):\n    return sorted(items)",
          "starter_code": "def sort_list(items):\n    pass",
          "test_code": "assert 'sort_list' in dir(), \"Function 'sort_list' not defined. Did you write: def sort_list(...)?\"\n_r0 = sort_list([3, 1, 4, 1, 5])\nassert _r0 == [1, 1, 3, 4, 5], 'Test 1: sort_list([3, 1, 4, 1, 5]) returned ' + str(repr(_r0)) + ', expected [1, 1, 3, 4, 5]'\n_r1 = sort_list(['c', 'a', 'b'])\nassert _r1 == ['a', 'b', 'c'], \"Test 2: sort_list(['c', 'a', 'b']) returned \" + str(repr(_r1)) + \", expected ['a', 'b', 'c']\"\n_r2 = sort_list([-5, 0, 3])\nassert _r2 == [-5, 0, 3], 'Test 3: sort_list([-5, 0, 3]) returned ' + str(repr(_r2)) + ', expected [-5, 0, 3]'",
          "concepts": [
            "sorted() function"
          ]
        },
        {
          "id": "ls_22",
          "title": "Sort with reverse",
          "difficulty": 3,
          "description": "Write a function that sorts a list in descending order.",
          "hints": [
            "Use sorted() with reverse=True parameter.",
            "Or use .sort(reverse=True)."
          ],
          "solution": "def sort_descending(items):\n    return sorted(items, reverse=True)",
          "starter_code": "def sort_descending(items):\n    pass",
          "test_code": "assert 'sort_descending' in dir(), \"Function 'sort_descending' not defined. Did you write: def sort_descending(...)?\"\n_r0 = sort_descending([3, 1, 4, 1, 5])\nassert _r0 == [5, 4, 3, 1, 1], 'Test 1: sort_descending([3, 1, 4, 1, 5]) returned ' + str(repr(_r0)) + ', expected [5, 4, 3, 1, 1]'\n_r1 = sort_descending(['a', 'c', 'b'])\nassert _r1 == ['c', 'b', 'a'], \"Test 2: sort_descending(['a', 'c', 'b']) returned \" + str(repr(_r1)) + \", expected ['c', 'b', 'a']\"",
          "concepts": [
            "reverse parameter in sorted()"
          ]
        },
        {
          "id": "ls_23",
          "title": "Sort by length",
          "difficulty": 3,
          "description": "Write a function that sorts a list of strings by their length.",
          "hints": [
            "Use sorted() with key=len.",
            "The key parameter specifies a function to extract comparison value."
          ],
          "solution": "def sort_by_length(words):\n    return sorted(words, key=len)",
          "starter_code": "def sort_by_length(words):\n    pass",
          "test_code": "assert 'sort_by_length' in dir(), \"Function 'sort_by_length' not defined. Did you write: def sort_by_length(...)?\"\n_r0 = sort_by_length(['apple', 'pie', 'banana'])\nassert _r0 == ['pie', 'apple', 'banana'], \"Test 1: sort_by_length(['apple', 'pie', 'banana']) returned \" + str(repr(_r0)) + \", expected ['pie', 'apple', 'banana']\"\n_r1 = sort_by_length(['a', 'bb', 'ccc'])\nassert _r1 == ['a', 'bb', 'ccc'], \"Test 2: sort_by_length(['a', 'bb', 'ccc']) returned \" + str(repr(_r1)) + \", expected ['a', 'bb', 'ccc']\"",
          "concepts": [
            "key parameter",
            "sorted with function"
          ]
        },
        {
          "id": "ls_24",
          "title": "Unpack a list",
          "difficulty": 3,
          "description": "Write a function that unpacks a 3-element list into three variables and returns their sum.",
          "hints": [
            "Use a, b, c = items.",
            "Unpacking assigns each element to a variable."
          ],
          "solution": "def unpack_three(items):\n    a, b, c = items\n    return a + b + c",
          "starter_code": "def unpack_three(items):\n    pass",
          "test_code": "assert 'unpack_three' in dir(), \"Function 'unpack_three' not defined. Did you write: def unpack_three(...)?\"\n_r0 = unpack_three([1, 2, 3])\nassert _r0 == 6, 'Test 1: unpack_three([1, 2, 3]) returned ' + str(repr(_r0)) + ', expected 6'\n_r1 = unpack_three([10, 20, 30])\nassert _r1 == 60, 'Test 2: unpack_three([10, 20, 30]) returned ' + str(repr(_r1)) + ', expected 60'",
          "concepts": [
            "tuple unpacking",
            "list unpacking"
          ]
        },
        {
          "id": "ls_25",
          "title": "Unpack with *",
          "difficulty": 3,
          "description": "Write a function that unpacks a list with a leading element and captures the rest in a variable.",
          "hints": [
            "Use a, *rest = items.",
            "The * operator captures remaining elements as a list."
          ],
          "solution": "def unpack_rest(items):\n    first, *rest = items\n    return first, rest",
          "starter_code": "def unpack_rest(items):\n    pass",
          "test_code": "assert 'unpack_rest' in dir(), \"Function 'unpack_rest' not defined. Did you write: def unpack_rest(...)?\"\n_r0 = unpack_rest([1, 2, 3, 4])\nassert _r0 == (1, [2, 3, 4]), 'Test 1: unpack_rest([1, 2, 3, 4]) returned ' + str(repr(_r0)) + ', expected (1, [2, 3, 4])'\n_r1 = unpack_rest([10])\nassert _r1 == (10, []), 'Test 2: unpack_rest([10]) returned ' + str(repr(_r1)) + ', expected (10, [])'",
          "concepts": [
            "extended unpacking",
            "* operator"
          ]
        },
        {
          "id": "ls_26",
          "title": "Zip two lists",
          "difficulty": 3,
          "description": "Write a function that pairs elements from two lists using zip().",
          "hints": [
            "Use zip(list1, list2) to pair elements.",
            "Convert to list if needed for the test."
          ],
          "solution": "def zip_lists(a, b):\n    return list(zip(a, b))",
          "starter_code": "def zip_lists(a, b):\n    pass",
          "test_code": "assert 'zip_lists' in dir(), \"Function 'zip_lists' not defined. Did you write: def zip_lists(...)?\"\n_r0 = zip_lists([1, 2, 3], ['a', 'b', 'c'])\nassert _r0 == [(1, 'a'), (2, 'b'), (3, 'c')], \"Test 1: zip_lists([1, 2, 3], ['a', 'b', 'c']) returned \" + str(repr(_r0)) + \", expected [(1, 'a'), (2, 'b'), (3, 'c')]\"\n_r1 = zip_lists([1, 2], ['x', 'y'])\nassert _r1 == [(1, 'x'), (2, 'y')], \"Test 2: zip_lists([1, 2], ['x', 'y']) returned \" + str(repr(_r1)) + \", expected [(1, 'x'), (2, 'y')]\"",
          "concepts": [
            "zip() function"
          ]
        },
        {
          "id": "ls_27",
          "title": "Enumerate a list",
          "difficulty": 3,
          "description": "Write a function that uses enumerate to create a list of (index, value) tuples.",
          "hints": [
            "Use enumerate(items) to get index-value pairs.",
            "Convert to list for the test."
          ],
          "solution": "def enumerate_list(items):\n    return list(enumerate(items))",
          "starter_code": "def enumerate_list(items):\n    pass",
          "test_code": "assert 'enumerate_list' in dir(), \"Function 'enumerate_list' not defined. Did you write: def enumerate_list(...)?\"\n_r0 = enumerate_list(['a', 'b', 'c'])\nassert _r0 == [(0, 'a'), (1, 'b'), (2, 'c')], \"Test 1: enumerate_list(['a', 'b', 'c']) returned \" + str(repr(_r0)) + \", expected [(0, 'a'), (1, 'b'), (2, 'c')]\"\n_r1 = enumerate_list([10, 20])\nassert _r1 == [(0, 10), (1, 20)], 'Test 2: enumerate_list([10, 20]) returned ' + str(repr(_r1)) + ', expected [(0, 10), (1, 20)]'",
          "concepts": [
            "enumerate() function"
          ]
        },
        {
          "id": "ls_28",
          "title": "Map function",
          "difficulty": 3,
          "description": "Write a function that applies a function to each element using map().",
          "hints": [
            "Use map(func, list) to apply a function.",
            "Convert to list for the result."
          ],
          "solution": "def map_square(numbers):\n    return list(map(lambda x: x**2, numbers))",
          "starter_code": "def map_square(numbers):\n    pass",
          "test_code": "assert 'map_square' in dir(), \"Function 'map_square' not defined. Did you write: def map_square(...)?\"\n_r0 = map_square([1, 2, 3])\nassert _r0 == [1, 4, 9], 'Test 1: map_square([1, 2, 3]) returned ' + str(repr(_r0)) + ', expected [1, 4, 9]'\n_r1 = map_square([0, 1, 2])\nassert _r1 == [0, 1, 4], 'Test 2: map_square([0, 1, 2]) returned ' + str(repr(_r1)) + ', expected [0, 1, 4]'",
          "concepts": [
            "map() function",
            "lambda"
          ]
        },
        {
          "id": "ls_29",
          "title": "Filter function",
          "difficulty": 3,
          "description": "Write a function that filters a list to keep only elements that satisfy a condition using filter().",
          "hints": [
            "Use filter(func, list) where func returns True/False.",
            "Convert to list for the result."
          ],
          "solution": "def filter_positive(numbers):\n    return list(filter(lambda x: x > 0, numbers))",
          "starter_code": "def filter_positive(numbers):\n    pass",
          "test_code": "assert 'filter_positive' in dir(), \"Function 'filter_positive' not defined. Did you write: def filter_positive(...)?\"\n_r0 = filter_positive([-1, 2, -3, 4])\nassert _r0 == [2, 4], 'Test 1: filter_positive([-1, 2, -3, 4]) returned ' + str(repr(_r0)) + ', expected [2, 4]'\n_r1 = filter_positive([-5, 0, 5])\nassert _r1 == [5], 'Test 2: filter_positive([-5, 0, 5]) returned ' + str(repr(_r1)) + ', expected [5]'",
          "concepts": [
            "filter() function"
          ]
        },
        {
          "id": "ls_30",
          "title": "Flatten a nested list",
          "difficulty": 3,
          "description": "Write a function that flattens a 2D list (list of lists) into a single list.",
          "hints": [
            "Use list comprehension with nested iteration.",
            "Or use sum() with an empty list as start: sum(list, [])."
          ],
          "solution": "def flatten(matrix):\n    return [item for row in matrix for item in row]",
          "starter_code": "def flatten(matrix):\n    pass",
          "test_code": "assert 'flatten' in dir(), \"Function 'flatten' not defined. Did you write: def flatten(...)?\"\n_r0 = flatten([[1, 2], [3, 4]])\nassert _r0 == [1, 2, 3, 4], 'Test 1: flatten([[1, 2], [3, 4]]) returned ' + str(repr(_r0)) + ', expected [1, 2, 3, 4]'\n_r1 = flatten([['a', 'b'], ['c']])\nassert _r1 == ['a', 'b', 'c'], \"Test 2: flatten([['a', 'b'], ['c']]) returned \" + str(repr(_r1)) + \", expected ['a', 'b', 'c']\"",
          "concepts": [
            "nested list comprehension",
            "flattening"
          ]
        },
        {
          "id": "ls_31",
          "title": "Rotate a list",
          "difficulty": 3,
          "description": "Write a function that rotates a list to the right by n positions.",
          "hints": [
            "Use slicing: last n elements + first (len-n) elements.",
            "If n=2 and list=[1,2,3,4], result is [3,4,1,2]."
          ],
          "solution": "def rotate_right(items, n):\n    n = n % len(items) if items else 0\n    return items[-n:] + items[:-n] if n else items[:]",
          "starter_code": "def rotate_right(items, n):\n    pass",
          "test_code": "assert 'rotate_right' in dir(), \"Function 'rotate_right' not defined. Did you write: def rotate_right(...)?\"\n_r0 = rotate_right([1, 2, 3, 4], 2)\nassert _r0 == [3, 4, 1, 2], 'Test 1: rotate_right([1, 2, 3, 4], 2) returned ' + str(repr(_r0)) + ', expected [3, 4, 1, 2]'\n_r1 = rotate_right([1, 2, 3], 1)\nassert _r1 == [3, 1, 2], 'Test 2: rotate_right([1, 2, 3], 1) returned ' + str(repr(_r1)) + ', expected [3, 1, 2]'\n_r2 = rotate_right([1, 2], 0)\nassert _r2 == [1, 2], 'Test 3: rotate_right([1, 2], 0) returned ' + str(repr(_r2)) + ', expected [1, 2]'",
          "concepts": [
            "list slicing",
            "rotation"
          ]
        },
        {
          "id": "ls_32",
          "title": "Remove duplicates (order preserved)",
          "difficulty": 3,
          "description": "Write a function that removes duplicates from a list while preserving the original order.",
          "hints": [
            "Use a set to track seen elements.",
            "Iterate through and keep only the first occurrence."
          ],
          "solution": "def remove_duplicates(items):\n    seen = set()\n    result = []\n    for item in items:\n        if item not in seen:\n            seen.add(item)\n            result.append(item)\n    return result",
          "starter_code": "def remove_duplicates(items):\n    pass",
          "test_code": "assert 'remove_duplicates' in dir(), \"Function 'remove_duplicates' not defined. Did you write: def remove_duplicates(...)?\"\n_r0 = remove_duplicates([1, 2, 2, 3, 1, 4])\nassert _r0 == [1, 2, 3, 4], 'Test 1: remove_duplicates([1, 2, 2, 3, 1, 4]) returned ' + str(repr(_r0)) + ', expected [1, 2, 3, 4]'\n_r1 = remove_duplicates(['a', 'b', 'a'])\nassert _r1 == ['a', 'b'], \"Test 2: remove_duplicates(['a', 'b', 'a']) returned \" + str(repr(_r1)) + \", expected ['a', 'b']\"\n_r2 = remove_duplicates([1, 2, 3])\nassert _r2 == [1, 2, 3], 'Test 3: remove_duplicates([1, 2, 3]) returned ' + str(repr(_r2)) + ', expected [1, 2, 3]'",
          "concepts": [
            "deduplication",
            "set usage"
          ]
        },
        {
          "id": "ls_33",
          "title": "Find common elements",
          "difficulty": 3,
          "description": "Write a function that finds common elements between two lists and returns a set.",
          "hints": [
            "Convert to sets and use intersection.",
            "Or use a loop with membership test."
          ],
          "solution": "def common_elements(list1, list2):\n    return set(list1) & set(list2)",
          "starter_code": "def common_elements(list1, list2):\n    pass",
          "test_code": "assert 'common_elements' in dir(), \"Function 'common_elements' not defined. Did you write: def common_elements(...)?\"\n_r0 = common_elements([1, 2, 3], [2, 3, 4])\nassert _r0 == {2, 3}, 'Test 1: common_elements([1, 2, 3], [2, 3, 4]) returned ' + str(repr(_r0)) + ', expected {2, 3}'\n_r1 = common_elements([1, 2], [3, 4])\nassert _r1 == set(), 'Test 2: common_elements([1, 2], [3, 4]) returned ' + str(repr(_r1)) + ', expected set()'",
          "concepts": [
            "set intersection"
          ]
        },
        {
          "id": "ls_34",
          "title": "Stack with list (LIFO)",
          "difficulty": 3,
          "description": "Write a Stack class using a list that supports push and pop operations.",
          "hints": [
            "Use append() for push (add to end).",
            "Use pop() for pop (remove from end)."
          ],
          "solution": "class Stack:\n    def __init__(self):\n        self.items = []\n    def push(self, item):\n        self.items.append(item)\n    def pop(self):\n        return self.items.pop()",
          "starter_code": "class Stack:\n    pass",
          "test_code": "assert 'Stack' in dir(), \"'Stack' is not defined\"\nassert callable(Stack), \"'Stack' should be a function\"",
          "concepts": [
            "stack pattern",
            "LIFO"
          ]
        },
        {
          "id": "ls_35",
          "title": "Queue with list (FIFO)",
          "difficulty": 3,
          "description": "Write a Queue class using a list that supports enqueue and dequeue operations.",
          "hints": [
            "Use append() for enqueue (add to end).",
            "Use pop(0) for dequeue (remove from beginning)."
          ],
          "solution": "class Queue:\n    def __init__(self):\n        self.items = []\n    def enqueue(self, item):\n        self.items.append(item)\n    def dequeue(self):\n        return self.items.pop(0)",
          "starter_code": "class Queue:\n    pass",
          "test_code": "assert 'Queue' in dir(), \"'Queue' is not defined\"\nassert callable(Queue), \"'Queue' should be a function\"",
          "concepts": [
            "queue pattern",
            "FIFO"
          ]
        },
        {
          "id": "ls_36",
          "title": "Create a set",
          "difficulty": 4,
          "description": "Write a function that creates a set from a list and returns its length.",
          "hints": [
            "Use set(list) to create a set.",
            "Sets remove duplicates automatically."
          ],
          "solution": "def make_set(items):\n    return len(set(items))",
          "starter_code": "def make_set(items):\n    pass",
          "test_code": "assert 'make_set' in dir(), \"Function 'make_set' not defined. Did you write: def make_set(...)?\"\n_r0 = make_set([1, 1, 2, 3])\nassert _r0 == 3, 'Test 1: make_set([1, 1, 2, 3]) returned ' + str(repr(_r0)) + ', expected 3'\n_r1 = make_set([1, 2, 3])\nassert _r1 == 3, 'Test 2: make_set([1, 2, 3]) returned ' + str(repr(_r1)) + ', expected 3'\n_r2 = make_set([])\nassert _r2 == 0, 'Test 3: make_set([]) returned ' + str(repr(_r2)) + ', expected 0'",
          "concepts": [
            "set creation"
          ]
        },
        {
          "id": "ls_37",
          "title": "Set union",
          "difficulty": 4,
          "description": "Write a function that returns the union of two sets.",
          "hints": [
            "Use | operator or .union() method.",
            "Union includes all elements from both sets."
          ],
          "solution": "def set_union(set1, set2):\n    return set1 | set2",
          "starter_code": "def set_union(set1, set2):\n    pass",
          "test_code": "assert 'set_union' in dir(), \"Function 'set_union' not defined. Did you write: def set_union(...)?\"\n_r0 = set_union({1, 2}, {2, 3})\nassert _r0 == {1, 2, 3}, 'Test 1: set_union({1, 2}, {2, 3}) returned ' + str(repr(_r0)) + ', expected {1, 2, 3}'\n_r1 = set_union({1}, {2})\nassert _r1 == {1, 2}, 'Test 2: set_union({1}, {2}) returned ' + str(repr(_r1)) + ', expected {1, 2}'",
          "concepts": [
            "set union",
            "| operator"
          ]
        },
        {
          "id": "ls_38",
          "title": "Set intersection",
          "difficulty": 4,
          "description": "Write a function that returns the intersection of two sets.",
          "hints": [
            "Use & operator or .intersection() method.",
            "Intersection includes only common elements."
          ],
          "solution": "def set_intersection(set1, set2):\n    return set1 & set2",
          "starter_code": "def set_intersection(set1, set2):\n    pass",
          "test_code": "assert 'set_intersection' in dir(), \"Function 'set_intersection' not defined. Did you write: def set_intersection(...)?\"\n_r0 = set_intersection({1, 2, 3}, {2, 3, 4})\nassert _r0 == {2, 3}, 'Test 1: set_intersection({1, 2, 3}, {2, 3, 4}) returned ' + str(repr(_r0)) + ', expected {2, 3}'\n_r1 = set_intersection({1, 2}, {3, 4})\nassert _r1 == set(), 'Test 2: set_intersection({1, 2}, {3, 4}) returned ' + str(repr(_r1)) + ', expected set()'",
          "concepts": [
            "set intersection",
            "& operator"
          ]
        },
        {
          "id": "ls_39",
          "title": "Set difference",
          "difficulty": 4,
          "description": "Write a function that returns elements in set1 but not in set2.",
          "hints": [
            "Use - operator or .difference() method.",
            "a - b = elements in a but not in b."
          ],
          "solution": "def set_difference(set1, set2):\n    return set1 - set2",
          "starter_code": "def set_difference(set1, set2):\n    pass",
          "test_code": "assert 'set_difference' in dir(), \"Function 'set_difference' not defined. Did you write: def set_difference(...)?\"\n_r0 = set_difference({1, 2, 3}, {2, 3, 4})\nassert _r0 == {1}, 'Test 1: set_difference({1, 2, 3}, {2, 3, 4}) returned ' + str(repr(_r0)) + ', expected {1}'\n_r1 = set_difference({1, 2}, {3, 4})\nassert _r1 == {1, 2}, 'Test 2: set_difference({1, 2}, {3, 4}) returned ' + str(repr(_r1)) + ', expected {1, 2}'",
          "concepts": [
            "set difference",
            "- operator"
          ]
        },
        {
          "id": "ls_40",
          "title": "Set symmetric difference",
          "difficulty": 4,
          "description": "Write a function that returns elements in either set but not both.",
          "hints": [
            "Use ^ operator or .symmetric_difference() method.",
            "a ^ b = (a - b) | (b - a)."
          ],
          "solution": "def set_sym_diff(set1, set2):\n    return set1 ^ set2",
          "starter_code": "def set_sym_diff(set1, set2):\n    pass",
          "test_code": "assert 'set_sym_diff' in dir(), \"Function 'set_sym_diff' not defined. Did you write: def set_sym_diff(...)?\"\n_r0 = set_sym_diff({1, 2, 3}, {2, 3, 4})\nassert _r0 == {1, 4}, 'Test 1: set_sym_diff({1, 2, 3}, {2, 3, 4}) returned ' + str(repr(_r0)) + ', expected {1, 4}'\n_r1 = set_sym_diff({1, 2}, {1, 2})\nassert _r1 == set(), 'Test 2: set_sym_diff({1, 2}, {1, 2}) returned ' + str(repr(_r1)) + ', expected set()'",
          "concepts": [
            "symmetric difference",
            "^ operator"
          ]
        },
        {
          "id": "ls_41",
          "title": "Set add and discard",
          "difficulty": 4,
          "description": "Write a function that adds an element to a set, then discards another, returning the modified set.",
          "hints": [
            "Use .add() to add an element.",
            "Use .discard() to remove without error if not present."
          ],
          "solution": "def modify_set(s, add_elem, discard_elem):\n    s.add(add_elem)\n    s.discard(discard_elem)\n    return s",
          "starter_code": "def modify_set(s, add_elem, discard_elem):\n    pass",
          "test_code": "assert 'modify_set' in dir(), \"Function 'modify_set' not defined. Did you write: def modify_set(...)?\"\n_r0 = modify_set({1, 2}, 3, 1)\nassert _r0 == {2, 3}, 'Test 1: modify_set({1, 2}, 3, 1) returned ' + str(repr(_r0)) + ', expected {2, 3}'\n_r1 = modify_set({1}, 2, 3)\nassert _r1 == {1, 2}, 'Test 2: modify_set({1}, 2, 3) returned ' + str(repr(_r1)) + ', expected {1, 2}'",
          "concepts": [
            "add() and discard() methods"
          ]
        },
        {
          "id": "ls_42",
          "title": "Set comprehension",
          "difficulty": 4,
          "description": "Write a set comprehension that creates a set of squares of numbers.",
          "hints": [
            "Use {expression for item in iterable}.",
            "Similar to list comprehension but with braces and produces a set."
          ],
          "solution": "def square_set(numbers):\n    return {x**2 for x in numbers}",
          "starter_code": "def square_set(numbers):\n    pass",
          "test_code": "assert 'square_set' in dir(), \"Function 'square_set' not defined. Did you write: def square_set(...)?\"\n_r0 = square_set([1, 2, 3])\nassert _r0 == {1, 4, 9}, 'Test 1: square_set([1, 2, 3]) returned ' + str(repr(_r0)) + ', expected {1, 4, 9}'\n_r1 = square_set([1, 2, 2, 3])\nassert _r1 == {1, 4, 9}, 'Test 2: square_set([1, 2, 2, 3]) returned ' + str(repr(_r1)) + ', expected {1, 4, 9}'",
          "concepts": [
            "set comprehension"
          ]
        },
        {
          "id": "ls_43",
          "title": "Frozenset basics",
          "difficulty": 4,
          "description": "Write a function that creates an immutable frozenset from a list.",
          "hints": [
            "Use frozenset(iterable) to create an immutable set.",
            "Frozensets can be used as dictionary keys."
          ],
          "solution": "def make_frozenset(items):\n    return frozenset(items)",
          "starter_code": "def make_frozenset(items):\n    pass",
          "test_code": "assert 'make_frozenset' in dir(), \"Function 'make_frozenset' not defined. Did you write: def make_frozenset(...)?\"\n_r0 = make_frozenset([1, 2, 3])\nassert _r0 == frozenset({1, 2, 3}), 'Test 1: make_frozenset([1, 2, 3]) returned ' + str(repr(_r0)) + ', expected frozenset({1, 2, 3})'\n_r1 = make_frozenset([])\nassert _r1 == frozenset(), 'Test 2: make_frozenset([]) returned ' + str(repr(_r1)) + ', expected frozenset()'",
          "concepts": [
            "frozenset"
          ]
        },
        {
          "id": "ls_44",
          "title": "Subset and superset",
          "difficulty": 4,
          "description": "Write a function that checks if set1 is a subset of set2.",
          "hints": [
            "Use <= operator or .issubset() method.",
            "a <= b means all elements of a are in b."
          ],
          "solution": "def is_subset(set1, set2):\n    return set1 <= set2",
          "starter_code": "def is_subset(set1, set2):\n    pass",
          "test_code": "assert 'is_subset' in dir(), \"Function 'is_subset' not defined. Did you write: def is_subset(...)?\"\n_r0 = is_subset({1, 2}, {1, 2, 3})\nassert _r0 == True, 'Test 1: is_subset({1, 2}, {1, 2, 3}) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = is_subset({1, 2}, {2, 3})\nassert _r1 == False, 'Test 2: is_subset({1, 2}, {2, 3}) returned ' + str(repr(_r1)) + ', expected False'\n_r2 = is_subset({1}, {1})\nassert _r2 == True, 'Test 3: is_subset({1}, {1}) returned ' + str(repr(_r2)) + ', expected True'",
          "concepts": [
            "subset",
            "<= operator"
          ]
        },
        {
          "id": "ls_45",
          "title": "Group by value (dict with lists)",
          "difficulty": 4,
          "description": "Write a function that groups students by their grade, returning a dict where keys are grades and values are lists of student names.",
          "hints": [
            "Use a dictionary comprehension or loop.",
            "Collect students with the same grade in a list."
          ],
          "solution": "def group_by_grade(students):\n    # students is a list of (name, grade) tuples\n    groups = {}\n    for name, grade in students:\n        if grade not in groups:\n            groups[grade] = []\n        groups[grade].append(name)\n    return groups",
          "starter_code": "def group_by_grade(students):\n    pass",
          "test_code": "assert 'group_by_grade' in dir(), \"Function 'group_by_grade' not defined. Did you write: def group_by_grade(...)?\"\n_r0 = group_by_grade([('Alice', 'A'), ('Bob', 'B'), ('Charlie', 'A')])\nassert _r0 == {'A': ['Alice', 'Charlie'], 'B': ['Bob']}, \"Test 1: group_by_grade([('Alice', 'A'), ('Bob', 'B'), ('Charlie', 'A')]) returned \" + str(repr(_r0)) + \", expected {'A': ['Alice', 'Charlie'], 'B': ['Bob']}\"",
          "concepts": [
            "grouping",
            "dictionary construction"
          ]
        },
        {
          "id": "ls_46",
          "title": "Leaderboard ranking",
          "difficulty": 5,
          "description": "Write a function that takes a list of (player, score) tuples and returns a sorted leaderboard as a list of player names, highest score first. Players with the same score maintain original order.",
          "hints": [
            "Use sorted() with a key function that sorts by score in reverse.",
            "Use key=lambda x: -x[1] or key=lambda x: x[1], reverse=True."
          ],
          "solution": "def leaderboard(players):\n    return [name for name, score in sorted(players, key=lambda x: x[1], reverse=True)]",
          "starter_code": "def leaderboard(players):\n    pass",
          "test_code": "assert 'leaderboard' in dir(), \"Function 'leaderboard' not defined. Did you write: def leaderboard(...)?\"\n_r0 = leaderboard([('Alice', 100), ('Bob', 90), ('Charlie', 100)])\nassert _r0 == ['Alice', 'Charlie', 'Bob'], \"Test 1: leaderboard([('Alice', 100), ('Bob', 90), ('Charlie', 100)]) returned \" + str(repr(_r0)) + \", expected ['Alice', 'Charlie', 'Bob']\"\n_r1 = leaderboard([('Eve', 50)])\nassert _r1 == ['Eve'], \"Test 2: leaderboard([('Eve', 50)]) returned \" + str(repr(_r1)) + \", expected ['Eve']\"",
          "concepts": [
            "sorting with key",
            "unpacking"
          ]
        },
        {
          "id": "ls_47",
          "title": "Find unique tags",
          "difficulty": 5,
          "description": "Write a function that takes a list of posts (each is a dict with 'tags' key containing a list), and returns a sorted list of all unique tags across all posts.",
          "hints": [
            "Flatten all tags from all posts.",
            "Use a set to get unique tags."
          ],
          "solution": "def unique_tags(posts):\n    all_tags = set()\n    for post in posts:\n        all_tags.update(post['tags'])\n    return sorted(list(all_tags))",
          "starter_code": "def unique_tags(posts):\n    pass",
          "test_code": "assert 'unique_tags' in dir(), \"Function 'unique_tags' not defined. Did you write: def unique_tags(...)?\"\n_r0 = unique_tags([{'tags': ['python', 'coding']}, {'tags': ['python', 'ai']}])\nassert _r0 == ['ai', 'coding', 'python'], \"Test 1: unique_tags([{'tags': ['python', 'coding']}, {'tags': ['python', 'ai']}]) returned \" + str(repr(_r0)) + \", expected ['ai', 'coding', 'python']\"",
          "concepts": [
            "set operations",
            "dict iteration"
          ]
        },
        {
          "id": "ls_48",
          "title": "Shopping cart operations",
          "difficulty": 5,
          "description": "Write a function that takes two lists of item IDs: 'cart' and 'wishlist'. Return items that are in cart but not in wishlist (things to remove) as a set.",
          "hints": [
            "Convert to sets and use set difference.",
            "cart - wishlist gives items in cart but not in wishlist."
          ],
          "solution": "def items_to_remove(cart, wishlist):\n    return set(cart) - set(wishlist)",
          "starter_code": "def items_to_remove(cart, wishlist):\n    pass",
          "test_code": "assert 'items_to_remove' in dir(), \"Function 'items_to_remove' not defined. Did you write: def items_to_remove(...)?\"\n_r0 = items_to_remove([1, 2, 3, 4], [1, 2])\nassert _r0 == {3, 4}, 'Test 1: items_to_remove([1, 2, 3, 4], [1, 2]) returned ' + str(repr(_r0)) + ', expected {3, 4}'",
          "concepts": [
            "set difference",
            "practical application"
          ]
        },
        {
          "id": "ls_49",
          "title": "Matrix transpose",
          "difficulty": 5,
          "description": "Write a function that transposes a 2D list (matrix). Rows become columns and columns become rows.",
          "hints": [
            "Use zip() with unpacking: list(zip(*matrix)).",
            "zip unpacks rows and pairs columns together."
          ],
          "solution": "def transpose(matrix):\n    return [list(row) for row in zip(*matrix)]",
          "starter_code": "def transpose(matrix):\n    pass",
          "test_code": "assert 'transpose' in dir(), \"Function 'transpose' not defined. Did you write: def transpose(...)?\"\n_r0 = transpose([[1, 2], [3, 4]])\nassert _r0 == [[1, 3], [2, 4]], 'Test 1: transpose([[1, 2], [3, 4]]) returned ' + str(repr(_r0)) + ', expected [[1, 3], [2, 4]]'\n_r1 = transpose([[1, 2, 3], [4, 5, 6]])\nassert _r1 == [[1, 4], [2, 5], [3, 6]], 'Test 2: transpose([[1, 2, 3], [4, 5, 6]]) returned ' + str(repr(_r1)) + ', expected [[1, 4], [2, 5], [3, 6]]'",
          "concepts": [
            "zip with unpacking",
            "matrix operations"
          ]
        },
        {
          "id": "ls_50",
          "title": "Inventory management",
          "difficulty": 5,
          "description": "Write a function that manages inventory: given a list of purchases (item_id, quantity), return a dict counting total quantity per item, ignoring items with negative quantity (returns/refunds).",
          "hints": [
            "Filter out negative quantities first.",
            "Use a dict or defaultdict to accumulate quantities."
          ],
          "solution": "def inventory_total(purchases):\n    inventory = {}\n    for item_id, qty in purchases:\n        if qty > 0:\n            if item_id not in inventory:\n                inventory[item_id] = 0\n            inventory[item_id] += qty\n    return inventory",
          "starter_code": "def inventory_total(purchases):\n    pass",
          "test_code": "assert 'inventory_total' in dir(), \"Function 'inventory_total' not defined. Did you write: def inventory_total(...)?\"\n_r0 = inventory_total([('A', 5), ('B', 3), ('A', 2), ('B', -1)])\nassert _r0 == {'A': 7, 'B': 3}, \"Test 1: inventory_total([('A', 5), ('B', 3), ('A', 2), ('B', -1)]) returned \" + str(repr(_r0)) + \", expected {'A': 7, 'B': 3}\"\n_r1 = inventory_total([('X', 10)])\nassert _r1 == {'X': 10}, \"Test 2: inventory_total([('X', 10)]) returned \" + str(repr(_r1)) + \", expected {'X': 10}\"",
          "concepts": [
            "dict accumulation",
            "filtering",
            "real-world scenario"
          ]
        }
      ]
    },
    {
      "id": "dictionaries",
      "title": "Dictionaries",
      "exercise_count": 50,
      "exercises": [
        {
          "id": "dict_01",
          "title": "Create a Dictionary",
          "difficulty": 1,
          "description": "Create a dictionary called `person` with keys 'name' and 'age', with values 'Alice' and 30.",
          "hints": [
            "Use curly braces {} to create a dictionary",
            "Separate key-value pairs with colons: key: value"
          ],
          "solution": "person = {'name': 'Alice', 'age': 30}",
          "starter_code": "",
          "test_code": "assert isinstance(person, dict), 'person should be a dictionary, got ' + str(type(person).__name__)\nassert len(person) > 0, \"person should not be empty\"",
          "concepts": [
            "dict creation",
            "key-value pairs"
          ]
        },
        {
          "id": "dict_02",
          "title": "Access Dictionary Value",
          "difficulty": 1,
          "description": "Create a dictionary `fruit_colors = {'apple': 'red', 'banana': 'yellow'}` and access the value for 'apple'.",
          "hints": [
            "Use square brackets with the key: dict[key]",
            "Store the result in variable `color`"
          ],
          "solution": "fruit_colors = {'apple': 'red', 'banana': 'yellow'}\ncolor = fruit_colors['apple']",
          "starter_code": "",
          "test_code": "assert isinstance(fruit_colors, dict), 'fruit_colors should be a dictionary, got ' + str(type(fruit_colors).__name__)\nassert len(fruit_colors) > 0, \"fruit_colors should not be empty\"\nassert color == 'red', \"color should be 'red', got \" + str(repr(color))",
          "concepts": [
            "dict access",
            "indexing"
          ]
        },
        {
          "id": "dict_03",
          "title": "Add Key-Value to Dictionary",
          "difficulty": 1,
          "description": "Create an empty dictionary `scores = {}` and add a key 'math' with value 95.",
          "hints": [
            "Use square bracket assignment: dict[key] = value",
            "You can add new keys to an empty dict"
          ],
          "solution": "scores = {}\nscores['math'] = 95",
          "starter_code": "",
          "test_code": "assert isinstance(scores, dict), 'scores should be a dictionary, got ' + str(type(scores).__name__)\nassert len(scores) > 0, \"scores should not be empty\"",
          "concepts": [
            "dict assignment",
            "adding keys"
          ]
        },
        {
          "id": "dict_04",
          "title": "Update Dictionary Value",
          "difficulty": 1,
          "description": "Create a dict `config = {'debug': False}` and update the value of 'debug' to True.",
          "hints": [
            "Use assignment like adding a new key",
            "Since 'debug' already exists, it updates the value"
          ],
          "solution": "config = {'debug': False}\nconfig['debug'] = True",
          "starter_code": "",
          "test_code": "assert isinstance(config, dict), 'config should be a dictionary, got ' + str(type(config).__name__)\nassert len(config) > 0, \"config should not be empty\"",
          "concepts": [
            "dict update",
            "overwriting values"
          ]
        },
        {
          "id": "dict_05",
          "title": "Delete a Dictionary Key",
          "difficulty": 1,
          "description": "Create a dict `inventory = {'apples': 10, 'oranges': 5}` and delete the 'oranges' key.",
          "hints": [
            "Use the del keyword: del dict[key]",
            "After deletion, the key-value pair is gone"
          ],
          "solution": "inventory = {'apples': 10, 'oranges': 5}\ndel inventory['oranges']",
          "starter_code": "",
          "test_code": "assert isinstance(inventory, dict), 'inventory should be a dictionary, got ' + str(type(inventory).__name__)\nassert len(inventory) > 0, \"inventory should not be empty\"",
          "concepts": [
            "del keyword",
            "removing keys"
          ]
        },
        {
          "id": "dict_06",
          "title": "Check if Key Exists",
          "difficulty": 1,
          "description": "Create a dict `user = {'username': 'john', 'email': 'john@example.com'}` and check if 'email' is in it.",
          "hints": [
            "Use the 'in' operator: key in dict",
            "This returns True or False"
          ],
          "solution": "user = {'username': 'john', 'email': 'john@example.com'}\nresult = 'email' in user",
          "starter_code": "",
          "test_code": "assert isinstance(user, dict), 'user should be a dictionary, got ' + str(type(user).__name__)\nassert len(user) > 0, \"user should not be empty\"\nassert isinstance(result, bool), 'result should be a boolean (True/False), got ' + str(type(result).__name__)",
          "concepts": [
            "membership test",
            "in operator"
          ]
        },
        {
          "id": "dict_07",
          "title": "Use dict.get() with Default",
          "difficulty": 1,
          "description": "Create a dict `settings = {'theme': 'dark'}` and use .get() to safely access 'language' with default 'English'.",
          "hints": [
            "Use dict.get(key, default) instead of dict[key]",
            "This returns the value if key exists, otherwise returns default"
          ],
          "solution": "settings = {'theme': 'dark'}\nlanguage = settings.get('language', 'English')",
          "starter_code": "",
          "test_code": "assert isinstance(settings, dict), 'settings should be a dictionary, got ' + str(type(settings).__name__)\nassert len(settings) > 0, \"settings should not be empty\"\nassert language == 'English', \"language should be 'English', got \" + str(repr(language))",
          "concepts": [
            "dict.get()",
            "default values",
            "safe access"
          ]
        },
        {
          "id": "dict_08",
          "title": "Get All Keys",
          "difficulty": 1,
          "description": "Create a dict `book = {'title': 'Python', 'author': 'Guido', 'year': 1991}` and get all keys.",
          "hints": [
            "Use dict.keys() method",
            "Store the keys in variable `keys_list` as a list"
          ],
          "solution": "book = {'title': 'Python', 'author': 'Guido', 'year': 1991}\nkeys_list = list(book.keys())",
          "starter_code": "",
          "test_code": "assert isinstance(book, dict), 'book should be a dictionary, got ' + str(type(book).__name__)\nassert len(book) > 0, \"book should not be empty\"\nassert isinstance(keys_list, list), 'keys_list should be a list, got ' + str(type(keys_list).__name__)\nassert len(keys_list) > 0, \"keys_list should not be empty\"",
          "concepts": [
            "dict.keys()",
            "getting keys"
          ]
        },
        {
          "id": "dict_09",
          "title": "Get All Values",
          "difficulty": 1,
          "description": "Create a dict `grades = {'Alice': 90, 'Bob': 85}` and get all values as a list.",
          "hints": [
            "Use dict.values() method",
            "Convert to a list with list()"
          ],
          "solution": "grades = {'Alice': 90, 'Bob': 85}\nvalues_list = list(grades.values())",
          "starter_code": "",
          "test_code": "assert isinstance(grades, dict), 'grades should be a dictionary, got ' + str(type(grades).__name__)\nassert len(grades) > 0, \"grades should not be empty\"\nassert isinstance(values_list, list), 'values_list should be a list, got ' + str(type(values_list).__name__)\nassert len(values_list) > 0, \"values_list should not be empty\"",
          "concepts": [
            "dict.values()",
            "getting values"
          ]
        },
        {
          "id": "dict_10",
          "title": "Get Key-Value Pairs",
          "difficulty": 1,
          "description": "Create a dict `product = {'name': 'Laptop', 'price': 999}` and get all key-value pairs.",
          "hints": [
            "Use dict.items() method",
            "Store result as a list in `pairs`"
          ],
          "solution": "product = {'name': 'Laptop', 'price': 999}\npairs = list(product.items())",
          "starter_code": "",
          "test_code": "assert isinstance(product, dict), 'product should be a dictionary, got ' + str(type(product).__name__)\nassert len(product) > 0, \"product should not be empty\"\nassert isinstance(pairs, list), 'pairs should be a list, got ' + str(type(pairs).__name__)\nassert len(pairs) > 0, \"pairs should not be empty\"",
          "concepts": [
            "dict.items()",
            "key-value pairs"
          ]
        },
        {
          "id": "dict_11",
          "title": "Iterate Over Dictionary Keys",
          "difficulty": 2,
          "description": "Write a function `get_keys_uppercase` that takes a dict and returns a set of all keys in uppercase.",
          "hints": [
            "Iterate over the dictionary or use dict.keys()",
            "Use .upper() method on each key string"
          ],
          "solution": "def get_keys_uppercase(d):\n    return {k.upper() for k in d.keys()}",
          "starter_code": "",
          "test_code": "assert 'get_keys_uppercase' in dir(), \"Function 'get_keys_uppercase' not defined. Did you write: def get_keys_uppercase(...)?\"\n_r0 = get_keys_uppercase({'name': 'Alice', 'city': 'NYC'})\nassert _r0 == {'CITY', 'NAME'}, \"Test 1: get_keys_uppercase({'name': 'Alice', 'city': 'NYC'}) returned \" + str(repr(_r0)) + \", expected {'CITY', 'NAME'}\"\n_r1 = get_keys_uppercase({'x': 1, 'y': 2})\nassert _r1 == {'Y', 'X'}, \"Test 2: get_keys_uppercase({'x': 1, 'y': 2}) returned \" + str(repr(_r1)) + \", expected {'Y', 'X'}\"",
          "concepts": [
            "iteration",
            "string methods",
            "set comprehension"
          ]
        },
        {
          "id": "dict_12",
          "title": "Iterate Over Dictionary Values",
          "difficulty": 2,
          "description": "Write a function `sum_values` that takes a dict with numeric values and returns their sum.",
          "hints": [
            "Use dict.values() to get all values",
            "Use the sum() function on them"
          ],
          "solution": "def sum_values(d):\n    return sum(d.values())",
          "starter_code": "",
          "test_code": "assert 'sum_values' in dir(), \"Function 'sum_values' not defined. Did you write: def sum_values(...)?\"\n_r0 = sum_values({'a': 10, 'b': 20, 'c': 5})\nassert _r0 == 35, \"Test 1: sum_values({'a': 10, 'b': 20, 'c': 5}) returned \" + str(repr(_r0)) + ', expected 35'\n_r1 = sum_values({'x': 1, 'y': 2, 'z': 3})\nassert _r1 == 6, \"Test 2: sum_values({'x': 1, 'y': 2, 'z': 3}) returned \" + str(repr(_r1)) + ', expected 6'\n_r2 = sum_values({})\nassert _r2 == 0, 'Test 3: sum_values({}) returned ' + str(repr(_r2)) + ', expected 0'",
          "concepts": [
            "dict.values()",
            "sum()"
          ]
        },
        {
          "id": "dict_13",
          "title": "Filter Dictionary by Value",
          "difficulty": 2,
          "description": "Write a function `filter_dict` that returns a new dict containing only items where value > threshold.",
          "hints": [
            "Iterate through dict.items() to get key-value pairs",
            "Use a dict comprehension or loop to build the result"
          ],
          "solution": "def filter_dict(d, threshold):\n    return {k: v for k, v in d.items() if v > threshold}",
          "starter_code": "",
          "test_code": "assert 'filter_dict' in dir(), \"Function 'filter_dict' not defined. Did you write: def filter_dict(...)?\"\n_r0 = filter_dict({'a': 5, 'b': 15, 'c': 10}, 8)\nassert _r0 == {'b': 15, 'c': 10}, \"Test 1: filter_dict({'a': 5, 'b': 15, 'c': 10}, 8) returned \" + str(repr(_r0)) + \", expected {'b': 15, 'c': 10}\"\n_r1 = filter_dict({'x': 1, 'y': 2, 'z': 3}, 2)\nassert _r1 == {'z': 3}, \"Test 2: filter_dict({'x': 1, 'y': 2, 'z': 3}, 2) returned \" + str(repr(_r1)) + \", expected {'z': 3}\"",
          "concepts": [
            "dict comprehension",
            "filtering",
            "dict.items()"
          ]
        },
        {
          "id": "dict_14",
          "title": "Dictionary Comprehension",
          "difficulty": 2,
          "description": "Write a function `square_values` that creates a new dict with the same keys but values squared.",
          "hints": [
            "Use a dict comprehension: {k: expression for k, v in ...}",
            "Iterate over dict.items()"
          ],
          "solution": "def square_values(d):\n    return {k: v ** 2 for k, v in d.items()}",
          "starter_code": "",
          "test_code": "assert 'square_values' in dir(), \"Function 'square_values' not defined. Did you write: def square_values(...)?\"\n_r0 = square_values({'a': 2, 'b': 3, 'c': 4})\nassert _r0 == {'a': 4, 'b': 9, 'c': 16}, \"Test 1: square_values({'a': 2, 'b': 3, 'c': 4}) returned \" + str(repr(_r0)) + \", expected {'a': 4, 'b': 9, 'c': 16}\"\n_r1 = square_values({'x': 5, 'y': 10})\nassert _r1 == {'x': 25, 'y': 100}, \"Test 2: square_values({'x': 5, 'y': 10}) returned \" + str(repr(_r1)) + \", expected {'x': 25, 'y': 100}\"",
          "concepts": [
            "dict comprehension",
            "transformations"
          ]
        },
        {
          "id": "dict_15",
          "title": "Invert Dictionary",
          "difficulty": 2,
          "description": "Write a function `invert_dict` that swaps keys and values (assumes all values are unique).",
          "hints": [
            "Use a dict comprehension: {v: k for k, v in d.items()}",
            "Keys become values and values become keys"
          ],
          "solution": "def invert_dict(d):\n    return {v: k for k, v in d.items()}",
          "starter_code": "",
          "test_code": "assert 'invert_dict' in dir(), \"Function 'invert_dict' not defined. Did you write: def invert_dict(...)?\"\n_r0 = invert_dict({'a': 1, 'b': 2, 'c': 3})\nassert _r0 == {1: 'a', 2: 'b', 3: 'c'}, \"Test 1: invert_dict({'a': 1, 'b': 2, 'c': 3}) returned \" + str(repr(_r0)) + \", expected {1: 'a', 2: 'b', 3: 'c'}\"\n_r1 = invert_dict({'x': 'hello', 'y': 'world'})\nassert _r1 == {'hello': 'x', 'world': 'y'}, \"Test 2: invert_dict({'x': 'hello', 'y': 'world'}) returned \" + str(repr(_r1)) + \", expected {'hello': 'x', 'world': 'y'}\"",
          "concepts": [
            "dict inversion",
            "dict comprehension"
          ]
        },
        {
          "id": "dict_16",
          "title": "Merge Two Dictionaries",
          "difficulty": 2,
          "description": "Write a function `merge_dicts` that combines two dicts (second dict wins on conflicts).",
          "hints": [
            "Use the | operator (Python 3.9+) or dict.update()",
            "Or use {**dict1, **dict2}"
          ],
          "solution": "def merge_dicts(d1, d2):\n    return {**d1, **d2}",
          "starter_code": "",
          "test_code": "assert 'merge_dicts' in dir(), \"Function 'merge_dicts' not defined. Did you write: def merge_dicts(...)?\"\n_r0 = merge_dicts({'a': 1, 'b': 2}, {'c': 3})\nassert _r0 == {'a': 1, 'b': 2, 'c': 3}, \"Test 1: merge_dicts({'a': 1, 'b': 2}, {'c': 3}) returned \" + str(repr(_r0)) + \", expected {'a': 1, 'b': 2, 'c': 3}\"\n_r1 = merge_dicts({'x': 10}, {'x': 20, 'y': 30})\nassert _r1 == {'x': 20, 'y': 30}, \"Test 2: merge_dicts({'x': 10}, {'x': 20, 'y': 30}) returned \" + str(repr(_r1)) + \", expected {'x': 20, 'y': 30}\"",
          "concepts": [
            "dict unpacking",
            "merging"
          ]
        },
        {
          "id": "dict_17",
          "title": "Count Occurrences",
          "difficulty": 2,
          "description": "Write a function `count_items` that counts how many times each item appears in a list.",
          "hints": [
            "Initialize an empty dict",
            "For each item, increment its count or set it to 1"
          ],
          "solution": "def count_items(items):\n    result = {}\n    for item in items:\n        result[item] = result.get(item, 0) + 1\n    return result",
          "starter_code": "",
          "test_code": "assert 'count_items' in dir(), \"Function 'count_items' not defined. Did you write: def count_items(...)?\"\n_r0 = count_items(['a', 'b', 'a', 'c', 'b', 'a'])\nassert _r0 == {'a': 3, 'b': 2, 'c': 1}, \"Test 1: count_items(['a', 'b', 'a', 'c', 'b', 'a']) returned \" + str(repr(_r0)) + \", expected {'a': 3, 'b': 2, 'c': 1}\"\n_r1 = count_items([1, 1, 2, 2, 2, 3])\nassert _r1 == {1: 2, 2: 3, 3: 1}, 'Test 2: count_items([1, 1, 2, 2, 2, 3]) returned ' + str(repr(_r1)) + ', expected {1: 2, 2: 3, 3: 1}'",
          "concepts": [
            "frequency counting",
            "dict.get()"
          ]
        },
        {
          "id": "dict_18",
          "title": "Group List by Function",
          "difficulty": 2,
          "description": "Write a function `group_by_length` that groups words by their length.",
          "hints": [
            "Create a dict where keys are lengths",
            "Values are lists of words with that length"
          ],
          "solution": "def group_by_length(words):\n    result = {}\n    for word in words:\n        length = len(word)\n        if length not in result:\n            result[length] = []\n        result[length].append(word)\n    return result",
          "starter_code": "",
          "test_code": "assert 'group_by_length' in dir(), \"Function 'group_by_length' not defined. Did you write: def group_by_length(...)?\"\n_r0 = group_by_length(['a', 'bb', 'ccc', 'dd'])\nassert _r0 == {1: ['a'], 2: ['bb', 'dd'], 3: ['ccc']}, \"Test 1: group_by_length(['a', 'bb', 'ccc', 'dd']) returned \" + str(repr(_r0)) + \", expected {1: ['a'], 2: ['bb', 'dd'], 3: ['ccc']}\"\n_r1 = group_by_length(['cat', 'dog', 'bird', 'fish'])\nassert _r1 == {3: ['cat', 'dog'], 4: ['bird', 'fish']}, \"Test 2: group_by_length(['cat', 'dog', 'bird', 'fish']) returned \" + str(repr(_r1)) + \", expected {3: ['cat', 'dog'], 4: ['bird', 'fish']}\"",
          "concepts": [
            "grouping",
            "dict of lists"
          ]
        },
        {
          "id": "dict_19",
          "title": "Conditional Dict Creation",
          "difficulty": 2,
          "description": "Write a function `filter_even` that creates a dict with only even keys from the input dict.",
          "hints": [
            "Use a dict comprehension with an if condition",
            "Check if the key is even using key % 2 == 0"
          ],
          "solution": "def filter_even(d):\n    return {k: v for k, v in d.items() if k % 2 == 0}",
          "starter_code": "",
          "test_code": "assert 'filter_even' in dir(), \"Function 'filter_even' not defined. Did you write: def filter_even(...)?\"\n_r0 = filter_even({1: 'a', 2: 'b', 3: 'c', 4: 'd'})\nassert _r0 == {2: 'b', 4: 'd'}, \"Test 1: filter_even({1: 'a', 2: 'b', 3: 'c', 4: 'd'}) returned \" + str(repr(_r0)) + \", expected {2: 'b', 4: 'd'}\"\n_r1 = filter_even({0: 'zero', 5: 'five', 10: 'ten'})\nassert _r1 == {0: 'zero', 10: 'ten'}, \"Test 2: filter_even({0: 'zero', 5: 'five', 10: 'ten'}) returned \" + str(repr(_r1)) + \", expected {0: 'zero', 10: 'ten'}\"",
          "concepts": [
            "dict comprehension",
            "filtering"
          ]
        },
        {
          "id": "dict_20",
          "title": "Dictionary Length and Check Empty",
          "difficulty": 2,
          "description": "Write a function `is_empty` that returns True if dict is empty, False otherwise.",
          "hints": [
            "Use len() function on the dict",
            "Empty dict has length 0"
          ],
          "solution": "def is_empty(d):\n    return len(d) == 0",
          "starter_code": "",
          "test_code": "assert 'is_empty' in dir(), \"Function 'is_empty' not defined. Did you write: def is_empty(...)?\"\n_r0 = is_empty({})\nassert _r0 == True, 'Test 1: is_empty({}) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = is_empty({'a': 1})\nassert _r1 == False, \"Test 2: is_empty({'a': 1}) returned \" + str(repr(_r1)) + ', expected False'\n_r2 = is_empty({'x': 0, 'y': None})\nassert _r2 == False, \"Test 3: is_empty({'x': 0, 'y': None}) returned \" + str(repr(_r2)) + ', expected False'",
          "concepts": [
            "len()",
            "dict length"
          ]
        },
        {
          "id": "dict_21",
          "title": "Nested Dictionary Access",
          "difficulty": 3,
          "description": "Write a function `get_nested` that safely accesses nested.get('user').get('name') with defaults.",
          "hints": [
            "Chain .get() calls with defaults",
            "Return 'Unknown' if any level is missing"
          ],
          "solution": "def get_nested(d):\n    user = d.get('user', {})\n    return user.get('name', 'Unknown')",
          "starter_code": "",
          "test_code": "assert 'get_nested' in dir(), \"Function 'get_nested' not defined. Did you write: def get_nested(...)?\"\n_r0 = get_nested({'user': {'name': 'Alice'}})\nassert _r0 == 'Alice', \"Test 1: get_nested({'user': {'name': 'Alice'}}) returned \" + str(repr(_r0)) + \", expected 'Alice'\"\n_r1 = get_nested({'user': {}})\nassert _r1 == 'Unknown', \"Test 2: get_nested({'user': {}}) returned \" + str(repr(_r1)) + \", expected 'Unknown'\"\n_r2 = get_nested({})\nassert _r2 == 'Unknown', 'Test 3: get_nested({}) returned ' + str(repr(_r2)) + \", expected 'Unknown'\"",
          "concepts": [
            "nested dicts",
            "safe access",
            "chaining"
          ]
        },
        {
          "id": "dict_22",
          "title": "Update Nested Dictionary",
          "difficulty": 3,
          "description": "Write a function `set_nested` that sets a value in dict['user']['email'] = new_email (creating nested structure).",
          "hints": [
            "Check if 'user' key exists, create it if not",
            "Then set the 'email' key"
          ],
          "solution": "def set_nested(d, email):\n    if 'user' not in d:\n        d['user'] = {}\n    d['user']['email'] = email\n    return d",
          "starter_code": "",
          "test_code": "assert 'set_nested' in dir(), \"Function 'set_nested' not defined. Did you write: def set_nested(...)?\"\n_r0 = set_nested({}, 'test@example.com')\nassert _r0 == {'user': {'email': 'test@example.com'}}, \"Test 1: set_nested({}, 'test@example.com') returned \" + str(repr(_r0)) + \", expected {'user': {'email': 'test@example.com'}}\"\n_r1 = set_nested({'user': {'name': 'Bob'}}, 'bob@example.com')\nassert _r1 == {'user': {'name': 'Bob', 'email': 'bob@example.com'}}, \"Test 2: set_nested({'user': {'name': 'Bob'}}, 'bob@example.com') returned \" + str(repr(_r1)) + \", expected {'user': {'name': 'Bob', 'email': 'bob@example.com'}}\"",
          "concepts": [
            "nested dict modification",
            "creating nested structure"
          ]
        },
        {
          "id": "dict_23",
          "title": "Flatten Nested Dictionary",
          "difficulty": 3,
          "description": "Write a function `flatten_dict` that flattens a nested dict into dot-notation keys (e.g., 'user.name').",
          "hints": [
            "Use recursion or iteration to traverse nested structure",
            "Build keys like 'parent.child' as you go deeper"
          ],
          "solution": "def flatten_dict(d, parent_key=''):\n    result = {}\n    for k, v in d.items():\n        new_key = f'{parent_key}.{k}' if parent_key else k\n        if isinstance(v, dict):\n            result.update(flatten_dict(v, new_key))\n        else:\n            result[new_key] = v\n    return result",
          "starter_code": "",
          "test_code": "assert 'flatten_dict' in dir(), \"Function 'flatten_dict' not defined. Did you write: def flatten_dict(...)?\"\n_r0 = flatten_dict({'user': {'name': 'Alice', 'age': 30}})\nassert _r0 == {'user.name': 'Alice', 'user.age': 30}, \"Test 1: flatten_dict({'user': {'name': 'Alice', 'age': 30}}) returned \" + str(repr(_r0)) + \", expected {'user.name': 'Alice', 'user.age': 30}\"\n_r1 = flatten_dict({'a': {'b': {'c': 1}}})\nassert _r1 == {'a.b.c': 1}, \"Test 2: flatten_dict({'a': {'b': {'c': 1}}}) returned \" + str(repr(_r1)) + \", expected {'a.b.c': 1}\"",
          "concepts": [
            "recursion",
            "nested dicts",
            "key construction"
          ]
        },
        {
          "id": "dict_24",
          "title": "Deep Copy vs Shallow Copy",
          "difficulty": 3,
          "description": "Write a function `copy_dict` that creates a deep copy of a nested dict.",
          "hints": [
            "Use copy.deepcopy() from the copy module",
            "Shallow copy (d.copy() or {**d}) won't work for nested dicts"
          ],
          "solution": "import copy\ndef copy_dict(d):\n    return copy.deepcopy(d)",
          "starter_code": "",
          "test_code": "assert 'copy_dict' in dir(), \"Function 'copy_dict' not defined. Did you write: def copy_dict(...)?\"\n_r0 = copy_dict({'a': {'b': 1}})\nassert _r0 == {'a': {'b': 1}}, \"Test 1: copy_dict({'a': {'b': 1}}) returned \" + str(repr(_r0)) + \", expected {'a': {'b': 1}}\"",
          "concepts": [
            "deep copy",
            "copy module"
          ]
        },
        {
          "id": "dict_25",
          "title": "Count Word Frequency",
          "difficulty": 3,
          "description": "Write a function `word_frequency` that counts word frequency in a text (lowercase, no punctuation).",
          "hints": [
            "Split text into words using .split()",
            "Use a dict to count each word",
            "Return dict sorted by count (optional)"
          ],
          "solution": "def word_frequency(text):\n    words = text.lower().split()\n    freq = {}\n    for word in words:\n        freq[word] = freq.get(word, 0) + 1\n    return freq",
          "starter_code": "",
          "test_code": "assert 'word_frequency' in dir(), \"Function 'word_frequency' not defined. Did you write: def word_frequency(...)?\"\n_r0 = word_frequency('hello world hello')\nassert _r0 == {'hello': 2, 'world': 1}, \"Test 1: word_frequency('hello world hello') returned \" + str(repr(_r0)) + \", expected {'hello': 2, 'world': 1}\"\n_r1 = word_frequency('a b c a b a')\nassert _r1 == {'a': 3, 'b': 2, 'c': 1}, \"Test 2: word_frequency('a b c a b a') returned \" + str(repr(_r1)) + \", expected {'a': 3, 'b': 2, 'c': 1}\"",
          "concepts": [
            "frequency analysis",
            "text processing"
          ]
        },
        {
          "id": "dict_26",
          "title": "Merge User Profiles",
          "difficulty": 3,
          "description": "Write a function `merge_profiles` that merges two user profiles (newer values win, keep all fields).",
          "hints": [
            "Combine both dicts",
            "If keys conflict, newer profile's value should win"
          ],
          "solution": "def merge_profiles(old, new):\n    return {**old, **new}",
          "starter_code": "",
          "test_code": "assert 'merge_profiles' in dir(), \"Function 'merge_profiles' not defined. Did you write: def merge_profiles(...)?\"\n_r0 = merge_profiles({'name': 'Alice', 'email': 'old@ex.com'}, {'email': 'new@ex.com', 'phone': '123'})\nassert _r0 == {'name': 'Alice', 'email': 'new@ex.com', 'phone': '123'}, \"Test 1: merge_profiles({'name': 'Alice', 'email': 'old@ex.com'}, {'email': 'new@ex.com', 'phone': '123'}) returned \" + str(repr(_r0)) + \", expected {'name': 'Alice', 'email': 'new@ex.com', 'phone': '123'}\"\n_r1 = merge_profiles({'a': 1, 'b': 2}, {'b': 3, 'c': 4})\nassert _r1 == {'a': 1, 'b': 3, 'c': 4}, \"Test 2: merge_profiles({'a': 1, 'b': 2}, {'b': 3, 'c': 4}) returned \" + str(repr(_r1)) + \", expected {'a': 1, 'b': 3, 'c': 4}\"",
          "concepts": [
            "dict merging",
            "unpacking"
          ]
        },
        {
          "id": "dict_27",
          "title": "Group People by City",
          "difficulty": 3,
          "description": "Write a function `group_by_city` that takes a list of people dicts and groups them by city.",
          "hints": [
            "Each person is a dict with 'name' and 'city' keys",
            "Group by city, values are lists of people (dicts)"
          ],
          "solution": "def group_by_city(people):\n    result = {}\n    for person in people:\n        city = person['city']\n        if city not in result:\n            result[city] = []\n        result[city].append(person)\n    return result",
          "starter_code": "",
          "test_code": "assert 'group_by_city' in dir(), \"Function 'group_by_city' not defined. Did you write: def group_by_city(...)?\"\n_r0 = group_by_city([{'name': 'Alice', 'city': 'NYC'}, {'name': 'Bob', 'city': 'LA'}, {'name': 'Charlie', 'city': 'NYC'}])\nassert _r0 == {'NYC': [{'name': 'Alice', 'city': 'NYC'}, {'name': 'Charlie', 'city': 'NYC'}], 'LA': [{'name': 'Bob', 'city': 'LA'}]}, \"Test 1: group_by_city([{'name': 'Alice', 'city': 'NYC'}, {'name': 'Bob', 'city': 'LA'}, {'name': 'Charlie', 'city': 'NYC'}]) returned \" + str(repr(_r0)) + \", expected {'NYC': [{'name': 'Alice', 'city': 'NYC'}, {'name': 'Charlie', 'city': 'NYC'}], 'LA': [{'name': 'Bob', 'city': 'LA'}]}\"",
          "concepts": [
            "grouping",
            "dict of lists",
            "complex data"
          ]
        },
        {
          "id": "dict_28",
          "title": "Validate Against Schema",
          "difficulty": 3,
          "description": "Write a function `validate_schema` that checks if a dict matches a schema (required keys).",
          "hints": [
            "Schema is a list of required key names",
            "Check if all required keys are present"
          ],
          "solution": "def validate_schema(data, schema):\n    return all(key in data for key in schema)",
          "starter_code": "",
          "test_code": "assert 'validate_schema' in dir(), \"Function 'validate_schema' not defined. Did you write: def validate_schema(...)?\"\n_r0 = validate_schema({'name': 'Alice', 'age': 30}, ['name', 'age'])\nassert _r0 == True, \"Test 1: validate_schema({'name': 'Alice', 'age': 30}, ['name', 'age']) returned \" + str(repr(_r0)) + ', expected True'\n_r1 = validate_schema({'name': 'Bob'}, ['name', 'age'])\nassert _r1 == False, \"Test 2: validate_schema({'name': 'Bob'}, ['name', 'age']) returned \" + str(repr(_r1)) + ', expected False'\n_r2 = validate_schema({'x': 1, 'y': 2, 'z': 3}, ['x', 'y'])\nassert _r2 == True, \"Test 3: validate_schema({'x': 1, 'y': 2, 'z': 3}, ['x', 'y']) returned \" + str(repr(_r2)) + ', expected True'",
          "concepts": [
            "validation",
            "schema checking"
          ]
        },
        {
          "id": "dict_29",
          "title": "Create Lookup Table",
          "difficulty": 3,
          "description": "Write a function `create_lookup` that builds a dict mapping IDs to objects (from a list).",
          "hints": [
            "Each object in the list has an 'id' field",
            "Use dict comprehension or loop to build {id: object} mapping"
          ],
          "solution": "def create_lookup(objects):\n    return {obj['id']: obj for obj in objects}",
          "starter_code": "",
          "test_code": "assert 'create_lookup' in dir(), \"Function 'create_lookup' not defined. Did you write: def create_lookup(...)?\"\n_r0 = create_lookup([{'id': 1, 'name': 'Alice'}, {'id': 2, 'name': 'Bob'}])\nassert _r0 == {1: {'id': 1, 'name': 'Alice'}, 2: {'id': 2, 'name': 'Bob'}}, \"Test 1: create_lookup([{'id': 1, 'name': 'Alice'}, {'id': 2, 'name': 'Bob'}]) returned \" + str(repr(_r0)) + \", expected {1: {'id': 1, 'name': 'Alice'}, 2: {'id': 2, 'name': 'Bob'}}\"",
          "concepts": [
            "dict comprehension",
            "lookup tables"
          ]
        },
        {
          "id": "dict_30",
          "title": "Remove Keys by Pattern",
          "difficulty": 3,
          "description": "Write a function `remove_private_keys` that removes keys starting with '_'.",
          "hints": [
            "Use dict comprehension to filter",
            "Check if key.startswith('_') is False"
          ],
          "solution": "def remove_private_keys(d):\n    return {k: v for k, v in d.items() if not k.startswith('_')}",
          "starter_code": "",
          "test_code": "assert 'remove_private_keys' in dir(), \"Function 'remove_private_keys' not defined. Did you write: def remove_private_keys(...)?\"\n_r0 = remove_private_keys({'public': 1, '_private': 2, 'name': 'Alice'})\nassert _r0 == {'public': 1, 'name': 'Alice'}, \"Test 1: remove_private_keys({'public': 1, '_private': 2, 'name': 'Alice'}) returned \" + str(repr(_r0)) + \", expected {'public': 1, 'name': 'Alice'}\"\n_r1 = remove_private_keys({'_a': 1, '_b': 2, 'x': 3})\nassert _r1 == {'x': 3}, \"Test 2: remove_private_keys({'_a': 1, '_b': 2, 'x': 3}) returned \" + str(repr(_r1)) + \", expected {'x': 3}\"",
          "concepts": [
            "filtering",
            "string methods"
          ]
        },
        {
          "id": "dict_31",
          "title": "Dictionary with setdefault",
          "difficulty": 3,
          "description": "Write a function `get_or_create` that uses setdefault to get value or create with default.",
          "hints": [
            "Use dict.setdefault(key, default)",
            "Returns existing value or sets and returns default"
          ],
          "solution": "def get_or_create(d, key, default):\n    return d.setdefault(key, default)",
          "starter_code": "",
          "test_code": "assert 'get_or_create' in dir(), \"Function 'get_or_create' not defined. Did you write: def get_or_create(...)?\"\n_r0 = get_or_create({'a': 1}, 'a', 0)\nassert _r0 == 1, \"Test 1: get_or_create({'a': 1}, 'a', 0) returned \" + str(repr(_r0)) + ', expected 1'\n_r1 = get_or_create({'a': 1}, 'b', 99)\nassert _r1 == 99, \"Test 2: get_or_create({'a': 1}, 'b', 99) returned \" + str(repr(_r1)) + ', expected 99'",
          "concepts": [
            "dict.setdefault()",
            "default values"
          ]
        },
        {
          "id": "dict_32",
          "title": "Build Inverted Index",
          "difficulty": 3,
          "description": "Write a function `inverted_index` that maps words to documents they appear in.",
          "hints": [
            "Each document is a dict with 'id' and 'text'",
            "Build dict where keys are words, values are lists of doc IDs"
          ],
          "solution": "def inverted_index(documents):\n    index = {}\n    for doc in documents:\n        for word in doc['text'].lower().split():\n            if word not in index:\n                index[word] = []\n            if doc['id'] not in index[word]:\n                index[word].append(doc['id'])\n    return index",
          "starter_code": "",
          "test_code": "assert 'inverted_index' in dir(), \"Function 'inverted_index' not defined. Did you write: def inverted_index(...)?\"\n_r0 = inverted_index([{'id': 1, 'text': 'hello world'}, {'id': 2, 'text': 'hello there'}])\nassert _r0 == {'hello': [1, 2], 'world': [1], 'there': [2]}, \"Test 1: inverted_index([{'id': 1, 'text': 'hello world'}, {'id': 2, 'text': 'hello there'}]) returned \" + str(repr(_r0)) + \", expected {'hello': [1, 2], 'world': [1], 'there': [2]}\"",
          "concepts": [
            "inverted index",
            "text indexing"
          ]
        },
        {
          "id": "dict_33",
          "title": "Dict Comprehension with enumerate",
          "difficulty": 3,
          "description": "Write a function `list_to_dict` that converts a list to dict with indices as keys.",
          "hints": [
            "Use enumerate() to get (index, value) pairs",
            "Build dict comprehension {index: value for ...}"
          ],
          "solution": "def list_to_dict(lst):\n    return {i: v for i, v in enumerate(lst)}",
          "starter_code": "",
          "test_code": "assert 'list_to_dict' in dir(), \"Function 'list_to_dict' not defined. Did you write: def list_to_dict(...)?\"\n_r0 = list_to_dict(['a', 'b', 'c'])\nassert _r0 == {0: 'a', 1: 'b', 2: 'c'}, \"Test 1: list_to_dict(['a', 'b', 'c']) returned \" + str(repr(_r0)) + \", expected {0: 'a', 1: 'b', 2: 'c'}\"\n_r1 = list_to_dict([10, 20, 30])\nassert _r1 == {0: 10, 1: 20, 2: 30}, 'Test 2: list_to_dict([10, 20, 30]) returned ' + str(repr(_r1)) + ', expected {0: 10, 1: 20, 2: 30}'",
          "concepts": [
            "enumerate()",
            "dict comprehension"
          ]
        },
        {
          "id": "dict_34",
          "title": "Compute Running Totals",
          "difficulty": 3,
          "description": "Write a function `running_total` that computes cumulative sum of dict values.",
          "hints": [
            "Iterate through items in order",
            "Keep a running sum variable",
            "Store cumulative value for each key"
          ],
          "solution": "def running_total(d):\n    result = {}\n    total = 0\n    for k, v in d.items():\n        total += v\n        result[k] = total\n    return result",
          "starter_code": "",
          "test_code": "assert 'running_total' in dir(), \"Function 'running_total' not defined. Did you write: def running_total(...)?\"\n_r0 = running_total({'a': 1, 'b': 2, 'c': 3})\nassert _r0 == {'a': 1, 'b': 3, 'c': 6}, \"Test 1: running_total({'a': 1, 'b': 2, 'c': 3}) returned \" + str(repr(_r0)) + \", expected {'a': 1, 'b': 3, 'c': 6}\"",
          "concepts": [
            "iteration",
            "accumulation"
          ]
        },
        {
          "id": "dict_35",
          "title": "Find Key by Value",
          "difficulty": 3,
          "description": "Write a function `find_key` that finds the key for a given value (returns first match).",
          "hints": [
            "Iterate through items",
            "Return key when value matches",
            "Return None if not found"
          ],
          "solution": "def find_key(d, value):\n    for k, v in d.items():\n        if v == value:\n            return k\n    return None",
          "starter_code": "",
          "test_code": "assert 'find_key' in dir(), \"Function 'find_key' not defined. Did you write: def find_key(...)?\"\n_r0 = find_key({'a': 1, 'b': 2, 'c': 3}, 2)\nassert _r0 == 'b', \"Test 1: find_key({'a': 1, 'b': 2, 'c': 3}, 2) returned \" + str(repr(_r0)) + \", expected 'b'\"\n_r1 = find_key({'a': 1, 'b': 2}, 99)\nassert _r1 == None, \"Test 2: find_key({'a': 1, 'b': 2}, 99) returned \" + str(repr(_r1)) + ', expected None'",
          "concepts": [
            "searching",
            "dict.items()"
          ]
        },
        {
          "id": "dict_36",
          "title": "Use defaultdict for Grouping",
          "difficulty": 4,
          "description": "Write a function `group_with_defaultdict` that groups numbers by their modulo 3 using defaultdict(list).",
          "hints": [
            "Import defaultdict from collections",
            "defaultdict(list) creates empty list for missing keys automatically"
          ],
          "solution": "from collections import defaultdict\ndef group_with_defaultdict(numbers):\n    groups = defaultdict(list)\n    for num in numbers:\n        groups[num % 3].append(num)\n    return dict(groups)",
          "starter_code": "",
          "test_code": "assert 'group_with_defaultdict' in dir(), \"Function 'group_with_defaultdict' not defined. Did you write: def group_with_defaultdict(...)?\"\n_r0 = group_with_defaultdict([1, 2, 3, 4, 5, 6])\nassert _r0 == {0: [3, 6], 1: [1, 4], 2: [2, 5]}, 'Test 1: group_with_defaultdict([1, 2, 3, 4, 5, 6]) returned ' + str(repr(_r0)) + ', expected {0: [3, 6], 1: [1, 4], 2: [2, 5]}'",
          "concepts": [
            "defaultdict",
            "collections module"
          ]
        },
        {
          "id": "dict_37",
          "title": "Use Counter for Frequency",
          "difficulty": 4,
          "description": "Write a function `top_words` that uses Counter to find the 3 most common words.",
          "hints": [
            "Import Counter from collections",
            "Counter.most_common(n) returns top n items"
          ],
          "solution": "from collections import Counter\ndef top_words(text):\n    words = text.lower().split()\n    counter = Counter(words)\n    return dict(counter.most_common(3))",
          "starter_code": "",
          "test_code": "assert 'top_words' in dir(), \"Function 'top_words' not defined. Did you write: def top_words(...)?\"\n_r0 = top_words('the quick brown fox quick fox fox')\nassert _r0 == {'fox': 3, 'quick': 2, 'the': 1}, \"Test 1: top_words('the quick brown fox quick fox fox') returned \" + str(repr(_r0)) + \", expected {'fox': 3, 'quick': 2, 'the': 1}\"",
          "concepts": [
            "Counter",
            "collections module",
            "frequency"
          ]
        },
        {
          "id": "dict_38",
          "title": "Use OrderedDict for Ordering",
          "difficulty": 4,
          "description": "Write a function `dict_by_value_desc` that returns dict items sorted by value descending.",
          "hints": [
            "Sort dict.items() by value",
            "Use sorted() with key parameter",
            "Can return as OrderedDict or regular dict (Python 3.7+)"
          ],
          "solution": "def dict_by_value_desc(d):\n    return dict(sorted(d.items(), key=lambda x: x[1], reverse=True))",
          "starter_code": "",
          "test_code": "assert 'dict_by_value_desc' in dir(), \"Function 'dict_by_value_desc' not defined. Did you write: def dict_by_value_desc(...)?\"\n_r0 = dict_by_value_desc({'a': 3, 'b': 1, 'c': 2})\nassert _r0 == {'a': 3, 'c': 2, 'b': 1}, \"Test 1: dict_by_value_desc({'a': 3, 'b': 1, 'c': 2}) returned \" + str(repr(_r0)) + \", expected {'a': 3, 'c': 2, 'b': 1}\"",
          "concepts": [
            "sorting",
            "lambda",
            "dict ordering"
          ]
        },
        {
          "id": "dict_39",
          "title": "Merge Multiple Dictionaries",
          "difficulty": 4,
          "description": "Write a function `merge_many` that merges a list of dicts (later dicts override earlier).",
          "hints": [
            "Use the | operator (Python 3.9+) in a loop",
            "Or use {**d1, **d2, **d3, ...}"
          ],
          "solution": "def merge_many(dicts):\n    result = {}\n    for d in dicts:\n        result |= d\n    return result",
          "starter_code": "",
          "test_code": "assert 'merge_many' in dir(), \"Function 'merge_many' not defined. Did you write: def merge_many(...)?\"\n_r0 = merge_many([{'a': 1}, {'b': 2}, {'a': 3}])\nassert _r0 == {'a': 3, 'b': 2}, \"Test 1: merge_many([{'a': 1}, {'b': 2}, {'a': 3}]) returned \" + str(repr(_r0)) + \", expected {'a': 3, 'b': 2}\"",
          "concepts": [
            "dict merging",
            "| operator"
          ]
        },
        {
          "id": "dict_40",
          "title": "Create Cache with Decorator",
          "difficulty": 4,
          "description": "Write a simple memoization decorator that caches function results using a dict.",
          "hints": [
            "Use a dict inside the decorator to store results",
            "Key is the function arguments",
            "Return cached result if it exists"
          ],
          "solution": "def memoize(func):\n    cache = {}\n    def wrapper(*args):\n        if args not in cache:\n            cache[args] = func(*args)\n        return cache[args]\n    return wrapper",
          "starter_code": "",
          "test_code": "assert 'memoize' in dir(), \"'memoize' is not defined\"\nassert callable(memoize), \"'memoize' should be a function\"",
          "concepts": [
            "caching",
            "decorator",
            "memoization"
          ]
        },
        {
          "id": "dict_41",
          "title": "Parse Query String to Dict",
          "difficulty": 4,
          "description": "Write a function `parse_query` that converts 'a=1&b=2&c=3' into a dict.",
          "hints": [
            "Split by '&' to get key=value pairs",
            "Split each pair by '=' to get key and value"
          ],
          "solution": "def parse_query(query_string):\n    result = {}\n    for pair in query_string.split('&'):\n        key, value = pair.split('=')\n        result[key] = value\n    return result",
          "starter_code": "",
          "test_code": "assert 'parse_query' in dir(), \"Function 'parse_query' not defined. Did you write: def parse_query(...)?\"\n_r0 = parse_query('a=1&b=2&c=3')\nassert _r0 == {'a': '1', 'b': '2', 'c': '3'}, \"Test 1: parse_query('a=1&b=2&c=3') returned \" + str(repr(_r0)) + \", expected {'a': '1', 'b': '2', 'c': '3'}\"",
          "concepts": [
            "parsing",
            "string manipulation"
          ]
        },
        {
          "id": "dict_42",
          "title": "Dict as Dispatch Table",
          "difficulty": 4,
          "description": "Write a function `calculate` that uses a dict to dispatch operations (+, -, *, /).",
          "hints": [
            "Store functions in a dict with operator symbols as keys",
            "Look up and call the appropriate function"
          ],
          "solution": "def calculate(op, args):\n    a, b = args\n    ops = {\n        '+': lambda x, y: x + y,\n        '-': lambda x, y: x - y,\n        '*': lambda x, y: x * y,\n        '/': lambda x, y: x / y,\n    }\n    return ops[op](a, b)",
          "starter_code": "",
          "test_code": "assert 'calculate' in dir(), \"Function 'calculate' not defined. Did you write: def calculate(...)?\"\n_r0 = calculate('+', (5, 3))\nassert _r0 == 8, \"Test 1: calculate('+', (5, 3)) returned \" + str(repr(_r0)) + ', expected 8'\n_r1 = calculate('+', (5, 3))\nassert _r1 == 8, \"Test 2: calculate('+', (5, 3)) returned \" + str(repr(_r1)) + ', expected 8'\n_r2 = calculate('-', (10, 4))\nassert _r2 == 6, \"Test 3: calculate('-', (10, 4)) returned \" + str(repr(_r2)) + ', expected 6'",
          "concepts": [
            "dispatch table",
            "lambda",
            "function storage"
          ]
        },
        {
          "id": "dict_43",
          "title": "Convert Nested List to Dict",
          "difficulty": 4,
          "description": "Write a function `nested_list_to_dict` that converts [['a', 1], ['b', 2]] to {'a': 1, 'b': 2}.",
          "hints": [
            "Iterate through the list of pairs",
            "Each pair is [key, value]",
            "Use dict comprehension or dict() constructor"
          ],
          "solution": "def nested_list_to_dict(pairs):\n    return dict(pairs)",
          "starter_code": "",
          "test_code": "assert 'nested_list_to_dict' in dir(), \"Function 'nested_list_to_dict' not defined. Did you write: def nested_list_to_dict(...)?\"\n_r0 = nested_list_to_dict([['a', 1], ['b', 2]])\nassert _r0 == {'a': 1, 'b': 2}, \"Test 1: nested_list_to_dict([['a', 1], ['b', 2]]) returned \" + str(repr(_r0)) + \", expected {'a': 1, 'b': 2}\"\n_r1 = nested_list_to_dict([['x', 10], ['y', 20], ['z', 30]])\nassert _r1 == {'x': 10, 'y': 20, 'z': 30}, \"Test 2: nested_list_to_dict([['x', 10], ['y', 20], ['z', 30]]) returned \" + str(repr(_r1)) + \", expected {'x': 10, 'y': 20, 'z': 30}\"",
          "concepts": [
            "type conversion",
            "dict constructor"
          ]
        },
        {
          "id": "dict_44",
          "title": "Inventory Management with Dicts",
          "difficulty": 4,
          "description": "Write a function `process_orders` that updates inventory based on orders (subtract quantities).",
          "hints": [
            "Inventory is dict {item: quantity}",
            "Orders is dict {item: quantity_ordered}",
            "Return updated inventory"
          ],
          "solution": "def process_orders(inventory, orders):\n    for item, qty in orders.items():\n        inventory[item] -= qty\n    return inventory",
          "starter_code": "",
          "test_code": "assert 'process_orders' in dir(), \"Function 'process_orders' not defined. Did you write: def process_orders(...)?\"\n_r0 = process_orders({'apple': 100, 'banana': 50}, {'apple': 20, 'banana': 10})\nassert _r0 == {'apple': 80, 'banana': 40}, \"Test 1: process_orders({'apple': 100, 'banana': 50}, {'apple': 20, 'banana': 10}) returned \" + str(repr(_r0)) + \", expected {'apple': 80, 'banana': 40}\"",
          "concepts": [
            "inventory management",
            "dict manipulation"
          ]
        },
        {
          "id": "dict_45",
          "title": "JSON-like Data Transformation",
          "difficulty": 4,
          "description": "Write a function `extract_ids` that extracts all 'id' fields from nested JSON-like dict structure.",
          "hints": [
            "Recursively search for 'id' keys",
            "Handle both dicts and lists",
            "Return list of all found IDs"
          ],
          "solution": "def extract_ids(data):\n    ids = []\n    if isinstance(data, dict):\n        if 'id' in data:\n            ids.append(data['id'])\n        for v in data.values():\n            ids.extend(extract_ids(v))\n    elif isinstance(data, list):\n        for item in data:\n            ids.extend(extract_ids(item))\n    return ids",
          "starter_code": "",
          "test_code": "assert 'extract_ids' in dir(), \"Function 'extract_ids' not defined. Did you write: def extract_ids(...)?\"\n_r0 = extract_ids({'id': 1, 'user': {'id': 2}})\nassert _r0 == [1, 2], \"Test 1: extract_ids({'id': 1, 'user': {'id': 2}}) returned \" + str(repr(_r0)) + ', expected [1, 2]'",
          "concepts": [
            "recursion",
            "JSON processing"
          ]
        },
        {
          "id": "dict_46",
          "title": "Grade Book Statistics",
          "difficulty": 5,
          "description": "Write a function `compute_stats` that takes grade_dict {student: [grades]} and returns {student: {mean, max, min}}.",
          "hints": [
            "Compute mean, max, min for each student's grades",
            "Return nested dict with stats"
          ],
          "solution": "def compute_stats(grades_dict):\n    return {student: {'mean': sum(grades)/len(grades), 'max': max(grades), 'min': min(grades)} for student, grades in grades_dict.items()}",
          "starter_code": "",
          "test_code": "assert 'compute_stats' in dir(), \"Function 'compute_stats' not defined. Did you write: def compute_stats(...)?\"\n_r0 = compute_stats({'Alice': [90, 85, 88], 'Bob': [92, 95, 89]})\nassert _r0 == {'Alice': {'mean': 87.66666666666667, 'max': 90, 'min': 85}, 'Bob': {'mean': 92.0, 'max': 95, 'min': 89}}, \"Test 1: compute_stats({'Alice': [90, 85, 88], 'Bob': [92, 95, 89]}) returned \" + str(repr(_r0)) + \", expected {'Alice': {'mean': 87.66666666666667, 'max': 90, 'min': 85}, 'Bob': {'mean': 92.0, 'max': 95, 'min': 89}}\"",
          "concepts": [
            "statistics",
            "nested dict",
            "dict comprehension"
          ]
        },
        {
          "id": "dict_47",
          "title": "Cross-Join Two Dicts",
          "difficulty": 5,
          "description": "Write a function `cross_join` that creates all combinations of keys from two dicts with combined values.",
          "hints": [
            "Use nested loops to iterate both dicts",
            "Create key like (k1, k2) and value like {v1, v2}"
          ],
          "solution": "def cross_join(d1, d2):\n    return {(k1, k2): (v1, v2) for k1, v1 in d1.items() for k2, v2 in d2.items()}",
          "starter_code": "",
          "test_code": "assert 'cross_join' in dir(), \"Function 'cross_join' not defined. Did you write: def cross_join(...)?\"\n_r0 = cross_join({'a': 1, 'b': 2}, {'x': 10, 'y': 20})\nassert _r0 == {('a', 'x'): (1, 10), ('a', 'y'): (1, 20), ('b', 'x'): (2, 10), ('b', 'y'): (2, 20)}, \"Test 1: cross_join({'a': 1, 'b': 2}, {'x': 10, 'y': 20}) returned \" + str(repr(_r0)) + \", expected {('a', 'x'): (1, 10), ('a', 'y'): (1, 20), ('b', 'x'): (2, 10), ('b', 'y'): (2, 20)}\"",
          "concepts": [
            "nested iteration",
            "dict comprehension",
            "combinations"
          ]
        },
        {
          "id": "dict_48",
          "title": "Phone Book with Name Lookup",
          "difficulty": 5,
          "description": "Write functions `add_contact` and `find_by_name` for a phone book that handles duplicate first names.",
          "hints": [
            "Store {full_name: phone_number}",
            "For find_by_name, filter by first name and return all matches",
            "This is a 2-function exercise"
          ],
          "solution": "class PhoneBook:\n    def __init__(self):\n        self.contacts = {}\n    def add_contact(self, name, phone):\n        self.contacts[name] = phone\n    def find_by_name(self, first_name):\n        return {name: phone for name, phone in self.contacts.items() if name.split()[0] == first_name}",
          "starter_code": "",
          "test_code": "assert 'PhoneBook' in dir(), \"'PhoneBook' is not defined\"\nassert callable(PhoneBook), \"'PhoneBook' should be a function\"",
          "concepts": [
            "dict for data storage",
            "search patterns"
          ]
        },
        {
          "id": "dict_49",
          "title": "Shopping Cart Calculations",
          "difficulty": 5,
          "description": "Write a function `cart_total` that takes cart {item: (price, qty)} and returns {item_total, subtotal, tax, total}.",
          "hints": [
            "Calculate price * qty for each item",
            "Sum all items for subtotal",
            "Tax is subtotal * tax_rate (0.08)",
            "Total is subtotal + tax"
          ],
          "solution": "def cart_total(cart, tax_rate=0.08):\n    items_total = {item: price * qty for item, (price, qty) in cart.items()}\n    subtotal = sum(items_total.values())\n    tax = subtotal * tax_rate\n    return {'items': items_total, 'subtotal': subtotal, 'tax': tax, 'total': subtotal + tax}",
          "starter_code": "",
          "test_code": "assert 'cart_total' in dir(), \"Function 'cart_total' not defined. Did you write: def cart_total(...)?\"\n_r0 = cart_total({'apple': (1.5, 3), 'banana': (0.5, 2)})\nassert _r0 == {'items': {'apple': 4.5, 'banana': 1.0}, 'subtotal': 5.5, 'tax': 0.44, 'total': 5.94}, \"Test 1: cart_total({'apple': (1.5, 3), 'banana': (0.5, 2)}) returned \" + str(repr(_r0)) + \", expected {'items': {'apple': 4.5, 'banana': 1.0}, 'subtotal': 5.5, 'tax': 0.44, 'total': 5.94}\"",
          "concepts": [
            "complex calculations",
            "nested dict"
          ]
        },
        {
          "id": "dict_50",
          "title": "Build API Response Cache",
          "difficulty": 5,
          "description": "Write a class APICache that stores responses by endpoint+params, with TTL (time-to-live) tracking.",
          "hints": [
            "Store {endpoint: {params_str: (response, timestamp)}}",
            "is_expired checks if (now - timestamp) > ttl",
            "get returns response if not expired, else None"
          ],
          "solution": "import time\nclass APICache:\n    def __init__(self, ttl=60):\n        self.cache = {}\n        self.ttl = ttl\n    def set(self, endpoint, params, response):\n        if endpoint not in self.cache:\n            self.cache[endpoint] = {}\n        self.cache[endpoint][str(params)] = (response, time.time())\n    def get(self, endpoint, params):\n        if endpoint in self.cache and str(params) in self.cache[endpoint]:\n            response, timestamp = self.cache[endpoint][str(params)]\n            if time.time() - timestamp < self.ttl:\n                return response\n        return None",
          "starter_code": "",
          "test_code": "assert 'APICache' in dir(), \"'APICache' is not defined\"\nassert callable(APICache), \"'APICache' should be a function\"",
          "concepts": [
            "caching",
            "TTL",
            "class design",
            "timestamp"
          ]
        }
      ]
    },
    {
      "id": "fastapi_ex",
      "title": "FastAPI",
      "exercise_count": 50,
      "exercises": [
        {
          "id": "fapi_01",
          "title": "What is an API?",
          "difficulty": 1,
          "description": "Explain in 1-2 sentences what an API is. Provide a variable `api_explanation` containing your answer.",
          "hints": [
            "API stands for Application Programming Interface",
            "Think about how programs communicate with each other"
          ],
          "solution": "api_explanation = 'An API is a set of rules and protocols that allows different software applications to communicate and exchange data. It defines the methods and data formats that applications can use to request and provide information.'",
          "starter_code": "# Define api_explanation as a string\napi_explanation = ...",
          "test_code": "assert isinstance(api_explanation, str), 'api_explanation should be a string (text), got ' + str(type(api_explanation).__name__)\nassert len(api_explanation) > 0, \"api_explanation should not be empty\"",
          "concepts": [
            "API fundamentals"
          ]
        },
        {
          "id": "fapi_02",
          "title": "HTTP GET Request",
          "difficulty": 1,
          "description": "Create a dict called `get_request` that describes what a GET request does. Include 'method' and 'purpose' keys.",
          "hints": [
            "GET is used to retrieve data",
            "It's read-only and should not modify server state"
          ],
          "solution": "get_request = {\n    'method': 'GET',\n    'purpose': 'Retrieve data from the server',\n    'modifies_data': False,\n    'has_request_body': False\n}",
          "starter_code": "get_request = {...}",
          "test_code": "assert isinstance(get_request, dict), 'get_request should be a dictionary, got ' + str(type(get_request).__name__)\nassert len(get_request) > 0, \"get_request should not be empty\"",
          "concepts": [
            "HTTP GET"
          ]
        },
        {
          "id": "fapi_03",
          "title": "HTTP POST Request",
          "difficulty": 1,
          "description": "Create a dict called `post_request` that describes what a POST request does. Include 'method', 'purpose', and 'has_body' keys.",
          "hints": [
            "POST is used to create new data",
            "POST requests typically include a request body with data"
          ],
          "solution": "post_request = {\n    'method': 'POST',\n    'purpose': 'Create new data on the server',\n    'has_body': True,\n    'modifies_data': True\n}",
          "starter_code": "post_request = {...}",
          "test_code": "assert isinstance(post_request, dict), 'post_request should be a dictionary, got ' + str(type(post_request).__name__)\nassert len(post_request) > 0, \"post_request should not be empty\"",
          "concepts": [
            "HTTP POST"
          ]
        },
        {
          "id": "fapi_04",
          "title": "HTTP PUT Request",
          "difficulty": 1,
          "description": "Create a dict called `put_request` describing PUT. Include 'method' and 'action' keys.",
          "hints": [
            "PUT is used to replace/update existing data",
            "It replaces the entire resource"
          ],
          "solution": "put_request = {\n    'method': 'PUT',\n    'action': 'Update or replace existing data',\n    'requires_id': True\n}",
          "starter_code": "put_request = {...}",
          "test_code": "assert isinstance(put_request, dict), 'put_request should be a dictionary, got ' + str(type(put_request).__name__)\nassert len(put_request) > 0, \"put_request should not be empty\"",
          "concepts": [
            "HTTP PUT"
          ]
        },
        {
          "id": "fapi_05",
          "title": "HTTP DELETE Request",
          "difficulty": 1,
          "description": "Create a dict called `delete_request` describing DELETE. Include 'method' and 'action' keys.",
          "hints": [
            "DELETE is used to remove data",
            "It removes a resource from the server"
          ],
          "solution": "delete_request = {\n    'method': 'DELETE',\n    'action': 'Remove data from the server',\n    'requires_id': True\n}",
          "starter_code": "delete_request = {...}",
          "test_code": "assert isinstance(delete_request, dict), 'delete_request should be a dictionary, got ' + str(type(delete_request).__name__)\nassert len(delete_request) > 0, \"delete_request should not be empty\"",
          "concepts": [
            "HTTP DELETE"
          ]
        },
        {
          "id": "fapi_06",
          "title": "REST API Endpoints",
          "difficulty": 1,
          "description": "Create a dict called `rest_endpoints` mapping HTTP methods to example endpoints for a TODO app.",
          "hints": [
            "Map GET, POST, PUT, DELETE to their typical paths",
            "Use /todos as the base path"
          ],
          "solution": "rest_endpoints = {\n    'GET': '/todos',\n    'POST': '/todos',\n    'PUT': '/todos/{id}',\n    'DELETE': '/todos/{id}'\n}",
          "starter_code": "rest_endpoints = {...}",
          "test_code": "assert isinstance(rest_endpoints, dict), 'rest_endpoints should be a dictionary, got ' + str(type(rest_endpoints).__name__)\nassert len(rest_endpoints) > 0, \"rest_endpoints should not be empty\"",
          "concepts": [
            "REST principles"
          ]
        },
        {
          "id": "fapi_07",
          "title": "HTTP Status Codes",
          "difficulty": 1,
          "description": "Create a dict called `status_codes` with at least 5 common HTTP status codes and their meanings.",
          "hints": [
            "Include 200, 201, 400, 404, 500",
            "200 = OK, 201 = Created, 400 = Bad Request, 404 = Not Found, 500 = Server Error"
          ],
          "solution": "status_codes = {\n    200: 'OK',\n    201: 'Created',\n    204: 'No Content',\n    400: 'Bad Request',\n    401: 'Unauthorized',\n    404: 'Not Found',\n    500: 'Internal Server Error'\n}",
          "starter_code": "status_codes = {...}",
          "test_code": "assert isinstance(status_codes, dict), 'status_codes should be a dictionary, got ' + str(type(status_codes).__name__)\nassert len(status_codes) > 0, \"status_codes should not be empty\"",
          "concepts": [
            "HTTP status codes"
          ]
        },
        {
          "id": "fapi_08",
          "title": "Pydantic BaseModel Basics",
          "difficulty": 1,
          "description": "Create a Pydantic model called `Item` with fields: name (str), price (float), description (str).",
          "hints": [
            "Import BaseModel from pydantic",
            "Use type hints for each field"
          ],
          "solution": "from pydantic import BaseModel\n\nclass Item(BaseModel):\n    name: str\n    price: float\n    description: str",
          "starter_code": "from pydantic import BaseModel\n\nclass Item(BaseModel):\n    ...",
          "test_code": "assert 'BaseModel' in dir(), \"'BaseModel' is not defined\"\nassert callable(BaseModel), \"'BaseModel' should be a function\"\nassert 'Item' in dir(), \"'Item' is not defined\"\nassert callable(Item), \"'Item' should be a function\"",
          "concepts": [
            "Pydantic BaseModel",
            "Type hints"
          ]
        },
        {
          "id": "fapi_09",
          "title": "Pydantic Model Instantiation",
          "difficulty": 1,
          "description": "Create an Item instance with name='Widget', price=19.99, description='A useful widget'.",
          "hints": [
            "Use the Item class from previous exercise",
            "Pass values as keyword arguments"
          ],
          "solution": "from pydantic import BaseModel\n\nclass Item(BaseModel):\n    name: str\n    price: float\n    description: str\n\nitem = Item(\n    name='Widget',\n    price=19.99,\n    description='A useful widget'\n)",
          "starter_code": "# From previous exercise\nfrom pydantic import BaseModel\n\nclass Item(BaseModel):\n    name: str\n    price: float\n    description: str\n\n# Create instance\nitem = ...",
          "test_code": "assert 'BaseModel' in dir(), \"'BaseModel' is not defined\"\nassert callable(BaseModel), \"'BaseModel' should be a function\"\nassert 'Item' in dir(), \"'Item' is not defined\"\nassert callable(Item), \"'Item' should be a function\"",
          "concepts": [
            "Pydantic instantiation"
          ]
        },
        {
          "id": "fapi_10",
          "title": "Pydantic Model to Dict",
          "difficulty": 1,
          "description": "Convert a Pydantic Item model to a Python dict using model_dump().",
          "hints": [
            "Call model_dump() on the instance",
            "It returns a regular Python dict"
          ],
          "solution": "from pydantic import BaseModel\n\nclass Item(BaseModel):\n    name: str\n    price: float\n    description: str\n\nitem = Item(name='Gadget', price=29.99, description='A cool gadget')\nitem_dict = item.model_dump()",
          "starter_code": "# ... Item class from before\nitem_dict = ...",
          "test_code": "assert 'BaseModel' in dir(), \"'BaseModel' is not defined\"\nassert callable(BaseModel), \"'BaseModel' should be a function\"\nassert 'Item' in dir(), \"'Item' is not defined\"\nassert callable(Item), \"'Item' should be a function\"\nassert isinstance(item_dict, dict), 'item_dict should be a dictionary, got ' + str(type(item_dict).__name__)\nassert len(item_dict) > 0, \"item_dict should not be empty\"",
          "concepts": [
            "Pydantic serialization"
          ]
        },
        {
          "id": "fapi_11",
          "title": "Field with Constraints",
          "difficulty": 2,
          "description": "Create a Pydantic model `Product` with: name (str, min 1 char), price (float, gt=0).",
          "hints": [
            "Import Field from pydantic",
            "Use min_length for strings, gt for greater-than"
          ],
          "solution": "from pydantic import BaseModel, Field\n\nclass Product(BaseModel):\n    name: str = Field(..., min_length=1)\n    price: float = Field(..., gt=0)",
          "starter_code": "from pydantic import BaseModel, Field\n\nclass Product(BaseModel):\n    ...",
          "test_code": "assert 'BaseModel' in dir(), \"'BaseModel' is not defined\"\nassert callable(BaseModel), \"'BaseModel' should be a function\"\nassert 'Field' in dir(), \"'Field' is not defined\"\nassert callable(Field), \"'Field' should be a function\"\nassert 'Product' in dir(), \"'Product' is not defined\"\nassert callable(Product), \"'Product' should be a function\"",
          "concepts": [
            "Field constraints",
            "Validation"
          ]
        },
        {
          "id": "fapi_12",
          "title": "Email Validation",
          "difficulty": 2,
          "description": "Create a Pydantic `User` model with email field that validates email format.",
          "hints": [
            "Use EmailStr from pydantic",
            "Or use Field with pattern validation"
          ],
          "solution": "from pydantic import BaseModel, EmailStr\n\nclass User(BaseModel):\n    name: str\n    email: EmailStr",
          "starter_code": "from pydantic import BaseModel\n\nclass User(BaseModel):\n    ...",
          "test_code": "assert 'BaseModel' in dir(), \"'BaseModel' is not defined\"\nassert callable(BaseModel), \"'BaseModel' should be a function\"\nassert 'EmailStr' in dir(), \"'EmailStr' is not defined\"\nassert callable(EmailStr), \"'EmailStr' should be a function\"\nassert 'User' in dir(), \"'User' is not defined\"\nassert callable(User), \"'User' should be a function\"",
          "concepts": [
            "Email validation",
            "Pydantic validators"
          ]
        },
        {
          "id": "fapi_13",
          "title": "Optional Fields",
          "difficulty": 2,
          "description": "Create a Pydantic `Article` with: title (str), content (str), tags (optional list of str).",
          "hints": [
            "Use Optional[list[str]] or list[str] | None",
            "Optional fields should have default=None"
          ],
          "solution": "from pydantic import BaseModel\nfrom typing import Optional\n\nclass Article(BaseModel):\n    title: str\n    content: str\n    tags: Optional[list[str]] = None",
          "starter_code": "from pydantic import BaseModel\nfrom typing import Optional\n\nclass Article(BaseModel):\n    ...",
          "test_code": "assert 'BaseModel' in dir(), \"'BaseModel' is not defined\"\nassert callable(BaseModel), \"'BaseModel' should be a function\"\nassert 'Optional' in dir(), \"'Optional' is not defined\"\nassert callable(Optional), \"'Optional' should be a function\"\nassert 'Article' in dir(), \"'Article' is not defined\"\nassert callable(Article), \"'Article' should be a function\"",
          "concepts": [
            "Optional fields",
            "Default values"
          ]
        },
        {
          "id": "fapi_14",
          "title": "Nested Pydantic Models",
          "difficulty": 2,
          "description": "Create two models: `Address` (street, city, zip) and `Person` (name, age, address).",
          "hints": [
            "Person.address should be of type Address",
            "Nesting enables complex data structures"
          ],
          "solution": "from pydantic import BaseModel\n\nclass Address(BaseModel):\n    street: str\n    city: str\n    zip: str\n\nclass Person(BaseModel):\n    name: str\n    age: int\n    address: Address",
          "starter_code": "from pydantic import BaseModel\n\nclass Address(BaseModel):\n    ...\n\nclass Person(BaseModel):\n    ...",
          "test_code": "assert 'BaseModel' in dir(), \"'BaseModel' is not defined\"\nassert callable(BaseModel), \"'BaseModel' should be a function\"\nassert 'Address' in dir(), \"'Address' is not defined\"\nassert callable(Address), \"'Address' should be a function\"\nassert 'Person' in dir(), \"'Person' is not defined\"\nassert callable(Person), \"'Person' should be a function\"",
          "concepts": [
            "Nested models",
            "Complex types"
          ]
        },
        {
          "id": "fapi_15",
          "title": "Default Values in Pydantic",
          "difficulty": 2,
          "description": "Create a `Config` model with: host (str, default='localhost'), port (int, default=8000).",
          "hints": [
            "Use default parameter in field definition",
            "Fields with defaults are optional in instantiation"
          ],
          "solution": "from pydantic import BaseModel\n\nclass Config(BaseModel):\n    host: str = 'localhost'\n    port: int = 8000",
          "starter_code": "from pydantic import BaseModel\n\nclass Config(BaseModel):\n    ...",
          "test_code": "assert 'BaseModel' in dir(), \"'BaseModel' is not defined\"\nassert callable(BaseModel), \"'BaseModel' should be a function\"\nassert 'Config' in dir(), \"'Config' is not defined\"\nassert callable(Config), \"'Config' should be a function\"",
          "concepts": [
            "Default values"
          ]
        },
        {
          "id": "fapi_16",
          "title": "Custom Validators",
          "difficulty": 2,
          "description": "Create a `Password` model with password field that validates length >= 8.",
          "hints": [
            "Use field_validator from pydantic",
            "The validator should check string length"
          ],
          "solution": "from pydantic import BaseModel, field_validator\n\nclass Password(BaseModel):\n    password: str\n\n    @field_validator('password')\n    def validate_password(cls, v):\n        if len(v) < 8:\n            raise ValueError('Password must be at least 8 characters')\n        return v",
          "starter_code": "from pydantic import BaseModel, field_validator\n\nclass Password(BaseModel):\n    ...",
          "test_code": "assert 'BaseModel' in dir(), \"'BaseModel' is not defined\"\nassert callable(BaseModel), \"'BaseModel' should be a function\"\nassert 'field_validator' in dir(), \"'field_validator' is not defined\"\nassert callable(field_validator), \"'field_validator' should be a function\"\nassert 'Password' in dir(), \"'Password' is not defined\"\nassert callable(Password), \"'Password' should be a function\"",
          "concepts": [
            "Custom validators",
            "Field validation"
          ]
        },
        {
          "id": "fapi_17",
          "title": "List Validation",
          "difficulty": 2,
          "description": "Create a `TagList` model with tags field: list of strings, min 1 item, each string min 1 char.",
          "hints": [
            "Use Field with min_length for the list",
            "Each string in the list also needs validation"
          ],
          "solution": "from pydantic import BaseModel, Field\n\nclass TagList(BaseModel):\n    tags: list[str] = Field(..., min_length=1)",
          "starter_code": "from pydantic import BaseModel, Field\n\nclass TagList(BaseModel):\n    ...",
          "test_code": "assert 'BaseModel' in dir(), \"'BaseModel' is not defined\"\nassert callable(BaseModel), \"'BaseModel' should be a function\"\nassert 'Field' in dir(), \"'Field' is not defined\"\nassert callable(Field), \"'Field' should be a function\"\nassert 'TagList' in dir(), \"'TagList' is not defined\"\nassert callable(TagList), \"'TagList' should be a function\"",
          "concepts": [
            "List validation",
            "Constraints"
          ]
        },
        {
          "id": "fapi_18",
          "title": "Enum Fields in Pydantic",
          "difficulty": 2,
          "description": "Create a `Task` model with status field: Enum('pending', 'in_progress', 'completed').",
          "hints": [
            "Import Enum from enum module",
            "Define an Enum class for status values"
          ],
          "solution": "from pydantic import BaseModel\nfrom enum import Enum\n\nclass TaskStatus(str, Enum):\n    PENDING = 'pending'\n    IN_PROGRESS = 'in_progress'\n    COMPLETED = 'completed'\n\nclass Task(BaseModel):\n    title: str\n    status: TaskStatus",
          "starter_code": "from pydantic import BaseModel\nfrom enum import Enum\n\nclass Task(BaseModel):\n    ...",
          "test_code": "assert 'BaseModel' in dir(), \"'BaseModel' is not defined\"\nassert callable(BaseModel), \"'BaseModel' should be a function\"\nassert 'Enum' in dir(), \"'Enum' is not defined\"\nassert callable(Enum), \"'Enum' should be a function\"\nassert 'TaskStatus' in dir(), \"'TaskStatus' is not defined\"\nassert callable(TaskStatus), \"'TaskStatus' should be a function\"\nassert 'Task' in dir(), \"'Task' is not defined\"\nassert callable(Task), \"'Task' should be a function\"",
          "concepts": [
            "Enum types",
            "Type safety"
          ]
        },
        {
          "id": "fapi_19",
          "title": "Response Model Exclusion",
          "difficulty": 2,
          "description": "Create a `User` model with password field. Write a function that returns user data excluding password.",
          "hints": [
            "Use model_dump(exclude={'password'})",
            "This prevents sensitive data exposure"
          ],
          "solution": "from pydantic import BaseModel\n\nclass User(BaseModel):\n    username: str\n    password: str\n    email: str\n\ndef get_user_public(user: User) -> dict:\n    return user.model_dump(exclude={'password'})",
          "starter_code": "from pydantic import BaseModel\n\nclass User(BaseModel):\n    ...\n\ndef get_user_public(user: User) -> dict:\n    ...",
          "test_code": "assert 'BaseModel' in dir(), \"'BaseModel' is not defined\"\nassert callable(BaseModel), \"'BaseModel' should be a function\"\nassert 'User' in dir(), \"'User' is not defined\"\nassert callable(User), \"'User' should be a function\"\nassert 'get_user_public' in dir(), \"'get_user_public' is not defined\"\nassert callable(get_user_public), \"'get_user_public' should be a function\"",
          "concepts": [
            "Security",
            "Field exclusion"
          ]
        },
        {
          "id": "fapi_20",
          "title": "Pagination Helper Function",
          "difficulty": 2,
          "description": "Write a function paginate(items: list, page: int, per_page: int) that returns paginated slice.",
          "hints": [
            "Calculate skip = (page - 1) * per_page",
            "Return items[skip:skip+per_page]"
          ],
          "solution": "def paginate(items: list, page: int, per_page: int) -> list:\n    skip = (page - 1) * per_page\n    return items[skip:skip + per_page]",
          "starter_code": "def paginate(items: list, page: int, per_page: int) -> list:\n    ...",
          "test_code": "assert 'paginate' in dir(), \"Function 'paginate' not defined. Did you write: def paginate(...)?\"\n_r0 = paginate([1, 2, 3, 4, 5], 1, 2)\nassert _r0 == [1, 2], 'Test 1: paginate([1, 2, 3, 4, 5], 1, 2) returned ' + str(repr(_r0)) + ', expected [1, 2]'\n_r1 = paginate([1, 2, 3, 4, 5], 2, 2)\nassert _r1 == [3, 4], 'Test 2: paginate([1, 2, 3, 4, 5], 2, 2) returned ' + str(repr(_r1)) + ', expected [3, 4]'\n_r2 = paginate([1, 2, 3, 4, 5], 3, 2)\nassert _r2 == [5], 'Test 3: paginate([1, 2, 3, 4, 5], 3, 2) returned ' + str(repr(_r2)) + ', expected [5]'",
          "concepts": [
            "Pagination",
            "List slicing"
          ]
        },
        {
          "id": "fapi_21",
          "title": "Path Parameter Handler",
          "difficulty": 3,
          "description": "Write a function get_user(user_id: int, users: dict) that retrieves a user by ID from a dict.",
          "hints": [
            "users is a dict with user_id as key",
            "Return the user dict or None if not found"
          ],
          "solution": "def get_user(user_id: int, users: dict) -> dict | None:\n    return users.get(user_id)",
          "starter_code": "def get_user(user_id: int, users: dict) -> dict | None:\n    ...",
          "test_code": "assert 'get_user' in dir(), \"Function 'get_user' not defined. Did you write: def get_user(...)?\"\n_r0 = get_user(1, {1: {'id': 1, 'name': 'Alice'}, 2: {'id': 2, 'name': 'Bob'}})\nassert _r0 == {'id': 1, 'name': 'Alice'}, \"Test 1: get_user(1, {1: {'id': 1, 'name': 'Alice'}, 2: {'id': 2, 'name': 'Bob'}}) returned \" + str(repr(_r0)) + \", expected {'id': 1, 'name': 'Alice'}\"\n_r1 = get_user(3, {1: {'id': 1, 'name': 'Alice'}})\nassert _r1 == None, \"Test 2: get_user(3, {1: {'id': 1, 'name': 'Alice'}}) returned \" + str(repr(_r1)) + ', expected None'",
          "concepts": [
            "Path parameters",
            "Lookups"
          ]
        },
        {
          "id": "fapi_22",
          "title": "Query Parameter Handler",
          "difficulty": 3,
          "description": "Write a function filter_items(items: list, category: str) that filters by category field.",
          "hints": [
            "items is a list of dicts with 'category' key",
            "Return only matching items"
          ],
          "solution": "def filter_items(items: list, category: str) -> list:\n    return [item for item in items if item.get('category') == category]",
          "starter_code": "def filter_items(items: list, category: str) -> list:\n    ...",
          "test_code": "assert 'filter_items' in dir(), \"Function 'filter_items' not defined. Did you write: def filter_items(...)?\"\n_r0 = filter_items([{'id': 1, 'category': 'A'}, {'id': 2, 'category': 'B'}], 'A')\nassert _r0 == [{'id': 1, 'category': 'A'}], \"Test 1: filter_items([{'id': 1, 'category': 'A'}, {'id': 2, 'category': 'B'}], 'A') returned \" + str(repr(_r0)) + \", expected [{'id': 1, 'category': 'A'}]\"\n_r1 = filter_items([{'id': 1, 'category': 'A'}], 'Z')\nassert _r1 == [], \"Test 2: filter_items([{'id': 1, 'category': 'A'}], 'Z') returned \" + str(repr(_r1)) + ', expected []'",
          "concepts": [
            "Query parameters",
            "Filtering"
          ]
        },
        {
          "id": "fapi_23",
          "title": "Create Handler (POST)",
          "difficulty": 3,
          "description": "Write a function create_item(db: dict, next_id: int, name: str, price: float) that adds item to db.",
          "hints": [
            "Generate new ID from next_id",
            "Add to db dict and return the created item with ID"
          ],
          "solution": "def create_item(db: dict, next_id: int, name: str, price: float) -> dict:\n    item = {'id': next_id, 'name': name, 'price': price}\n    db[next_id] = item\n    return item",
          "starter_code": "def create_item(db: dict, next_id: int, name: str, price: float) -> dict:\n    ...",
          "test_code": "assert 'create_item' in dir(), \"Function 'create_item' not defined. Did you write: def create_item(...)?\"\n_r0 = create_item({}, 1, 'Widget', 9.99)\nassert _r0 == {'id': 1, 'name': 'Widget', 'price': 9.99}, \"Test 1: create_item({}, 1, 'Widget', 9.99) returned \" + str(repr(_r0)) + \", expected {'id': 1, 'name': 'Widget', 'price': 9.99}\"",
          "concepts": [
            "POST handlers",
            "CRUD Create"
          ]
        },
        {
          "id": "fapi_24",
          "title": "Update Handler (PUT)",
          "difficulty": 3,
          "description": "Write a function update_item(db: dict, item_id: int, name: str, price: float) that updates an item.",
          "hints": [
            "Find item in db by item_id",
            "Update fields and return updated item"
          ],
          "solution": "def update_item(db: dict, item_id: int, name: str, price: float) -> dict | None:\n    if item_id not in db:\n        return None\n    db[item_id].update({'name': name, 'price': price})\n    return db[item_id]",
          "starter_code": "def update_item(db: dict, item_id: int, name: str, price: float) -> dict | None:\n    ...",
          "test_code": "assert 'update_item' in dir(), \"Function 'update_item' not defined. Did you write: def update_item(...)?\"\n_r0 = update_item({1: {'id': 1, 'name': 'A', 'price': 5}}, 1, 'B', 10)\nassert _r0 == {'id': 1, 'name': 'B', 'price': 10}, \"Test 1: update_item({1: {'id': 1, 'name': 'A', 'price': 5}}, 1, 'B', 10) returned \" + str(repr(_r0)) + \", expected {'id': 1, 'name': 'B', 'price': 10}\"\n_r1 = update_item({}, 1, 'B', 10)\nassert _r1 == None, \"Test 2: update_item({}, 1, 'B', 10) returned \" + str(repr(_r1)) + ', expected None'",
          "concepts": [
            "PUT handlers",
            "CRUD Update"
          ]
        },
        {
          "id": "fapi_25",
          "title": "Delete Handler (DELETE)",
          "difficulty": 3,
          "description": "Write a function delete_item(db: dict, item_id: int) that removes item and returns True if deleted.",
          "hints": [
            "Check if item_id exists in db",
            "Delete it and return True, or return False if not found"
          ],
          "solution": "def delete_item(db: dict, item_id: int) -> bool:\n    if item_id in db:\n        del db[item_id]\n        return True\n    return False",
          "starter_code": "def delete_item(db: dict, item_id: int) -> bool:\n    ...",
          "test_code": "assert 'delete_item' in dir(), \"Function 'delete_item' not defined. Did you write: def delete_item(...)?\"\n_r0 = delete_item({1: {'id': 1}}, 1)\nassert _r0 == True, \"Test 1: delete_item({1: {'id': 1}}, 1) returned \" + str(repr(_r0)) + ', expected True'\n_r1 = delete_item({}, 1)\nassert _r1 == False, 'Test 2: delete_item({}, 1) returned ' + str(repr(_r1)) + ', expected False'",
          "concepts": [
            "DELETE handlers",
            "CRUD Delete"
          ]
        },
        {
          "id": "fapi_26",
          "title": "CRUD Operations Dict",
          "difficulty": 3,
          "description": "Implement a simple CRUD operations dict with 4 functions: create, read, update, delete.",
          "hints": [
            "Each function takes db dict as first arg",
            "Return appropriate values per operation"
          ],
          "solution": "db = {}\nnext_id = 1\n\ndef create(name, price):\n    global next_id\n    item = {'id': next_id, 'name': name, 'price': price}\n    db[next_id] = item\n    next_id += 1\n    return item\n\ndef read(item_id):\n    return db.get(item_id)\n\ndef update(item_id, name, price):\n    if item_id not in db:\n        return None\n    db[item_id].update({'name': name, 'price': price})\n    return db[item_id]\n\ndef delete(item_id):\n    if item_id in db:\n        del db[item_id]\n        return True\n    return False",
          "starter_code": "db = {}\nnext_id = 1\n\ndef create(name, price):\n    ...\n\ndef read(item_id):\n    ...\n\ndef update(item_id, name, price):\n    ...\n\ndef delete(item_id):\n    ...",
          "test_code": "assert isinstance(db, dict), 'db should be a dictionary, got ' + str(type(db).__name__)\nassert isinstance(next_id, (int, float)), 'next_id should be a number, got ' + str(type(next_id).__name__)\nassert 'create' in dir(), \"'create' is not defined\"\nassert callable(create), \"'create' should be a function\"\nassert 'read' in dir(), \"'read' is not defined\"\nassert callable(read), \"'read' should be a function\"\nassert 'update' in dir(), \"'update' is not defined\"\nassert callable(update), \"'update' should be a function\"\nassert 'delete' in dir(), \"'delete' is not defined\"\nassert callable(delete), \"'delete' should be a function\"",
          "concepts": [
            "CRUD operations",
            "In-memory database"
          ]
        },
        {
          "id": "fapi_27",
          "title": "Request Body Validation",
          "difficulty": 3,
          "description": "Create a Pydantic model for a POST request body: CreateItem with name, price, description.",
          "hints": [
            "Use BaseModel with type hints",
            "Add validation: name min length 1, price > 0"
          ],
          "solution": "from pydantic import BaseModel, Field\n\nclass CreateItem(BaseModel):\n    name: str = Field(..., min_length=1)\n    price: float = Field(..., gt=0)\n    description: str = Field(..., min_length=1)",
          "starter_code": "from pydantic import BaseModel, Field\n\nclass CreateItem(BaseModel):\n    ...",
          "test_code": "assert 'BaseModel' in dir(), \"'BaseModel' is not defined\"\nassert callable(BaseModel), \"'BaseModel' should be a function\"\nassert 'Field' in dir(), \"'Field' is not defined\"\nassert callable(Field), \"'Field' should be a function\"\nassert 'CreateItem' in dir(), \"'CreateItem' is not defined\"\nassert callable(CreateItem), \"'CreateItem' should be a function\"",
          "concepts": [
            "Request bodies",
            "Validation"
          ]
        },
        {
          "id": "fapi_28",
          "title": "Response Model",
          "difficulty": 3,
          "description": "Create two models: ItemRequest (without id) and ItemResponse (with id). Show the pattern.",
          "hints": [
            "ItemResponse includes the id field",
            "ItemRequest is for input, ItemResponse for output"
          ],
          "solution": "from pydantic import BaseModel\n\nclass ItemRequest(BaseModel):\n    name: str\n    price: float\n\nclass ItemResponse(BaseModel):\n    id: int\n    name: str\n    price: float",
          "starter_code": "from pydantic import BaseModel\n\nclass ItemRequest(BaseModel):\n    ...\n\nclass ItemResponse(BaseModel):\n    ...",
          "test_code": "assert 'BaseModel' in dir(), \"'BaseModel' is not defined\"\nassert callable(BaseModel), \"'BaseModel' should be a function\"\nassert 'ItemRequest' in dir(), \"'ItemRequest' is not defined\"\nassert callable(ItemRequest), \"'ItemRequest' should be a function\"\nassert 'ItemResponse' in dir(), \"'ItemResponse' is not defined\"\nassert callable(ItemResponse), \"'ItemResponse' should be a function\"",
          "concepts": [
            "Request/response models"
          ]
        },
        {
          "id": "fapi_29",
          "title": "Error Handler - Not Found",
          "difficulty": 3,
          "description": "Write a function that raises an HTTPException for 404 Not Found.",
          "hints": [
            "Import HTTPException from fastapi",
            "Raise with status_code=404 and detail message"
          ],
          "solution": "from fastapi import HTTPException\n\ndef get_item_or_404(item_id: int, db: dict):\n    if item_id not in db:\n        raise HTTPException(status_code=404, detail='Item not found')\n    return db[item_id]",
          "starter_code": "from fastapi import HTTPException\n\ndef get_item_or_404(item_id: int, db: dict):\n    ...",
          "test_code": "assert 'get_item_or_404' in dir(), \"Function 'get_item_or_404' not defined. Did you write: def get_item_or_404(...)?\"\n_r0 = get_item_or_404(1, {1: {'id': 1, 'name': 'A'}})\nassert _r0 == {'id': 1, 'name': 'A'}, \"Test 1: get_item_or_404(1, {1: {'id': 1, 'name': 'A'}}) returned \" + str(repr(_r0)) + \", expected {'id': 1, 'name': 'A'}\"",
          "concepts": [
            "Error handling",
            "HTTP exceptions"
          ]
        },
        {
          "id": "fapi_30",
          "title": "Dependency Injection Pattern",
          "difficulty": 3,
          "description": "Write a function get_db() that returns a sample db dict. Show how it could be a dependency.",
          "hints": [
            "Dependency injection is a pattern of passing dependencies as parameters",
            "In FastAPI, you'd use Depends() to inject this at runtime"
          ],
          "solution": "def get_db() -> dict:\n    return {\n        1: {'id': 1, 'name': 'Item A', 'price': 9.99},\n        2: {'id': 2, 'name': 'Item B', 'price': 19.99}\n    }",
          "starter_code": "def get_db() -> dict:\n    ...",
          "test_code": "assert 'get_db' in dir(), \"Function 'get_db' not defined. Did you write: def get_db(...)?\"\n_r0 = get_db()\nassert _r0 == {1: {'id': 1, 'name': 'Item A', 'price': 9.99}, 2: {'id': 2, 'name': 'Item B', 'price': 19.99}}, 'Test 1: get_db() returned ' + str(repr(_r0)) + \", expected {1: {'id': 1, 'name': 'Item A', 'price': 9.99}, 2: {'id': 2, 'name': 'Item B', 'price': 19.99}}\"",
          "concepts": [
            "Dependency injection"
          ]
        },
        {
          "id": "fapi_31",
          "title": "API Key Validation",
          "difficulty": 3,
          "description": "Write a function verify_api_key(api_key: str) that validates the key. Valid key is 'secret-key-123'.",
          "hints": [
            "Compare api_key with expected value",
            "Raise HTTPException if invalid"
          ],
          "solution": "from fastapi import HTTPException\n\ndef verify_api_key(api_key: str) -> bool:\n    if api_key != 'secret-key-123':\n        raise HTTPException(status_code=401, detail='Invalid API key')\n    return True",
          "starter_code": "from fastapi import HTTPException\n\ndef verify_api_key(api_key: str) -> bool:\n    ...",
          "test_code": "assert 'verify_api_key' in dir(), \"Function 'verify_api_key' not defined. Did you write: def verify_api_key(...)?\"\n_r0 = verify_api_key('secret-key-123')\nassert _r0 == True, \"Test 1: verify_api_key('secret-key-123') returned \" + str(repr(_r0)) + ', expected True'",
          "concepts": [
            "API key auth",
            "Validation"
          ]
        },
        {
          "id": "fapi_32",
          "title": "Sorting Handler",
          "difficulty": 3,
          "description": "Write a function sort_items(items: list, sort_by: str) that sorts by 'name' or 'price' field.",
          "hints": [
            "Use sorted() with a key function",
            "sort_by parameter indicates which field to sort by"
          ],
          "solution": "def sort_items(items: list, sort_by: str) -> list:\n    if sort_by not in ['name', 'price']:\n        return items\n    return sorted(items, key=lambda x: x.get(sort_by, 0))",
          "starter_code": "def sort_items(items: list, sort_by: str) -> list:\n    ...",
          "test_code": "assert 'sort_items' in dir(), \"Function 'sort_items' not defined. Did you write: def sort_items(...)?\"\n_r0 = sort_items([{'name': 'B', 'price': 10}, {'name': 'A', 'price': 5}], 'name')\nassert _r0 == [{'name': 'A', 'price': 5}, {'name': 'B', 'price': 10}], \"Test 1: sort_items([{'name': 'B', 'price': 10}, {'name': 'A', 'price': 5}], 'name') returned \" + str(repr(_r0)) + \", expected [{'name': 'A', 'price': 5}, {'name': 'B', 'price': 10}]\"\n_r1 = sort_items([{'name': 'B', 'price': 10}, {'name': 'A', 'price': 5}], 'price')\nassert _r1 == [{'name': 'A', 'price': 5}, {'name': 'B', 'price': 10}], \"Test 2: sort_items([{'name': 'B', 'price': 10}, {'name': 'A', 'price': 5}], 'price') returned \" + str(repr(_r1)) + \", expected [{'name': 'A', 'price': 5}, {'name': 'B', 'price': 10}]\"",
          "concepts": [
            "Sorting",
            "Query parameters"
          ]
        },
        {
          "id": "fapi_33",
          "title": "Pagination with Offset",
          "difficulty": 3,
          "description": "Write paginate_with_offset(items: list, skip: int, limit: int) using skip/limit pattern.",
          "hints": [
            "skip = number of items to skip from start",
            "limit = max number of items to return"
          ],
          "solution": "def paginate_with_offset(items: list, skip: int, limit: int) -> list:\n    return items[skip:skip + limit]",
          "starter_code": "def paginate_with_offset(items: list, skip: int, limit: int) -> list:\n    ...",
          "test_code": "assert 'paginate_with_offset' in dir(), \"Function 'paginate_with_offset' not defined. Did you write: def paginate_with_offset(...)?\"\n_r0 = paginate_with_offset([1, 2, 3, 4, 5], 0, 2)\nassert _r0 == [1, 2], 'Test 1: paginate_with_offset([1, 2, 3, 4, 5], 0, 2) returned ' + str(repr(_r0)) + ', expected [1, 2]'\n_r1 = paginate_with_offset([1, 2, 3, 4, 5], 2, 2)\nassert _r1 == [3, 4], 'Test 2: paginate_with_offset([1, 2, 3, 4, 5], 2, 2) returned ' + str(repr(_r1)) + ', expected [3, 4]'",
          "concepts": [
            "Pagination",
            "Skip/limit pattern"
          ]
        },
        {
          "id": "fapi_34",
          "title": "Timestamp Tracking",
          "difficulty": 3,
          "description": "Create a Pydantic model for a blog Post with created_at and updated_at timestamp fields.",
          "hints": [
            "Use datetime from typing/datetime module",
            "Optional or use default_factory for auto-generation"
          ],
          "solution": "from pydantic import BaseModel\nfrom datetime import datetime\n\nclass Post(BaseModel):\n    title: str\n    content: str\n    created_at: datetime\n    updated_at: datetime",
          "starter_code": "from pydantic import BaseModel\nfrom datetime import datetime\n\nclass Post(BaseModel):\n    ...",
          "test_code": "assert 'BaseModel' in dir(), \"'BaseModel' is not defined\"\nassert callable(BaseModel), \"'BaseModel' should be a function\"\nassert 'datetime' in dir(), \"'datetime' is not defined\"\nassert callable(datetime), \"'datetime' should be a function\"\nassert 'Post' in dir(), \"'Post' is not defined\"\nassert callable(Post), \"'Post' should be a function\"",
          "concepts": [
            "Timestamps",
            "Datetime handling"
          ]
        },
        {
          "id": "fapi_35",
          "title": "Search Query Handler",
          "difficulty": 3,
          "description": "Write a function search_items(items: list, q: str) that searches name field (case-insensitive).",
          "hints": [
            "Use lower() for case-insensitive comparison",
            "Check if search term is in the name"
          ],
          "solution": "def search_items(items: list, q: str) -> list:\n    return [item for item in items if q.lower() in item.get('name', '').lower()]",
          "starter_code": "def search_items(items: list, q: str) -> list:\n    ...",
          "test_code": "assert 'search_items' in dir(), \"Function 'search_items' not defined. Did you write: def search_items(...)?\"\n_r0 = search_items([{'name': 'Apple'}, {'name': 'Banana'}], 'app')\nassert _r0 == [{'name': 'Apple'}], \"Test 1: search_items([{'name': 'Apple'}, {'name': 'Banana'}], 'app') returned \" + str(repr(_r0)) + \", expected [{'name': 'Apple'}]\"\n_r1 = search_items([{'name': 'Apple'}, {'name': 'Apricot'}], 'ap')\nassert _r1 == [{'name': 'Apple'}, {'name': 'Apricot'}], \"Test 2: search_items([{'name': 'Apple'}, {'name': 'Apricot'}], 'ap') returned \" + str(repr(_r1)) + \", expected [{'name': 'Apple'}, {'name': 'Apricot'}]\"",
          "concepts": [
            "Search",
            "Query filtering"
          ]
        },
        {
          "id": "fapi_36",
          "title": "Authentication Token Validation",
          "difficulty": 4,
          "description": "Write a function decode_token(token: str) that extracts username from 'Bearer username' format.",
          "hints": [
            "Token format is 'Bearer <username>'",
            "Split on space and validate format"
          ],
          "solution": "def decode_token(token: str) -> str | None:\n    parts = token.split()\n    if len(parts) != 2 or parts[0] != 'Bearer':\n        return None\n    return parts[1]",
          "starter_code": "def decode_token(token: str) -> str | None:\n    ...",
          "test_code": "assert 'decode_token' in dir(), \"Function 'decode_token' not defined. Did you write: def decode_token(...)?\"\n_r0 = decode_token('Bearer alice')\nassert _r0 == 'alice', \"Test 1: decode_token('Bearer alice') returned \" + str(repr(_r0)) + \", expected 'alice'\"\n_r1 = decode_token('Bearer bob')\nassert _r1 == 'bob', \"Test 2: decode_token('Bearer bob') returned \" + str(repr(_r1)) + \", expected 'bob'\"\n_r2 = decode_token('InvalidToken')\nassert _r2 == None, \"Test 3: decode_token('InvalidToken') returned \" + str(repr(_r2)) + ', expected None'",
          "concepts": [
            "Authentication",
            "Token parsing"
          ]
        },
        {
          "id": "fapi_37",
          "title": "Rate Limiting Counter",
          "difficulty": 4,
          "description": "Write a function check_rate_limit(user_id: int, limit: int) using a dict to track requests.",
          "hints": [
            "Maintain a dict tracking user request counts",
            "Increment count, return True if under limit"
          ],
          "solution": "request_counts = {}\n\ndef check_rate_limit(user_id: int, limit: int) -> bool:\n    current = request_counts.get(user_id, 0)\n    if current >= limit:\n        return False\n    request_counts[user_id] = current + 1\n    return True",
          "starter_code": "request_counts = {}\n\ndef check_rate_limit(user_id: int, limit: int) -> bool:\n    ...",
          "test_code": "assert 'check_rate_limit' in dir(), \"Function 'check_rate_limit' not defined. Did you write: def check_rate_limit(...)?\"\n_r0 = check_rate_limit(1, 5)\nassert _r0 == True, 'Test 1: check_rate_limit(1, 5) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = check_rate_limit(1, 5)\nassert _r1 == True, 'Test 2: check_rate_limit(1, 5) returned ' + str(repr(_r1)) + ', expected True'",
          "concepts": [
            "Rate limiting",
            "State tracking"
          ]
        },
        {
          "id": "fapi_38",
          "title": "Batch Insert Handler",
          "difficulty": 4,
          "description": "Write a function batch_create(db: dict, items: list, start_id: int) that creates multiple items.",
          "hints": [
            "Iterate over items list",
            "Assign incrementing IDs starting from start_id"
          ],
          "solution": "def batch_create(db: dict, items: list, start_id: int) -> list:\n    created = []\n    for i, item_data in enumerate(items):\n        item_id = start_id + i\n        db[item_id] = {'id': item_id, **item_data}\n        created.append(db[item_id])\n    return created",
          "starter_code": "def batch_create(db: dict, items: list, start_id: int) -> list:\n    ...",
          "test_code": "assert 'batch_create' in dir(), \"Function 'batch_create' not defined. Did you write: def batch_create(...)?\"\n_r0 = batch_create({}, [{'name': 'A'}, {'name': 'B'}], 1)\nassert _r0 == [{'id': 1, 'name': 'A'}, {'id': 2, 'name': 'B'}], \"Test 1: batch_create({}, [{'name': 'A'}, {'name': 'B'}], 1) returned \" + str(repr(_r0)) + \", expected [{'id': 1, 'name': 'A'}, {'id': 2, 'name': 'B'}]\"",
          "concepts": [
            "Batch operations",
            "Bulk inserts"
          ]
        },
        {
          "id": "fapi_39",
          "title": "Partial Update (PATCH) Logic",
          "difficulty": 4,
          "description": "Write a function partial_update(db: dict, item_id: int, updates: dict) that applies only provided fields.",
          "hints": [
            "Only update fields that are in the updates dict",
            "Don't overwrite missing fields"
          ],
          "solution": "def partial_update(db: dict, item_id: int, updates: dict) -> dict | None:\n    if item_id not in db:\n        return None\n    for key, value in updates.items():\n        if value is not None:\n            db[item_id][key] = value\n    return db[item_id]",
          "starter_code": "def partial_update(db: dict, item_id: int, updates: dict) -> dict | None:\n    ...",
          "test_code": "assert 'partial_update' in dir(), \"Function 'partial_update' not defined. Did you write: def partial_update(...)?\"\n_r0 = partial_update({1: {'id': 1, 'name': 'A', 'price': 5}}, 1, {'name': 'B'})\nassert _r0 == {'id': 1, 'name': 'B', 'price': 5}, \"Test 1: partial_update({1: {'id': 1, 'name': 'A', 'price': 5}}, 1, {'name': 'B'}) returned \" + str(repr(_r0)) + \", expected {'id': 1, 'name': 'B', 'price': 5}\"",
          "concepts": [
            "PATCH operations",
            "Partial updates"
          ]
        },
        {
          "id": "fapi_40",
          "title": "Middleware Pattern - Request Logging",
          "difficulty": 4,
          "description": "Write a simple request logging function log_request(method: str, path: str) that formats a log entry.",
          "hints": [
            "Return a formatted string with timestamp, method, path",
            "Use datetime.now() for timestamp"
          ],
          "solution": "from datetime import datetime\n\ndef log_request(method: str, path: str) -> str:\n    timestamp = datetime.now().isoformat()\n    return f'{timestamp} {method} {path}'",
          "starter_code": "from datetime import datetime\n\ndef log_request(method: str, path: str) -> str:\n    ...",
          "test_code": "assert 'log_request' in dir(), \"Function 'log_request' not defined. Did you write: def log_request(...)?\"\n_r0 = log_request('GET', '/items')\nassert _r0 is not None, 'Test 1: log_request returned None'",
          "concepts": [
            "Middleware",
            "Logging"
          ]
        },
        {
          "id": "fapi_41",
          "title": "Permission Check Function",
          "difficulty": 4,
          "description": "Write a function check_permission(user_role: str, resource: str) that validates access.",
          "hints": [
            "Admin has access to all resources",
            "User can access 'public' resource only"
          ],
          "solution": "def check_permission(user_role: str, resource: str) -> bool:\n    if user_role == 'admin':\n        return True\n    if user_role == 'user' and resource == 'public':\n        return True\n    return False",
          "starter_code": "def check_permission(user_role: str, resource: str) -> bool:\n    ...",
          "test_code": "assert 'check_permission' in dir(), \"Function 'check_permission' not defined. Did you write: def check_permission(...)?\"\n_r0 = check_permission('admin', 'private')\nassert _r0 == True, \"Test 1: check_permission('admin', 'private') returned \" + str(repr(_r0)) + ', expected True'\n_r1 = check_permission('user', 'public')\nassert _r1 == True, \"Test 2: check_permission('user', 'public') returned \" + str(repr(_r1)) + ', expected True'\n_r2 = check_permission('user', 'private')\nassert _r2 == False, \"Test 3: check_permission('user', 'private') returned \" + str(repr(_r2)) + ', expected False'",
          "concepts": [
            "Authorization",
            "Access control"
          ]
        },
        {
          "id": "fapi_42",
          "title": "Data Transformation Pipeline",
          "difficulty": 4,
          "description": "Write a function transform_response(items: list) that formats items with uppercase names.",
          "hints": [
            "Apply transformation to each item",
            "Return new list without mutating originals"
          ],
          "solution": "def transform_response(items: list) -> list:\n    return [{'id': item['id'], 'name': item['name'].upper(), 'price': item['price']} for item in items]",
          "starter_code": "def transform_response(items: list) -> list:\n    ...",
          "test_code": "assert 'transform_response' in dir(), \"Function 'transform_response' not defined. Did you write: def transform_response(...)?\"\n_r0 = transform_response([{'id': 1, 'name': 'widget', 'price': 10}])\nassert _r0 == [{'id': 1, 'name': 'WIDGET', 'price': 10}], \"Test 1: transform_response([{'id': 1, 'name': 'widget', 'price': 10}]) returned \" + str(repr(_r0)) + \", expected [{'id': 1, 'name': 'WIDGET', 'price': 10}]\"",
          "concepts": [
            "Data transformation",
            "Response formatting"
          ]
        },
        {
          "id": "fapi_43",
          "title": "Multi-level Filtering",
          "difficulty": 4,
          "description": "Write a function filter_by_multiple(items: list, category: str, min_price: float) that filters on both.",
          "hints": [
            "Both filters must pass for item to be included",
            "Use multiple conditions in list comprehension"
          ],
          "solution": "def filter_by_multiple(items: list, category: str, min_price: float) -> list:\n    return [item for item in items if item.get('category') == category and item.get('price', 0) >= min_price]",
          "starter_code": "def filter_by_multiple(items: list, category: str, min_price: float) -> list:\n    ...",
          "test_code": "assert 'filter_by_multiple' in dir(), \"Function 'filter_by_multiple' not defined. Did you write: def filter_by_multiple(...)?\"\n_r0 = filter_by_multiple([{'category': 'A', 'price': 10}, {'category': 'A', 'price': 5}, {'category': 'B', 'price': 10}], 'A', 7)\nassert _r0 == [{'category': 'A', 'price': 10}], \"Test 1: filter_by_multiple([{'category': 'A', 'price': 10}, {'category': 'A', 'price': 5}, {'category': 'B', 'price': 10}], 'A', 7) returned \" + str(repr(_r0)) + \", expected [{'category': 'A', 'price': 10}]\"",
          "concepts": [
            "Complex filtering",
            "Multiple conditions"
          ]
        },
        {
          "id": "fapi_44",
          "title": "Response Status Code Mapping",
          "difficulty": 4,
          "description": "Create a dict mapping actions to HTTP status codes: created→201, updated→200, deleted→204.",
          "hints": [
            "Map action names to appropriate status codes",
            "201=Created, 200=OK, 204=No Content"
          ],
          "solution": "status_code_map = {\n    'created': 201,\n    'updated': 200,\n    'deleted': 204,\n    'retrieved': 200,\n    'error': 400\n}",
          "starter_code": "status_code_map = {...}",
          "test_code": "assert isinstance(status_code_map, dict), 'status_code_map should be a dictionary, got ' + str(type(status_code_map).__name__)\nassert len(status_code_map) > 0, \"status_code_map should not be empty\"",
          "concepts": [
            "Status codes",
            "Response design"
          ]
        },
        {
          "id": "fapi_45",
          "title": "Aggregate Query (Count/Sum)",
          "difficulty": 4,
          "description": "Write a function aggregate_stats(items: list) that returns count and sum of prices.",
          "hints": [
            "Count the items",
            "Sum the price field"
          ],
          "solution": "def aggregate_stats(items: list) -> dict:\n    return {\n        'count': len(items),\n        'total_price': sum(item.get('price', 0) for item in items),\n        'avg_price': sum(item.get('price', 0) for item in items) / len(items) if items else 0\n    }",
          "starter_code": "def aggregate_stats(items: list) -> dict:\n    ...",
          "test_code": "assert 'aggregate_stats' in dir(), \"Function 'aggregate_stats' not defined. Did you write: def aggregate_stats(...)?\"\n_r0 = aggregate_stats([{'price': 10}, {'price': 20}])\nassert _r0 == {'count': 2, 'total_price': 30, 'avg_price': 15}, \"Test 1: aggregate_stats([{'price': 10}, {'price': 20}]) returned \" + str(repr(_r0)) + \", expected {'count': 2, 'total_price': 30, 'avg_price': 15}\"",
          "concepts": [
            "Aggregation",
            "Statistics"
          ]
        },
        {
          "id": "fapi_46",
          "title": "Todo API - Complete CRUD",
          "difficulty": 5,
          "description": "Implement a complete TODO API with create, read, list, update, delete, and complete operations.",
          "hints": [
            "Use in-memory dict as database",
            "Support marking todos as complete",
            "Generate IDs automatically"
          ],
          "solution": "class TodoAPI:\n    def __init__(self):\n        self.db = {}\n        self.next_id = 1\n\n    def create(self, title: str, description: str = '') -> dict:\n        todo = {\n            'id': self.next_id,\n            'title': title,\n            'description': description,\n            'completed': False\n        }\n        self.db[self.next_id] = todo\n        self.next_id += 1\n        return todo\n\n    def get(self, todo_id: int) -> dict | None:\n        return self.db.get(todo_id)\n\n    def list_all(self) -> list:\n        return list(self.db.values())\n\n    def update(self, todo_id: int, title: str, description: str) -> dict | None:\n        if todo_id not in self.db:\n            return None\n        self.db[todo_id]['title'] = title\n        self.db[todo_id]['description'] = description\n        return self.db[todo_id]\n\n    def complete(self, todo_id: int) -> dict | None:\n        if todo_id not in self.db:\n            return None\n        self.db[todo_id]['completed'] = True\n        return self.db[todo_id]\n\n    def delete(self, todo_id: int) -> bool:\n        if todo_id in self.db:\n            del self.db[todo_id]\n            return True\n        return False",
          "starter_code": "class TodoAPI:\n    def __init__(self):\n        self.db = {}\n        self.next_id = 1\n\n    def create(self, title: str, description: str = '') -> dict:\n        ...\n\n    def get(self, todo_id: int) -> dict | None:\n        ...\n\n    def list_all(self) -> list:\n        ...\n\n    def update(self, todo_id: int, title: str, description: str) -> dict | None:\n        ...\n\n    def complete(self, todo_id: int) -> dict | None:\n        ...\n\n    def delete(self, todo_id: int) -> bool:\n        ...",
          "test_code": "assert 'TodoAPI' in dir(), \"'TodoAPI' is not defined\"\nassert callable(TodoAPI), \"'TodoAPI' should be a function\"",
          "concepts": [
            "Full CRUD",
            "Real-world API",
            "State management"
          ]
        },
        {
          "id": "fapi_47",
          "title": "User Management API",
          "difficulty": 5,
          "description": "Create User model with validation, and implement a UserManager class with registration and login.",
          "hints": [
            "User: email, password, username validation",
            "UserManager: register (checks email exists), get_by_email, authenticate"
          ],
          "solution": "from pydantic import BaseModel, EmailStr, field_validator\n\nclass User(BaseModel):\n    id: int\n    username: str\n    email: EmailStr\n    password: str\n\nclass UserManager:\n    def __init__(self):\n        self.users = {}\n        self.next_id = 1\n\n    def register(self, username: str, email: str, password: str) -> dict | None:\n        # Check if email already exists\n        if any(u['email'] == email for u in self.users.values()):\n            return None\n        user = {\n            'id': self.next_id,\n            'username': username,\n            'email': email,\n            'password': password  # In real app, hash this!\n        }\n        self.users[self.next_id] = user\n        self.next_id += 1\n        return user\n\n    def authenticate(self, email: str, password: str) -> dict | None:\n        for user in self.users.values():\n            if user['email'] == email and user['password'] == password:\n                return user\n        return None",
          "starter_code": "from pydantic import BaseModel, EmailStr\n\nclass User(BaseModel):\n    ...\n\nclass UserManager:\n    def __init__(self):\n        ...\n\n    def register(self, username: str, email: str, password: str) -> dict | None:\n        ...\n\n    def authenticate(self, email: str, password: str) -> dict | None:\n        ...",
          "test_code": "assert 'BaseModel' in dir(), \"'BaseModel' is not defined\"\nassert callable(BaseModel), \"'BaseModel' should be a function\"\nassert 'EmailStr' in dir(), \"'EmailStr' is not defined\"\nassert callable(EmailStr), \"'EmailStr' should be a function\"\nassert 'field_validator' in dir(), \"'field_validator' is not defined\"\nassert callable(field_validator), \"'field_validator' should be a function\"\nassert 'User' in dir(), \"'User' is not defined\"\nassert callable(User), \"'User' should be a function\"\nassert 'UserManager' in dir(), \"'UserManager' is not defined\"\nassert callable(UserManager), \"'UserManager' should be a function\"",
          "concepts": [
            "User management",
            "Authentication",
            "Email validation"
          ]
        },
        {
          "id": "fapi_48",
          "title": "Blog API with Categories",
          "difficulty": 5,
          "description": "Implement a BlogAPI with posts that belong to categories. Support create, filter by category, search.",
          "hints": [
            "Post model: title, content, category",
            "BlogAPI: create_post, get_by_category, search_posts",
            "Store in dict with auto-incrementing IDs"
          ],
          "solution": "class BlogAPI:\n    def __init__(self):\n        self.posts = {}\n        self.next_id = 1\n\n    def create_post(self, title: str, content: str, category: str) -> dict:\n        post = {\n            'id': self.next_id,\n            'title': title,\n            'content': content,\n            'category': category\n        }\n        self.posts[self.next_id] = post\n        self.next_id += 1\n        return post\n\n    def get_by_category(self, category: str) -> list:\n        return [p for p in self.posts.values() if p['category'] == category]\n\n    def search_posts(self, query: str) -> list:\n        q = query.lower()\n        return [p for p in self.posts.values() if q in p['title'].lower() or q in p['content'].lower()]\n\n    def list_all(self) -> list:\n        return list(self.posts.values())",
          "starter_code": "class BlogAPI:\n    def __init__(self):\n        self.posts = {}\n        self.next_id = 1\n\n    def create_post(self, title: str, content: str, category: str) -> dict:\n        ...\n\n    def get_by_category(self, category: str) -> list:\n        ...\n\n    def search_posts(self, query: str) -> list:\n        ...\n\n    def list_all(self) -> list:\n        ...",
          "test_code": "assert 'BlogAPI' in dir(), \"'BlogAPI' is not defined\"\nassert callable(BlogAPI), \"'BlogAPI' should be a function\"",
          "concepts": [
            "Categories",
            "Search",
            "Complex queries"
          ]
        },
        {
          "id": "fapi_49",
          "title": "Shopping Cart API",
          "difficulty": 5,
          "description": "Build a CartAPI with add_item, remove_item, get_total, apply_discount operations.",
          "hints": [
            "Cart: items dict with item_id: quantity",
            "Store price info for calculation",
            "calculate_total with optional discount percentage"
          ],
          "solution": "class CartAPI:\n    def __init__(self):\n        self.items = {}\n        self.prices = {}\n\n    def set_price(self, item_id: int, price: float):\n        self.prices[item_id] = price\n\n    def add_item(self, item_id: int, quantity: int = 1):\n        self.items[item_id] = self.items.get(item_id, 0) + quantity\n\n    def remove_item(self, item_id: int):\n        if item_id in self.items:\n            del self.items[item_id]\n\n    def get_total(self, discount_percent: float = 0) -> float:\n        total = sum(self.prices.get(item_id, 0) * qty for item_id, qty in self.items.items())\n        if discount_percent > 0:\n            total = total * (1 - discount_percent / 100)\n        return total\n\n    def get_items_count(self) -> int:\n        return sum(self.items.values())",
          "starter_code": "class CartAPI:\n    def __init__(self):\n        self.items = {}\n        self.prices = {}\n\n    def set_price(self, item_id: int, price: float):\n        ...\n\n    def add_item(self, item_id: int, quantity: int = 1):\n        ...\n\n    def remove_item(self, item_id: int):\n        ...\n\n    def get_total(self, discount_percent: float = 0) -> float:\n        ...\n\n    def get_items_count(self) -> int:\n        ...",
          "test_code": "assert 'CartAPI' in dir(), \"'CartAPI' is not defined\"\nassert callable(CartAPI), \"'CartAPI' should be a function\"",
          "concepts": [
            "E-commerce",
            "Cart logic",
            "Discounts"
          ]
        },
        {
          "id": "fapi_50",
          "title": "Inventory Management API",
          "difficulty": 5,
          "description": "Implement an InventoryAPI with stock tracking, restock, and low-stock alerts.",
          "hints": [
            "Track item_id: (name, quantity, reorder_level)",
            "Methods: restock, consume (reduce), get_low_stock, get_inventory",
            "Low stock = quantity < reorder_level"
          ],
          "solution": "class InventoryAPI:\n    def __init__(self):\n        self.inventory = {}\n\n    def add_item(self, item_id: int, name: str, quantity: int, reorder_level: int = 10):\n        self.inventory[item_id] = {\n            'name': name,\n            'quantity': quantity,\n            'reorder_level': reorder_level\n        }\n\n    def restock(self, item_id: int, quantity: int) -> dict | None:\n        if item_id not in self.inventory:\n            return None\n        self.inventory[item_id]['quantity'] += quantity\n        return self.inventory[item_id]\n\n    def consume(self, item_id: int, quantity: int) -> dict | None:\n        if item_id not in self.inventory:\n            return None\n        if self.inventory[item_id]['quantity'] < quantity:\n            return None\n        self.inventory[item_id]['quantity'] -= quantity\n        return self.inventory[item_id]\n\n    def get_low_stock(self) -> list:\n        return [\n            {**v, 'item_id': k}\n            for k, v in self.inventory.items()\n            if v['quantity'] < v['reorder_level']\n        ]\n\n    def get_inventory(self) -> list:\n        return [{**v, 'item_id': k} for k, v in self.inventory.items()]",
          "starter_code": "class InventoryAPI:\n    def __init__(self):\n        self.inventory = {}\n\n    def add_item(self, item_id: int, name: str, quantity: int, reorder_level: int = 10):\n        ...\n\n    def restock(self, item_id: int, quantity: int) -> dict | None:\n        ...\n\n    def consume(self, item_id: int, quantity: int) -> dict | None:\n        ...\n\n    def get_low_stock(self) -> list:\n        ...\n\n    def get_inventory(self) -> list:\n        ...",
          "test_code": "assert 'InventoryAPI' in dir(), \"'InventoryAPI' is not defined\"\nassert callable(InventoryAPI), \"'InventoryAPI' should be a function\"",
          "concepts": [
            "Inventory",
            "Stock tracking",
            "Real-world API"
          ]
        }
      ]
    },
    {
      "id": "api_calling",
      "title": "API Calling",
      "exercise_count": 50,
      "exercises": [
        {
          "id": "api_01",
          "title": "What is an API? REST Basics",
          "difficulty": 1,
          "description": "Understand what an API is. API stands for Application Programming Interface. REST APIs use HTTP methods (GET, POST, PUT, DELETE) to interact with resources. Given a description of what an action should do, identify the correct HTTP method.",
          "hints": [
            "GET retrieves data (safe, idempotent)",
            "POST creates new data (not idempotent)",
            "PUT updates existing data (idempotent)",
            "DELETE removes data (idempotent)"
          ],
          "solution": "\ndef identify_http_method(action):\n    mapping = {\n        \"fetch a user profile\": \"GET\",\n        \"create a new post\": \"POST\",\n        \"update user settings\": \"PUT\",\n        \"remove a comment\": \"DELETE\",\n        \"retrieve a list of items\": \"GET\",\n    }\n    return mapping.get(action, \"UNKNOWN\")\n",
          "starter_code": "",
          "test_code": "assert 'identify_http_method' in dir(), \"Function 'identify_http_method' not defined. Did you write: def identify_http_method(...)?\"\n_r0 = identify_http_method('fetch a user profile')\nassert _r0 == 'GET', \"Test 1: identify_http_method('fetch a user profile') returned \" + str(repr(_r0)) + \", expected 'GET'\"\n_r1 = identify_http_method('create a new post')\nassert _r1 == 'POST', \"Test 2: identify_http_method('create a new post') returned \" + str(repr(_r1)) + \", expected 'POST'\"\n_r2 = identify_http_method('update user settings')\nassert _r2 == 'PUT', \"Test 3: identify_http_method('update user settings') returned \" + str(repr(_r2)) + \", expected 'PUT'\"\n_r3 = identify_http_method('remove a comment')\nassert _r3 == 'DELETE', \"Test 4: identify_http_method('remove a comment') returned \" + str(repr(_r3)) + \", expected 'DELETE'\"\n_r4 = identify_http_method('retrieve a list of items')\nassert _r4 == 'GET', \"Test 5: identify_http_method('retrieve a list of items') returned \" + str(repr(_r4)) + \", expected 'GET'\"",
          "concepts": [
            "REST",
            "HTTP methods",
            "GET",
            "POST",
            "PUT",
            "DELETE"
          ]
        },
        {
          "id": "api_02",
          "title": "Parse a JSON String",
          "difficulty": 1,
          "description": "APIs return data as JSON. Learn to parse JSON strings into Python objects using json.loads(). Convert a JSON string into a Python dictionary.",
          "hints": [
            "Use json.loads() to convert a string to a Python dict",
            "The result will be a dictionary with the same keys as the JSON"
          ],
          "solution": "\nimport json\n\ndef parse_json_response(json_string):\n    return json.loads(json_string)\n",
          "starter_code": "",
          "test_code": "assert 'parse_json_response' in dir(), \"Function 'parse_json_response' not defined. Did you write: def parse_json_response(...)?\"\n_r0 = parse_json_response('{\"name\": \"Alice\", \"age\": 30}')\nassert _r0 == {'name': 'Alice', 'age': 30}, 'Test 1: parse_json_response(\\'{\"name\": \"Alice\", \"age\": 30}\\') returned ' + str(repr(_r0)) + \", expected {'name': 'Alice', 'age': 30}\"\n_r1 = parse_json_response('{\"status\": \"success\"}')\nassert _r1 == {'status': 'success'}, 'Test 2: parse_json_response(\\'{\"status\": \"success\"}\\') returned ' + str(repr(_r1)) + \", expected {'status': 'success'}\"\n_r2 = parse_json_response('{\"users\": [1, 2, 3]}')\nassert _r2 == {'users': [1, 2, 3]}, 'Test 3: parse_json_response(\\'{\"users\": [1, 2, 3]}\\') returned ' + str(repr(_r2)) + \", expected {'users': [1, 2, 3]}\"",
          "concepts": [
            "json.loads",
            "JSON parsing",
            "Python dicts"
          ]
        },
        {
          "id": "api_03",
          "title": "Convert Python Object to JSON",
          "difficulty": 1,
          "description": "When sending data to an API, convert Python objects to JSON using json.dumps(). Convert a Python dictionary to a JSON string.",
          "hints": [
            "Use json.dumps() to convert a Python dict to a string",
            "The result will be a valid JSON string"
          ],
          "solution": "\nimport json\n\ndef dict_to_json(data):\n    return json.dumps(data)\n",
          "starter_code": "",
          "test_code": "assert 'dict_to_json' in dir(), \"Function 'dict_to_json' not defined. Did you write: def dict_to_json(...)?\"\n_r0 = dict_to_json({'name': 'Bob', 'age': 25})\nassert _r0 == '{\"name\": \"Bob\", \"age\": 25}', \"Test 1: dict_to_json({'name': 'Bob', 'age': 25}) returned \" + str(repr(_r0)) + ', expected \\'{\"name\": \"Bob\", \"age\": 25}\\''\n_r1 = dict_to_json({'status': 'error'})\nassert _r1 == '{\"status\": \"error\"}', \"Test 2: dict_to_json({'status': 'error'}) returned \" + str(repr(_r1)) + ', expected \\'{\"status\": \"error\"}\\''\n_r2 = dict_to_json({'items': [1, 2, 3]})\nassert _r2 == '{\"items\": [1, 2, 3]}', \"Test 3: dict_to_json({'items': [1, 2, 3]}) returned \" + str(repr(_r2)) + ', expected \\'{\"items\": [1, 2, 3]}\\''",
          "concepts": [
            "json.dumps",
            "JSON serialization",
            "Data encoding"
          ]
        },
        {
          "id": "api_04",
          "title": "Extract Nested Data from JSON",
          "difficulty": 1,
          "description": "API responses often have nested data. Extract a specific value from a nested JSON structure.",
          "hints": [
            "Chain dictionary accesses: dict['key1']['key2']",
            "Consider using .get() for safe access with defaults"
          ],
          "solution": "\ndef extract_user_email(response):\n    return response['user']['email']\n",
          "starter_code": "",
          "test_code": "assert 'extract_user_email' in dir(), \"Function 'extract_user_email' not defined. Did you write: def extract_user_email(...)?\"\n_r0 = extract_user_email({'user': {'email': 'alice@example.com'}})\nassert _r0 == 'alice@example.com', \"Test 1: extract_user_email({'user': {'email': 'alice@example.com'}}) returned \" + str(repr(_r0)) + \", expected 'alice@example.com'\"\n_r1 = extract_user_email({'user': {'email': 'bob@test.org'}})\nassert _r1 == 'bob@test.org', \"Test 2: extract_user_email({'user': {'email': 'bob@test.org'}}) returned \" + str(repr(_r1)) + \", expected 'bob@test.org'\"\n_r2 = extract_user_email({'user': {'email': 'charlie@api.io'}})\nassert _r2 == 'charlie@api.io', \"Test 3: extract_user_email({'user': {'email': 'charlie@api.io'}}) returned \" + str(repr(_r2)) + \", expected 'charlie@api.io'\"",
          "concepts": [
            "Nested dictionaries",
            "Data extraction",
            "JSON navigation"
          ]
        },
        {
          "id": "api_05",
          "title": "Build a Simple URL with Query Parameters",
          "difficulty": 1,
          "description": "API endpoints often accept query parameters. Build a complete URL with parameters like ?name=value&other=value2.",
          "hints": [
            "Base URL ends before the ?",
            "Parameters are key=value pairs joined by &",
            "Start parameters section with ?"
          ],
          "solution": "\ndef build_url(base, params):\n    param_str = \"&\".join(f\"{k}={v}\" for k, v in params.items())\n    return f\"{base}?{param_str}\"\n",
          "starter_code": "",
          "test_code": "assert 'build_url' in dir(), \"Function 'build_url' not defined. Did you write: def build_url(...)?\"\n_r0 = build_url('https://api.example.com/users', {'id': '123'})\nassert _r0 == 'https://api.example.com/users?id=123', \"Test 1: build_url('https://api.example.com/users', {'id': '123'}) returned \" + str(repr(_r0)) + \", expected 'https://api.example.com/users?id=123'\"\n_r1 = build_url('https://api.example.com/search', {'q': 'python'})\nassert _r1 == 'https://api.example.com/search?q=python', \"Test 2: build_url('https://api.example.com/search', {'q': 'python'}) returned \" + str(repr(_r1)) + \", expected 'https://api.example.com/search?q=python'\"\n_r2 = build_url('https://api.example.com/data', {'x': '1', 'y': '2'})\nassert _r2 == 'https://api.example.com/data?x=1&y=2', \"Test 3: build_url('https://api.example.com/data', {'x': '1', 'y': '2'}) returned \" + str(repr(_r2)) + \", expected 'https://api.example.com/data?x=1&y=2'\"",
          "concepts": [
            "Query strings",
            "URL building",
            "Parameters"
          ]
        },
        {
          "id": "api_06",
          "title": "Extract Data from a List in Response",
          "difficulty": 1,
          "description": "Many APIs return a list of items. Extract all names from a list of user objects.",
          "hints": [
            "Use a list comprehension: [item['name'] for item in list]",
            "Or use a for loop to iterate and collect names"
          ],
          "solution": "\ndef extract_user_names(response):\n    return [user['name'] for user in response['users']]\n",
          "starter_code": "",
          "test_code": "assert 'extract_user_names' in dir(), \"Function 'extract_user_names' not defined. Did you write: def extract_user_names(...)?\"\n_r0 = extract_user_names({'users': [{'name': 'Alice'}, {'name': 'Bob'}]})\nassert _r0 == ['Alice', 'Bob'], \"Test 1: extract_user_names({'users': [{'name': 'Alice'}, {'name': 'Bob'}]}) returned \" + str(repr(_r0)) + \", expected ['Alice', 'Bob']\"\n_r1 = extract_user_names({'users': [{'name': 'Charlie'}, {'name': 'Diana'}, {'name': 'Eve'}]})\nassert _r1 == ['Charlie', 'Diana', 'Eve'], \"Test 2: extract_user_names({'users': [{'name': 'Charlie'}, {'name': 'Diana'}, {'name': 'Eve'}]}) returned \" + str(repr(_r1)) + \", expected ['Charlie', 'Diana', 'Eve']\"\n_r2 = extract_user_names({'users': [{'name': 'Frank'}]})\nassert _r2 == ['Frank'], \"Test 3: extract_user_names({'users': [{'name': 'Frank'}]}) returned \" + str(repr(_r2)) + \", expected ['Frank']\"",
          "concepts": [
            "List comprehension",
            "Iteration",
            "Data extraction"
          ]
        },
        {
          "id": "api_07",
          "title": "Check HTTP Status Code",
          "difficulty": 1,
          "description": "HTTP responses have status codes. 200 = success, 404 = not found, 500 = server error, 401 = unauthorized. Given a status code, identify its meaning.",
          "hints": [
            "200-299: Success",
            "400-499: Client error",
            "500-599: Server error"
          ],
          "solution": "\ndef check_status(code):\n    if code == 200:\n        return \"OK\"\n    elif code == 404:\n        return \"Not Found\"\n    elif code == 500:\n        return \"Server Error\"\n    elif code == 401:\n        return \"Unauthorized\"\n    else:\n        return \"Unknown\"\n",
          "starter_code": "",
          "test_code": "assert 'check_status' in dir(), \"Function 'check_status' not defined. Did you write: def check_status(...)?\"\n_r0 = check_status(200)\nassert _r0 == 'OK', 'Test 1: check_status(200) returned ' + str(repr(_r0)) + \", expected 'OK'\"\n_r1 = check_status(404)\nassert _r1 == 'Not Found', 'Test 2: check_status(404) returned ' + str(repr(_r1)) + \", expected 'Not Found'\"\n_r2 = check_status(500)\nassert _r2 == 'Server Error', 'Test 3: check_status(500) returned ' + str(repr(_r2)) + \", expected 'Server Error'\"\n_r3 = check_status(401)\nassert _r3 == 'Unauthorized', 'Test 4: check_status(401) returned ' + str(repr(_r3)) + \", expected 'Unauthorized'\"",
          "concepts": [
            "HTTP status codes",
            "Error handling",
            "Response validation"
          ]
        },
        {
          "id": "api_08",
          "title": "Build a Content-Type Header",
          "difficulty": 1,
          "description": "HTTP headers tell the server about the request. Build a headers dictionary with Content-Type set to application/json.",
          "hints": [
            "Headers are dictionaries with string keys and values",
            "Content-Type for JSON is 'application/json'"
          ],
          "solution": "\ndef build_headers(content_type=\"application/json\"):\n    return {\"Content-Type\": content_type}\n",
          "starter_code": "",
          "test_code": "assert 'build_headers' in dir(), \"Function 'build_headers' not defined. Did you write: def build_headers(...)?\"\n_r0 = build_headers()\nassert _r0 == {'Content-Type': 'application/json'}, 'Test 1: build_headers() returned ' + str(repr(_r0)) + \", expected {'Content-Type': 'application/json'}\"\n_r1 = build_headers('application/xml')\nassert _r1 == {'Content-Type': 'application/xml'}, \"Test 2: build_headers('application/xml') returned \" + str(repr(_r1)) + \", expected {'Content-Type': 'application/xml'}\"\n_r2 = build_headers('text/plain')\nassert _r2 == {'Content-Type': 'text/plain'}, \"Test 3: build_headers('text/plain') returned \" + str(repr(_r2)) + \", expected {'Content-Type': 'text/plain'}\"",
          "concepts": [
            "HTTP headers",
            "Content-Type",
            "Request metadata"
          ]
        },
        {
          "id": "api_09",
          "title": "Parse List from API Response",
          "difficulty": 1,
          "description": "Extract a paginated list of items from an API response. Given a response with 'data' key containing items, return the count.",
          "hints": [
            "Access the 'data' key from the response dict",
            "Use len() to count items in the list"
          ],
          "solution": "\ndef count_items(response):\n    return len(response['data'])\n",
          "starter_code": "",
          "test_code": "assert 'count_items' in dir(), \"Function 'count_items' not defined. Did you write: def count_items(...)?\"\n_r0 = count_items({'data': [1, 2, 3]})\nassert _r0 == 3, \"Test 1: count_items({'data': [1, 2, 3]}) returned \" + str(repr(_r0)) + ', expected 3'\n_r1 = count_items({'data': []})\nassert _r1 == 0, \"Test 2: count_items({'data': []}) returned \" + str(repr(_r1)) + ', expected 0'\n_r2 = count_items({'data': [{'id': 1}, {'id': 2}, {'id': 3}, {'id': 4}]})\nassert _r2 == 4, \"Test 3: count_items({'data': [{'id': 1}, {'id': 2}, {'id': 3}, {'id': 4}]}) returned \" + str(repr(_r2)) + ', expected 4'",
          "concepts": [
            "List access",
            "Counting",
            "Data aggregation"
          ]
        },
        {
          "id": "api_10",
          "title": "Build Basic Auth Header",
          "difficulty": 1,
          "description": "Many APIs use Basic Authentication: combine username and password into a base64-encoded header. Build an Authorization header for Basic auth.",
          "hints": [
            "Basic auth format: 'username:password'",
            "Encode to base64: b64encode(b'username:password')",
            "Header format: 'Basic ' + base64_string"
          ],
          "solution": "\nfrom base64 import b64encode\n\ndef build_basic_auth(username, password):\n    credentials = f\"{username}:{password}\"\n    encoded = b64encode(credentials.encode()).decode()\n    return f\"Basic {encoded}\"\n",
          "starter_code": "",
          "test_code": "assert 'build_basic_auth' in dir(), \"Function 'build_basic_auth' not defined. Did you write: def build_basic_auth(...)?\"\n_r0 = build_basic_auth('user', 'pass')\nassert _r0 == 'Basic dXNlcjpwYXNz', \"Test 1: build_basic_auth('user', 'pass') returned \" + str(repr(_r0)) + \", expected 'Basic dXNlcjpwYXNz'\"\n_r1 = build_basic_auth('admin', 'secret')\nassert _r1 == 'Basic YWRtaW46c2VjcmV0', \"Test 2: build_basic_auth('admin', 'secret') returned \" + str(repr(_r1)) + \", expected 'Basic YWRtaW46c2VjcmV0'\"\n_r2 = build_basic_auth('test', '123')\nassert _r2 == 'Basic dGVzdDoxMjM=', \"Test 3: build_basic_auth('test', '123') returned \" + str(repr(_r2)) + \", expected 'Basic dGVzdDoxMjM='\"",
          "concepts": [
            "Basic Auth",
            "Base64 encoding",
            "Authentication"
          ]
        },
        {
          "id": "api_11",
          "title": "URL Encode Query Parameters",
          "difficulty": 2,
          "description": "Special characters in query parameters must be URL-encoded. Use urllib.parse.urlencode() to safely encode parameters.",
          "hints": [
            "Use urlencode() from urllib.parse",
            "Spaces become %20, special chars are encoded"
          ],
          "solution": "\nfrom urllib.parse import urlencode\n\ndef encode_params(params):\n    return urlencode(params)\n",
          "starter_code": "",
          "test_code": "assert 'encode_params' in dir(), \"Function 'encode_params' not defined. Did you write: def encode_params(...)?\"\n_r0 = encode_params({'q': 'hello world'})\nassert _r0 == 'q=hello+world', \"Test 1: encode_params({'q': 'hello world'}) returned \" + str(repr(_r0)) + \", expected 'q=hello+world'\"\n_r1 = encode_params({'name': 'John Doe', 'age': '30'})\nassert _r1 == 'name=John+Doe&age=30', \"Test 2: encode_params({'name': 'John Doe', 'age': '30'}) returned \" + str(repr(_r1)) + \", expected 'name=John+Doe&age=30'\"\n_r2 = encode_params({'search': 'api & integration'})\nassert _r2 == 'search=api+%26+integration', \"Test 3: encode_params({'search': 'api & integration'}) returned \" + str(repr(_r2)) + \", expected 'search=api+%26+integration'\"",
          "concepts": [
            "URL encoding",
            "urlencode",
            "Parameter escaping"
          ]
        },
        {
          "id": "api_12",
          "title": "Build Complete API Request URL",
          "difficulty": 2,
          "description": "Combine base URL, endpoint, and query parameters to build a complete API request URL.",
          "hints": [
            "Pattern: base_url + '/' + endpoint + '?' + encoded_params",
            "Use urlencode() for params"
          ],
          "solution": "\nfrom urllib.parse import urlencode\n\ndef build_api_url(base_url, endpoint, params):\n    encoded = urlencode(params)\n    return f\"{base_url}/{endpoint}?{encoded}\"\n",
          "starter_code": "",
          "test_code": "assert 'build_api_url' in dir(), \"Function 'build_api_url' not defined. Did you write: def build_api_url(...)?\"\n_r0 = build_api_url('https://api.github.com', 'users', {'per_page': '10'})\nassert _r0 == 'https://api.github.com/users?per_page=10', \"Test 1: build_api_url('https://api.github.com', 'users', {'per_page': '10'}) returned \" + str(repr(_r0)) + \", expected 'https://api.github.com/users?per_page=10'\"\n_r1 = build_api_url('https://api.example.com', 'search', {'q': 'python'})\nassert _r1 == 'https://api.example.com/search?q=python', \"Test 2: build_api_url('https://api.example.com', 'search', {'q': 'python'}) returned \" + str(repr(_r1)) + \", expected 'https://api.example.com/search?q=python'\"\n_r2 = build_api_url('https://api.test.org', 'data', {'id': '123', 'format': 'json'})\nassert _r2 == 'https://api.test.org/data?id=123&format=json', \"Test 3: build_api_url('https://api.test.org', 'data', {'id': '123', 'format': 'json'}) returned \" + str(repr(_r2)) + \", expected 'https://api.test.org/data?id=123&format=json'\"",
          "concepts": [
            "URL construction",
            "API endpoints",
            "urlencode"
          ]
        },
        {
          "id": "api_13",
          "title": "Bearer Token Authorization",
          "difficulty": 2,
          "description": "OAuth2 APIs use Bearer tokens for authorization. Build an Authorization header with a Bearer token.",
          "hints": [
            "Bearer auth format: 'Bearer ' + token",
            "Token is usually a JWT or API key"
          ],
          "solution": "\ndef build_bearer_auth(token):\n    return f\"Bearer {token}\"\n",
          "starter_code": "",
          "test_code": "assert 'build_bearer_auth' in dir(), \"Function 'build_bearer_auth' not defined. Did you write: def build_bearer_auth(...)?\"\n_r0 = build_bearer_auth('abc123def456')\nassert _r0 == 'Bearer abc123def456', \"Test 1: build_bearer_auth('abc123def456') returned \" + str(repr(_r0)) + \", expected 'Bearer abc123def456'\"\n_r1 = build_bearer_auth('eyJhbGc...')\nassert _r1 == 'Bearer eyJhbGc...', \"Test 2: build_bearer_auth('eyJhbGc...') returned \" + str(repr(_r1)) + \", expected 'Bearer eyJhbGc...'\"\n_r2 = build_bearer_auth('sk_test_123')\nassert _r2 == 'Bearer sk_test_123', \"Test 3: build_bearer_auth('sk_test_123') returned \" + str(repr(_r2)) + \", expected 'Bearer sk_test_123'\"",
          "concepts": [
            "Bearer Token",
            "OAuth2",
            "Authorization headers"
          ]
        },
        {
          "id": "api_14",
          "title": "Extract Status and Message from Error Response",
          "difficulty": 2,
          "description": "When an API call fails, extract error details. Parse an error response to get the status code and error message.",
          "hints": [
            "Error responses typically have 'status' or 'error' keys",
            "Messages might be in 'message' or 'detail' fields"
          ],
          "solution": "\ndef extract_error(response):\n    return (response.get('status'), response.get('message'))\n",
          "starter_code": "",
          "test_code": "assert 'extract_error' in dir(), \"Function 'extract_error' not defined. Did you write: def extract_error(...)?\"\n_r0 = extract_error({'status': 400, 'message': 'Invalid request'})\nassert _r0 == (400, 'Invalid request'), \"Test 1: extract_error({'status': 400, 'message': 'Invalid request'}) returned \" + str(repr(_r0)) + \", expected (400, 'Invalid request')\"\n_r1 = extract_error({'status': 401, 'message': 'Unauthorized'})\nassert _r1 == (401, 'Unauthorized'), \"Test 2: extract_error({'status': 401, 'message': 'Unauthorized'}) returned \" + str(repr(_r1)) + \", expected (401, 'Unauthorized')\"\n_r2 = extract_error({'status': 404, 'message': 'Not found'})\nassert _r2 == (404, 'Not found'), \"Test 3: extract_error({'status': 404, 'message': 'Not found'}) returned \" + str(repr(_r2)) + \", expected (404, 'Not found')\"",
          "concepts": [
            "Error handling",
            "Response parsing",
            "Debugging"
          ]
        },
        {
          "id": "api_15",
          "title": "Build Request Headers Dictionary",
          "difficulty": 2,
          "description": "Combine multiple headers (Content-Type, Authorization, Accept) into a single headers dictionary.",
          "hints": [
            "Headers is a dict: {key: value, ...}",
            "Common headers: Content-Type, Authorization, Accept, User-Agent"
          ],
          "solution": "\ndef build_request_headers(auth_token, content_type=\"application/json\"):\n    return {\n        \"Content-Type\": content_type,\n        \"Authorization\": f\"Bearer {auth_token}\",\n        \"Accept\": \"application/json\",\n    }\n",
          "starter_code": "",
          "test_code": "assert 'build_request_headers' in dir(), \"Function 'build_request_headers' not defined. Did you write: def build_request_headers(...)?\"\n_r0 = build_request_headers('token123')\nassert _r0 == {'Content-Type': 'application/json', 'Authorization': 'Bearer token123', 'Accept': 'application/json'}, \"Test 1: build_request_headers('token123') returned \" + str(repr(_r0)) + \", expected {'Content-Type': 'application/json', 'Authorization': 'Bearer token123', 'Accept': 'application/json'}\"\n_r1 = build_request_headers('abc', 'text/plain')\nassert _r1 == {'Content-Type': 'text/plain', 'Authorization': 'Bearer abc', 'Accept': 'application/json'}, \"Test 2: build_request_headers('abc', 'text/plain') returned \" + str(repr(_r1)) + \", expected {'Content-Type': 'text/plain', 'Authorization': 'Bearer abc', 'Accept': 'application/json'}\"",
          "concepts": [
            "HTTP headers",
            "Authorization",
            "Content negotiation"
          ]
        },
        {
          "id": "api_16",
          "title": "Parse Pagination Metadata",
          "difficulty": 2,
          "description": "APIs use pagination to limit response size. Extract pagination info (current page, total pages, next URL) from a response.",
          "hints": [
            "Look for 'pagination' or 'meta' key in response",
            "Check for 'page', 'per_page', 'total', 'next_url' keys"
          ],
          "solution": "\ndef get_pagination_info(response):\n    meta = response.get('pagination', {})\n    return (meta.get('page'), meta.get('per_page'), meta.get('total'), meta.get('next_url'))\n",
          "starter_code": "",
          "test_code": "assert 'get_pagination_info' in dir(), \"Function 'get_pagination_info' not defined. Did you write: def get_pagination_info(...)?\"\n_r0 = get_pagination_info({'pagination': {'page': 1, 'per_page': 10, 'total': 100, 'next_url': '?page=2'}})\nassert _r0 == (1, 10, 100, '?page=2'), \"Test 1: get_pagination_info({'pagination': {'page': 1, 'per_page': 10, 'total': 100, 'next_url': '?page=2'}}) returned \" + str(repr(_r0)) + \", expected (1, 10, 100, '?page=2')\"\n_r1 = get_pagination_info({'pagination': {'page': 2, 'per_page': 20, 'total': 50, 'next_url': None}})\nassert _r1 == (2, 20, 50, None), \"Test 2: get_pagination_info({'pagination': {'page': 2, 'per_page': 20, 'total': 50, 'next_url': None}}) returned \" + str(repr(_r1)) + ', expected (2, 20, 50, None)'",
          "concepts": [
            "Pagination",
            "Metadata extraction",
            "API design"
          ]
        },
        {
          "id": "api_17",
          "title": "Build JSON Request Body",
          "difficulty": 2,
          "description": "When sending data to an API via POST/PUT, create a JSON request body. Convert a Python dict to JSON string.",
          "hints": [
            "Use json.dumps() to serialize the dict",
            "Include required fields for the API endpoint"
          ],
          "solution": "\nimport json\n\ndef build_request_body(user_data):\n    return json.dumps({\n        \"name\": user_data['name'],\n        \"email\": user_data['email'],\n        \"age\": user_data['age'],\n    })\n",
          "starter_code": "",
          "test_code": "assert 'build_request_body' in dir(), \"Function 'build_request_body' not defined. Did you write: def build_request_body(...)?\"\n_r0 = build_request_body({'name': 'Alice', 'email': 'alice@example.com', 'age': 30})\nassert _r0 == '{\"name\": \"Alice\", \"email\": \"alice@example.com\", \"age\": 30}', \"Test 1: build_request_body({'name': 'Alice', 'email': 'alice@example.com', 'age': 30}) returned \" + str(repr(_r0)) + ', expected \\'{\"name\": \"Alice\", \"email\": \"alice@example.com\", \"age\": 30}\\''\n_r1 = build_request_body({'name': 'Bob', 'email': 'bob@test.org', 'age': 25})\nassert _r1 == '{\"name\": \"Bob\", \"email\": \"bob@test.org\", \"age\": 25}', \"Test 2: build_request_body({'name': 'Bob', 'email': 'bob@test.org', 'age': 25}) returned \" + str(repr(_r1)) + ', expected \\'{\"name\": \"Bob\", \"email\": \"bob@test.org\", \"age\": 25}\\''",
          "concepts": [
            "JSON serialization",
            "Request bodies",
            "Data formatting"
          ]
        },
        {
          "id": "api_18",
          "title": "Filter Data from API Response",
          "difficulty": 2,
          "description": "Extract and filter specific items from an API response. Get all users with age > 25.",
          "hints": [
            "Use list comprehension: [item for item in list if condition]",
            "Filter based on a field value"
          ],
          "solution": "\ndef filter_users_by_age(response, min_age):\n    return [user for user in response['users'] if user['age'] > min_age]\n",
          "starter_code": "",
          "test_code": "assert 'filter_users_by_age' in dir(), \"Function 'filter_users_by_age' not defined. Did you write: def filter_users_by_age(...)?\"\n_r0 = filter_users_by_age({'users': [{'name': 'Alice', 'age': 30}, {'name': 'Bob', 'age': 20}]}, 25)\nassert _r0 == [{'name': 'Alice', 'age': 30}], \"Test 1: filter_users_by_age({'users': [{'name': 'Alice', 'age': 30}, {'name': 'Bob', 'age': 20}]}, 25) returned \" + str(repr(_r0)) + \", expected [{'name': 'Alice', 'age': 30}]\"\n_r1 = filter_users_by_age({'users': [{'name': 'Charlie', 'age': 26}, {'name': 'Diana', 'age': 28}, {'name': 'Eve', 'age': 22}]}, 25)\nassert _r1 == [{'name': 'Charlie', 'age': 26}, {'name': 'Diana', 'age': 28}], \"Test 2: filter_users_by_age({'users': [{'name': 'Charlie', 'age': 26}, {'name': 'Diana', 'age': 28}, {'name': 'Eve', 'age': 22}]}, 25) returned \" + str(repr(_r1)) + \", expected [{'name': 'Charlie', 'age': 26}, {'name': 'Diana', 'age': 28}]\"",
          "concepts": [
            "List filtering",
            "Conditional logic",
            "Data transformation"
          ]
        },
        {
          "id": "api_19",
          "title": "Build Query String Manually",
          "difficulty": 2,
          "description": "Build a query string from parameters without urlencode(). Manually join key=value pairs with &.",
          "hints": [
            "Start with empty string",
            "Join pairs with '&'",
            "Format: key1=value1&key2=value2"
          ],
          "solution": "\ndef build_query_string(params):\n    pairs = [f\"{k}={v}\" for k, v in params.items()]\n    return \"&\".join(pairs)\n",
          "starter_code": "",
          "test_code": "assert 'build_query_string' in dir(), \"Function 'build_query_string' not defined. Did you write: def build_query_string(...)?\"\n_r0 = build_query_string({'id': '1'})\nassert _r0 == 'id=1', \"Test 1: build_query_string({'id': '1'}) returned \" + str(repr(_r0)) + \", expected 'id=1'\"\n_r1 = build_query_string({'name': 'test', 'page': '2'})\nassert _r1 == 'name=test&page=2', \"Test 2: build_query_string({'name': 'test', 'page': '2'}) returned \" + str(repr(_r1)) + \", expected 'name=test&page=2'\"",
          "concepts": [
            "Query strings",
            "String joining",
            "Manual URL building"
          ]
        },
        {
          "id": "api_20",
          "title": "Combine User Agent Header",
          "difficulty": 2,
          "description": "User-Agent headers identify the client. Build a User-Agent string for your API client.",
          "hints": [
            "Format: 'AppName/Version (Language; Platform)'",
            "Example: 'MyApp/1.0 (Python; Linux)'"
          ],
          "solution": "\ndef build_user_agent(app_name, version, language=\"Python\", platform=\"Linux\"):\n    return f\"{app_name}/{version} ({language}; {platform})\"\n",
          "starter_code": "",
          "test_code": "assert 'build_user_agent' in dir(), \"Function 'build_user_agent' not defined. Did you write: def build_user_agent(...)?\"\n_r0 = build_user_agent('MyApp', '1.0')\nassert _r0 == 'MyApp/1.0 (Python; Linux)', \"Test 1: build_user_agent('MyApp', '1.0') returned \" + str(repr(_r0)) + \", expected 'MyApp/1.0 (Python; Linux)'\"\n_r1 = build_user_agent('APIClient', '2.5', 'Python', 'Windows')\nassert _r1 == 'APIClient/2.5 (Python; Windows)', \"Test 2: build_user_agent('APIClient', '2.5', 'Python', 'Windows') returned \" + str(repr(_r1)) + \", expected 'APIClient/2.5 (Python; Windows)'\"",
          "concepts": [
            "User-Agent",
            "HTTP headers",
            "Client identification"
          ]
        },
        {
          "id": "api_21",
          "title": "Implement Pagination Loop",
          "difficulty": 3,
          "description": "Collect all items across multiple pages. Given responses with next_page_url, simulate fetching all pages and collecting all items.",
          "hints": [
            "Start with first page response",
            "Check for next_page_url in pagination metadata",
            "Collect items from each page until no next_page_url"
          ],
          "solution": "\ndef collect_all_pages(responses):\n    all_items = []\n    for response in responses:\n        all_items.extend(response.get('items', []))\n    return all_items\n",
          "starter_code": "",
          "test_code": "assert 'collect_all_pages' in dir(), \"Function 'collect_all_pages' not defined. Did you write: def collect_all_pages(...)?\"\n_r0 = collect_all_pages([{'items': [1, 2], 'next_url': 'page2'}, {'items': [3, 4], 'next_url': None}])\nassert _r0 == [1, 2, 3, 4], \"Test 1: collect_all_pages([{'items': [1, 2], 'next_url': 'page2'}, {'items': [3, 4], 'next_url': None}]) returned \" + str(repr(_r0)) + ', expected [1, 2, 3, 4]'\n_r1 = collect_all_pages([{'items': ['a', 'b', 'c']}])\nassert _r1 == ['a', 'b', 'c'], \"Test 2: collect_all_pages([{'items': ['a', 'b', 'c']}]) returned \" + str(repr(_r1)) + \", expected ['a', 'b', 'c']\"",
          "concepts": [
            "Pagination",
            "Loops",
            "Data aggregation"
          ]
        },
        {
          "id": "api_22",
          "title": "Transform API Response to Internal Format",
          "difficulty": 3,
          "description": "APIs return data in their format. Transform it to match your application's internal format.",
          "hints": [
            "Map API field names to your field names",
            "Extract only needed fields",
            "Use list comprehension for lists"
          ],
          "solution": "\ndef transform_users(api_response):\n    return [\n        {\"id\": u['user_id'], \"full_name\": u['name'], \"contact\": u['email']}\n        for u in api_response['users']\n    ]\n",
          "starter_code": "",
          "test_code": "assert 'transform_users' in dir(), \"Function 'transform_users' not defined. Did you write: def transform_users(...)?\"\n_r0 = transform_users({'users': [{'user_id': 1, 'name': 'Alice', 'email': 'alice@ex.com'}]})\nassert _r0 == [{'id': 1, 'full_name': 'Alice', 'contact': 'alice@ex.com'}], \"Test 1: transform_users({'users': [{'user_id': 1, 'name': 'Alice', 'email': 'alice@ex.com'}]}) returned \" + str(repr(_r0)) + \", expected [{'id': 1, 'full_name': 'Alice', 'contact': 'alice@ex.com'}]\"\n_r1 = transform_users({'users': [{'user_id': 2, 'name': 'Bob', 'email': 'bob@ex.com'}, {'user_id': 3, 'name': 'Charlie', 'email': 'charlie@ex.com'}]})\nassert _r1 == [{'id': 2, 'full_name': 'Bob', 'contact': 'bob@ex.com'}, {'id': 3, 'full_name': 'Charlie', 'contact': 'charlie@ex.com'}], \"Test 2: transform_users({'users': [{'user_id': 2, 'name': 'Bob', 'email': 'bob@ex.com'}, {'user_id': 3, 'name': 'Charlie', 'email': 'charlie@ex.com'}]}) returned \" + str(repr(_r1)) + \", expected [{'id': 2, 'full_name': 'Bob', 'contact': 'bob@ex.com'}, {'id': 3, 'full_name': 'Charlie', 'contact': 'charlie@ex.com'}]\"",
          "concepts": [
            "Data transformation",
            "Schema mapping",
            "List comprehension"
          ]
        },
        {
          "id": "api_23",
          "title": "Validate Required Fields in Response",
          "difficulty": 3,
          "description": "Ensure API response has required fields. Check if 'status' and 'data' keys exist; return True if valid, False otherwise.",
          "hints": [
            "Check if keys exist in dict using 'in' operator",
            "All required fields must be present"
          ],
          "solution": "\ndef validate_response(response, required_fields):\n    return all(field in response for field in required_fields)\n",
          "starter_code": "",
          "test_code": "assert 'validate_response' in dir(), \"Function 'validate_response' not defined. Did you write: def validate_response(...)?\"\n_r0 = validate_response({'status': 'ok', 'data': [1, 2]}, ['status', 'data'])\nassert _r0 == True, \"Test 1: validate_response({'status': 'ok', 'data': [1, 2]}, ['status', 'data']) returned \" + str(repr(_r0)) + ', expected True'\n_r1 = validate_response({'status': 'ok'}, ['status', 'data'])\nassert _r1 == False, \"Test 2: validate_response({'status': 'ok'}, ['status', 'data']) returned \" + str(repr(_r1)) + ', expected False'\n_r2 = validate_response({'status': 'error', 'message': 'fail', 'timestamp': 123}, ['status', 'message', 'timestamp'])\nassert _r2 == True, \"Test 3: validate_response({'status': 'error', 'message': 'fail', 'timestamp': 123}, ['status', 'message', 'timestamp']) returned \" + str(repr(_r2)) + ', expected True'",
          "concepts": [
            "Validation",
            "Error checking",
            "Data integrity"
          ]
        },
        {
          "id": "api_24",
          "title": "Build Webhook Signature (HMAC-SHA256)",
          "difficulty": 3,
          "description": "APIs send webhooks to your server. Validate webhook payload authenticity using HMAC-SHA256 signature.",
          "hints": [
            "Use hmac.new(key, msg, hashlib.sha256)",
            "Key is usually the API secret",
            "Message is the webhook payload (as bytes)"
          ],
          "solution": "\nimport hmac\nimport hashlib\n\ndef compute_webhook_signature(secret, payload):\n    return hmac.new(\n        secret.encode(),\n        payload.encode(),\n        hashlib.sha256\n    ).hexdigest()\n",
          "starter_code": "",
          "test_code": "assert 'compute_webhook_signature' in dir(), \"Function 'compute_webhook_signature' not defined. Did you write: def compute_webhook_signature(...)?\"\n_r0 = compute_webhook_signature('secret123', 'payload')\nassert _r0 == '6db7b2948f10a9a0edeebcfa6cfd43b0ebac5fadd6c131fb2b7842ee2c30f15f', \"Test 1: compute_webhook_signature('secret123', 'payload') returned \" + str(repr(_r0)) + \", expected '6db7b2948f10a9a0edeebcfa6cfd43b0ebac5fadd6c131fb2b7842ee2c30f15f'\"",
          "concepts": [
            "Webhooks",
            "HMAC",
            "Security"
          ]
        },
        {
          "id": "api_25",
          "title": "Extract Errors from Validation Response",
          "difficulty": 3,
          "description": "When data validation fails, APIs return detailed error messages. Extract all field errors from response.",
          "hints": [
            "Errors might be in 'errors' dict or 'validation_errors' list",
            "Each error has field name and error message"
          ],
          "solution": "\ndef extract_field_errors(response):\n    return response.get('errors', {})\n",
          "starter_code": "",
          "test_code": "assert 'extract_field_errors' in dir(), \"Function 'extract_field_errors' not defined. Did you write: def extract_field_errors(...)?\"\n_r0 = extract_field_errors({'errors': {'email': 'Invalid format', 'name': 'Required'}})\nassert _r0 == {'email': 'Invalid format', 'name': 'Required'}, \"Test 1: extract_field_errors({'errors': {'email': 'Invalid format', 'name': 'Required'}}) returned \" + str(repr(_r0)) + \", expected {'email': 'Invalid format', 'name': 'Required'}\"\n_r1 = extract_field_errors({'errors': {}})\nassert _r1 == {}, \"Test 2: extract_field_errors({'errors': {}}) returned \" + str(repr(_r1)) + ', expected {}'",
          "concepts": [
            "Error handling",
            "Validation",
            "User feedback"
          ]
        },
        {
          "id": "api_26",
          "title": "Build Batch Request Payload",
          "difficulty": 3,
          "description": "Some APIs accept batch requests. Build a payload with multiple operations.",
          "hints": [
            "Batch payload is usually a list of operation dicts",
            "Each operation has type, data, etc."
          ],
          "solution": "\ndef build_batch_request(operations):\n    return {\n        \"requests\": [\n            {\"method\": op['method'], \"endpoint\": op['endpoint'], \"data\": op.get('data')}\n            for op in operations\n        ]\n    }\n",
          "starter_code": "",
          "test_code": "assert 'build_batch_request' in dir(), \"Function 'build_batch_request' not defined. Did you write: def build_batch_request(...)?\"\n_r0 = build_batch_request([{'method': 'POST', 'endpoint': '/users', 'data': {'name': 'Alice'}}])\nassert _r0 == {'requests': [{'method': 'POST', 'endpoint': '/users', 'data': {'name': 'Alice'}}]}, \"Test 1: build_batch_request([{'method': 'POST', 'endpoint': '/users', 'data': {'name': 'Alice'}}]) returned \" + str(repr(_r0)) + \", expected {'requests': [{'method': 'POST', 'endpoint': '/users', 'data': {'name': 'Alice'}}]}\"",
          "concepts": [
            "Batch requests",
            "API design",
            "Optimization"
          ]
        },
        {
          "id": "api_27",
          "title": "Exponential Backoff Delay Calculation",
          "difficulty": 3,
          "description": "When rate limited, retry with increasing delays. Calculate exponential backoff: delay = base * (multiplier ^ attempt).",
          "hints": [
            "Formula: base * (multiplier ** attempt)",
            "Common: base=1, multiplier=2 (1, 2, 4, 8, 16...)"
          ],
          "solution": "\ndef calculate_backoff(attempt, base=1, multiplier=2):\n    return base * (multiplier ** attempt)\n",
          "starter_code": "",
          "test_code": "assert 'calculate_backoff' in dir(), \"Function 'calculate_backoff' not defined. Did you write: def calculate_backoff(...)?\"\n_r0 = calculate_backoff(0, 1, 2)\nassert _r0 == 1, 'Test 1: calculate_backoff(0, 1, 2) returned ' + str(repr(_r0)) + ', expected 1'\n_r1 = calculate_backoff(1, 1, 2)\nassert _r1 == 2, 'Test 2: calculate_backoff(1, 1, 2) returned ' + str(repr(_r1)) + ', expected 2'\n_r2 = calculate_backoff(3, 1, 2)\nassert _r2 == 8, 'Test 3: calculate_backoff(3, 1, 2) returned ' + str(repr(_r2)) + ', expected 8'\n_r3 = calculate_backoff(2, 2, 3)\nassert _r3 == 18, 'Test 4: calculate_backoff(2, 2, 3) returned ' + str(repr(_r3)) + ', expected 18'",
          "concepts": [
            "Rate limiting",
            "Retry logic",
            "Exponential backoff"
          ]
        },
        {
          "id": "api_28",
          "title": "Build API Cache Key",
          "difficulty": 3,
          "description": "Implement response caching by building unique cache keys from request parameters.",
          "hints": [
            "Cache key should include base URL and all params",
            "Use stable string representation (sorted dicts)"
          ],
          "solution": "\ndef build_cache_key(endpoint, params):\n    sorted_params = sorted(params.items())\n    param_str = \"&\".join(f\"{k}={v}\" for k, v in sorted_params)\n    return f\"{endpoint}?{param_str}\"\n",
          "starter_code": "",
          "test_code": "assert 'build_cache_key' in dir(), \"Function 'build_cache_key' not defined. Did you write: def build_cache_key(...)?\"\n_r0 = build_cache_key('https://api.example.com/users', {'id': '1'})\nassert _r0 == 'https://api.example.com/users?id=1', \"Test 1: build_cache_key('https://api.example.com/users', {'id': '1'}) returned \" + str(repr(_r0)) + \", expected 'https://api.example.com/users?id=1'\"\n_r1 = build_cache_key('https://api.example.com/search', {'q': 'test', 'page': '1'})\nassert _r1 == 'https://api.example.com/search?page=1&q=test', \"Test 2: build_cache_key('https://api.example.com/search', {'q': 'test', 'page': '1'}) returned \" + str(repr(_r1)) + \", expected 'https://api.example.com/search?page=1&q=test'\"",
          "concepts": [
            "Caching",
            "Performance",
            "Data consistency"
          ]
        },
        {
          "id": "api_29",
          "title": "Parse Timestamp from API Response",
          "difficulty": 3,
          "description": "APIs return timestamps in ISO 8601 format. Extract and validate timestamp from response.",
          "hints": [
            "ISO format: '2024-04-08T12:30:45Z'",
            "Could be string or Unix timestamp",
            "Validate presence before using"
          ],
          "solution": "\ndef get_response_timestamp(response):\n    return response.get('timestamp') or response.get('created_at')\n",
          "starter_code": "",
          "test_code": "assert 'get_response_timestamp' in dir(), \"Function 'get_response_timestamp' not defined. Did you write: def get_response_timestamp(...)?\"\n_r0 = get_response_timestamp({'timestamp': '2024-04-08T12:30:45Z'})\nassert _r0 == '2024-04-08T12:30:45Z', \"Test 1: get_response_timestamp({'timestamp': '2024-04-08T12:30:45Z'}) returned \" + str(repr(_r0)) + \", expected '2024-04-08T12:30:45Z'\"\n_r1 = get_response_timestamp({'created_at': '2024-04-08T10:00:00Z'})\nassert _r1 == '2024-04-08T10:00:00Z', \"Test 2: get_response_timestamp({'created_at': '2024-04-08T10:00:00Z'}) returned \" + str(repr(_r1)) + \", expected '2024-04-08T10:00:00Z'\"",
          "concepts": [
            "Timestamp handling",
            "Data parsing",
            "Time zones"
          ]
        },
        {
          "id": "api_30",
          "title": "Count Items with Specific Status",
          "difficulty": 3,
          "description": "Count items matching a status from paginated API responses.",
          "hints": [
            "Iterate through items in response",
            "Check status field",
            "Count matches"
          ],
          "solution": "\ndef count_status(response, status):\n    return sum(1 for item in response['items'] if item['status'] == status)\n",
          "starter_code": "",
          "test_code": "assert 'count_status' in dir(), \"Function 'count_status' not defined. Did you write: def count_status(...)?\"\n_r0 = count_status({'items': [{'status': 'active'}, {'status': 'active'}, {'status': 'inactive'}]}, 'active')\nassert _r0 == 2, \"Test 1: count_status({'items': [{'status': 'active'}, {'status': 'active'}, {'status': 'inactive'}]}, 'active') returned \" + str(repr(_r0)) + ', expected 2'\n_r1 = count_status({'items': [{'status': 'pending'}, {'status': 'completed'}]}, 'pending')\nassert _r1 == 1, \"Test 2: count_status({'items': [{'status': 'pending'}, {'status': 'completed'}]}, 'pending') returned \" + str(repr(_r1)) + ', expected 1'",
          "concepts": [
            "Filtering",
            "Aggregation",
            "Data analysis"
          ]
        },
        {
          "id": "api_31",
          "title": "Build Conditional Request Headers",
          "difficulty": 3,
          "description": "Build headers conditionally: include auth only if token provided, include custom headers based on conditions.",
          "hints": [
            "Start with base headers",
            "Add optional headers conditionally",
            "Use dict.update() or dict unpacking"
          ],
          "solution": "\ndef build_conditional_headers(has_auth=False, token=None, is_json=True):\n    headers = {}\n    if is_json:\n        headers['Content-Type'] = 'application/json'\n    if has_auth and token:\n        headers['Authorization'] = f'Bearer {token}'\n    return headers\n",
          "starter_code": "",
          "test_code": "assert 'build_conditional_headers' in dir(), \"Function 'build_conditional_headers' not defined. Did you write: def build_conditional_headers(...)?\"\n_r0 = build_conditional_headers(False, None, True)\nassert _r0 == {'Content-Type': 'application/json'}, 'Test 1: build_conditional_headers(False, None, True) returned ' + str(repr(_r0)) + \", expected {'Content-Type': 'application/json'}\"\n_r1 = build_conditional_headers(True, 'abc123', True)\nassert _r1 == {'Content-Type': 'application/json', 'Authorization': 'Bearer abc123'}, \"Test 2: build_conditional_headers(True, 'abc123', True) returned \" + str(repr(_r1)) + \", expected {'Content-Type': 'application/json', 'Authorization': 'Bearer abc123'}\"\n_r2 = build_conditional_headers(True, None, False)\nassert _r2 == {}, 'Test 3: build_conditional_headers(True, None, False) returned ' + str(repr(_r2)) + ', expected {}'",
          "concepts": [
            "Conditional logic",
            "Headers",
            "API flexibility"
          ]
        },
        {
          "id": "api_32",
          "title": "Extract Links from Response (HATEOAS)",
          "difficulty": 3,
          "description": "HATEOAS APIs include links to related resources. Extract all links from response.",
          "hints": [
            "Links are typically in '_links' or 'links' object",
            "Each link has 'rel' and 'href' properties"
          ],
          "solution": "\ndef extract_links(response):\n    links = response.get('_links', {})\n    return {rel: link['href'] for rel, link in links.items()}\n",
          "starter_code": "",
          "test_code": "assert 'extract_links' in dir(), \"Function 'extract_links' not defined. Did you write: def extract_links(...)?\"\n_r0 = extract_links({'_links': {'self': {'href': '/users/1'}, 'next': {'href': '/users/2'}}})\nassert _r0 == {'self': '/users/1', 'next': '/users/2'}, \"Test 1: extract_links({'_links': {'self': {'href': '/users/1'}, 'next': {'href': '/users/2'}}}) returned \" + str(repr(_r0)) + \", expected {'self': '/users/1', 'next': '/users/2'}\"",
          "concepts": [
            "HATEOAS",
            "Resource linking",
            "API discovery"
          ]
        },
        {
          "id": "api_33",
          "title": "Aggregate Data from Multiple API Calls",
          "difficulty": 3,
          "description": "Combine results from multiple API responses. Sum values across responses.",
          "hints": [
            "Each response contains items with values",
            "Sum all values from all responses"
          ],
          "solution": "\ndef aggregate_totals(responses):\n    return sum(item['value'] for response in responses for item in response['items'])\n",
          "starter_code": "",
          "test_code": "assert 'aggregate_totals' in dir(), \"Function 'aggregate_totals' not defined. Did you write: def aggregate_totals(...)?\"\n_r0 = aggregate_totals([{'items': [{'value': 10}, {'value': 20}]}, {'items': [{'value': 5}]}])\nassert _r0 == 35, \"Test 1: aggregate_totals([{'items': [{'value': 10}, {'value': 20}]}, {'items': [{'value': 5}]}]) returned \" + str(repr(_r0)) + ', expected 35'",
          "concepts": [
            "Data aggregation",
            "Multiple sources",
            "Calculation"
          ]
        },
        {
          "id": "api_34",
          "title": "Detect Rate Limit Headers",
          "difficulty": 3,
          "description": "APIs send rate limit info in response headers. Extract limit, remaining, and reset time.",
          "hints": [
            "Common headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset",
            "Access headers dict to get values"
          ],
          "solution": "\ndef get_rate_limit_info(headers):\n    return {\n        \"limit\": int(headers.get(\"X-RateLimit-Limit\", 0)),\n        \"remaining\": int(headers.get(\"X-RateLimit-Remaining\", 0)),\n        \"reset\": int(headers.get(\"X-RateLimit-Reset\", 0)),\n    }\n",
          "starter_code": "",
          "test_code": "assert 'get_rate_limit_info' in dir(), \"Function 'get_rate_limit_info' not defined. Did you write: def get_rate_limit_info(...)?\"\n_r0 = get_rate_limit_info({'X-RateLimit-Limit': '60', 'X-RateLimit-Remaining': '30', 'X-RateLimit-Reset': '1234567890'})\nassert _r0 == {'limit': 60, 'remaining': 30, 'reset': 1234567890}, \"Test 1: get_rate_limit_info({'X-RateLimit-Limit': '60', 'X-RateLimit-Remaining': '30', 'X-RateLimit-Reset': '1234567890'}) returned \" + str(repr(_r0)) + \", expected {'limit': 60, 'remaining': 30, 'reset': 1234567890}\"",
          "concepts": [
            "Rate limiting",
            "HTTP headers",
            "API quotas"
          ]
        },
        {
          "id": "api_35",
          "title": "Build OAuth Authorization URL",
          "difficulty": 3,
          "description": "OAuth requires redirecting user to authorization URL. Build the full authorization URL with params.",
          "hints": [
            "Include: client_id, redirect_uri, scope, response_type='code'",
            "Use urlencode for params"
          ],
          "solution": "\nfrom urllib.parse import urlencode\n\ndef build_oauth_url(base_url, client_id, redirect_uri, scope):\n    params = {\n        \"client_id\": client_id,\n        \"redirect_uri\": redirect_uri,\n        \"scope\": scope,\n        \"response_type\": \"code\",\n    }\n    return f\"{base_url}?{urlencode(params)}\"\n",
          "starter_code": "",
          "test_code": "assert 'build_oauth_url' in dir(), \"Function 'build_oauth_url' not defined. Did you write: def build_oauth_url(...)?\"\n_r0 = build_oauth_url('https://auth.example.com/authorize', 'abc123', 'https://myapp.com/callback', 'read write')\nassert _r0 == 'https://auth.example.com/authorize?client_id=abc123&redirect_uri=https%3A%2F%2Fmyapp.com%2Fcallback&scope=read+write&response_type=code', \"Test 1: build_oauth_url('https://auth.example.com/authorize', 'abc123', 'https://myapp.com/callback', 'read write') returned \" + str(repr(_r0)) + \", expected 'https://auth.example.com/authorize?client_id=abc123&redirect_uri=https%3A%2F%2Fmyapp.com%2Fcallback&scope=read+write&response_type=code'\"",
          "concepts": [
            "OAuth2",
            "Authorization",
            "URL parameters"
          ]
        },
        {
          "id": "api_36",
          "title": "Implement Retry Logic with Exponential Backoff",
          "difficulty": 4,
          "description": "Simulate retry logic with exponential backoff. Given a list of (status_code, attempt_number), determine if retry is needed and calculate next wait time.",
          "hints": [
            "Retry on 429 (rate limit), 5xx errors",
            "Calculate wait using exponential backoff",
            "Max retries typically 3-5"
          ],
          "solution": "\ndef should_retry(status_code, attempt, max_attempts=3):\n    if status_code in [429, 500, 502, 503, 504]:\n        return attempt < max_attempts\n    return False\n\ndef get_wait_time(attempt, base=1, multiplier=2):\n    return base * (multiplier ** attempt)\n",
          "starter_code": "",
          "test_code": "assert 'should_retry' in dir(), \"Function 'should_retry' not defined. Did you write: def should_retry(...)?\"\n_r0 = should_retry(429, 0, 3)\nassert _r0 == True, 'Test 1: should_retry(429, 0, 3) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = should_retry(429, 3, 3)\nassert _r1 == False, 'Test 2: should_retry(429, 3, 3) returned ' + str(repr(_r1)) + ', expected False'\n_r2 = should_retry(200, 0, 3)\nassert _r2 == False, 'Test 3: should_retry(200, 0, 3) returned ' + str(repr(_r2)) + ', expected False'\n_r3 = should_retry(503, 1, 3)\nassert _r3 == True, 'Test 4: should_retry(503, 1, 3) returned ' + str(repr(_r3)) + ', expected True'",
          "concepts": [
            "Retry logic",
            "Rate limiting",
            "Error recovery"
          ]
        },
        {
          "id": "api_37",
          "title": "Parse Complex Nested JSON",
          "difficulty": 4,
          "description": "Extract deeply nested data: user.profile.contact.email from complex API response.",
          "hints": [
            "Use .get() for safe navigation",
            "Chain multiple .get() calls",
            "Provide defaults for missing keys"
          ],
          "solution": "\ndef get_user_email(response):\n    user = response.get('user')\n    if not isinstance(user, dict):\n        return None\n    profile = user.get('profile', {})\n    contact = profile.get('contact', {})\n    return contact.get('email')\n",
          "starter_code": "",
          "test_code": "assert 'get_user_email' in dir(), \"Function 'get_user_email' not defined. Did you write: def get_user_email(...)?\"\n_r0 = get_user_email({'user': {'profile': {'contact': {'email': 'alice@example.com'}}}})\nassert _r0 == 'alice@example.com', \"Test 1: get_user_email({'user': {'profile': {'contact': {'email': 'alice@example.com'}}}}) returned \" + str(repr(_r0)) + \", expected 'alice@example.com'\"\n_r1 = get_user_email({'user': {'profile': {}}})\nassert _r1 == None, \"Test 2: get_user_email({'user': {'profile': {}}}) returned \" + str(repr(_r1)) + ', expected None'\n_r2 = get_user_email({'user': None})\nassert _r2 == None, \"Test 3: get_user_email({'user': None}) returned \" + str(repr(_r2)) + ', expected None'",
          "concepts": [
            "Nested data",
            "Safe navigation",
            "Error prevention"
          ]
        },
        {
          "id": "api_38",
          "title": "Validate and Normalize Phone Number from API",
          "difficulty": 4,
          "description": "APIs return phone numbers in various formats. Validate and normalize to standard format.",
          "hints": [
            "Remove non-digit characters",
            "Check length (usually 10+ digits)",
            "Return normalized format"
          ],
          "solution": "\ndef normalize_phone(phone):\n    if not phone:\n        return None\n    digits = ''.join(c for c in phone if c.isdigit())\n    if len(digits) >= 10:\n        return digits\n    return None\n",
          "starter_code": "",
          "test_code": "assert 'normalize_phone' in dir(), \"Function 'normalize_phone' not defined. Did you write: def normalize_phone(...)?\"\n_r0 = normalize_phone('+1 (555) 123-4567')\nassert _r0 == '15551234567', \"Test 1: normalize_phone('+1 (555) 123-4567') returned \" + str(repr(_r0)) + \", expected '15551234567'\"\n_r1 = normalize_phone('555.123.4567')\nassert _r1 == '5551234567', \"Test 2: normalize_phone('555.123.4567') returned \" + str(repr(_r1)) + \", expected '5551234567'\"\n_r2 = normalize_phone('123')\nassert _r2 == None, \"Test 3: normalize_phone('123') returned \" + str(repr(_r2)) + ', expected None'",
          "concepts": [
            "Data validation",
            "Normalization",
            "String processing"
          ]
        },
        {
          "id": "api_39",
          "title": "Build Cursor-Based Pagination Request",
          "difficulty": 4,
          "description": "Cursor-based pagination uses opaque cursors instead of page numbers. Build request with cursor.",
          "hints": [
            "Use 'cursor' parameter instead of 'page'",
            "Next cursor comes from previous response",
            "First request has no cursor or cursor=null"
          ],
          "solution": "\nfrom urllib.parse import urlencode\n\ndef build_cursor_request(base_url, cursor=None):\n    params = {\"limit\": 10}\n    if cursor:\n        params[\"cursor\"] = cursor\n    return f\"{base_url}?{urlencode(params)}\"\n",
          "starter_code": "",
          "test_code": "assert 'build_cursor_request' in dir(), \"Function 'build_cursor_request' not defined. Did you write: def build_cursor_request(...)?\"\n_r0 = build_cursor_request('https://api.example.com/items')\nassert _r0 == 'https://api.example.com/items?limit=10', \"Test 1: build_cursor_request('https://api.example.com/items') returned \" + str(repr(_r0)) + \", expected 'https://api.example.com/items?limit=10'\"\n_r1 = build_cursor_request('https://api.example.com/items', 'abc123')\nassert _r1 == 'https://api.example.com/items?limit=10&cursor=abc123', \"Test 2: build_cursor_request('https://api.example.com/items', 'abc123') returned \" + str(repr(_r1)) + \", expected 'https://api.example.com/items?limit=10&cursor=abc123'\"",
          "concepts": [
            "Cursor pagination",
            "API design",
            "Stateless iteration"
          ]
        },
        {
          "id": "api_40",
          "title": "Handle API Response Errors with Fallback",
          "difficulty": 4,
          "description": "When API fails, use cached or default data. Return API data if valid, else fallback.",
          "hints": [
            "Check if response has errors",
            "Use cached data if API response is invalid",
            "Provide sensible defaults"
          ],
          "solution": "\ndef get_data_with_fallback(api_response, cached_data, default_data=None):\n    if api_response.get('status') == 'success' and api_response.get('data'):\n        return api_response['data']\n    elif cached_data:\n        return cached_data\n    return default_data or {}\n",
          "starter_code": "",
          "test_code": "assert 'get_data_with_fallback' in dir(), \"Function 'get_data_with_fallback' not defined. Did you write: def get_data_with_fallback(...)?\"\n_r0 = get_data_with_fallback({'status': 'success', 'data': {'id': 1}}, [1, 2], [])\nassert _r0 == {'id': 1}, \"Test 1: get_data_with_fallback({'status': 'success', 'data': {'id': 1}}, [1, 2], []) returned \" + str(repr(_r0)) + \", expected {'id': 1}\"\n_r1 = get_data_with_fallback({'status': 'error'}, [1, 2], [])\nassert _r1 == [1, 2], \"Test 2: get_data_with_fallback({'status': 'error'}, [1, 2], []) returned \" + str(repr(_r1)) + ', expected [1, 2]'\n_r2 = get_data_with_fallback({'error': 'failed'}, None, {'default': True})\nassert _r2 == {'default': True}, \"Test 3: get_data_with_fallback({'error': 'failed'}, None, {'default': True}) returned \" + str(repr(_r2)) + \", expected {'default': True}\"",
          "concepts": [
            "Error handling",
            "Caching",
            "Resilience"
          ]
        },
        {
          "id": "api_41",
          "title": "Transform Flat Response to Nested Structure",
          "difficulty": 4,
          "description": "API returns flat data. Transform to nested structure (e.g., group by category).",
          "hints": [
            "Use dict comprehension or defaultdict",
            "Group items by a field",
            "Create nested structure"
          ],
          "solution": "\ndef group_by_category(items):\n    result = {}\n    for item in items:\n        cat = item['category']\n        if cat not in result:\n            result[cat] = []\n        result[cat].append(item)\n    return result\n",
          "starter_code": "",
          "test_code": "assert 'group_by_category' in dir(), \"Function 'group_by_category' not defined. Did you write: def group_by_category(...)?\"\n_r0 = group_by_category([{'category': 'A', 'name': 'Item1'}, {'category': 'B', 'name': 'Item2'}, {'category': 'A', 'name': 'Item3'}])\nassert _r0 == {'A': [{'category': 'A', 'name': 'Item1'}, {'category': 'A', 'name': 'Item3'}], 'B': [{'category': 'B', 'name': 'Item2'}]}, \"Test 1: group_by_category([{'category': 'A', 'name': 'Item1'}, {'category': 'B', 'name': 'Item2'}, {'category': 'A', 'name': 'Item3'}]) returned \" + str(repr(_r0)) + \", expected {'A': [{'category': 'A', 'name': 'Item1'}, {'category': 'A', 'name': 'Item3'}], 'B': [{'category': 'B', 'name': 'Item2'}]}\"",
          "concepts": [
            "Data restructuring",
            "Grouping",
            "Transformation"
          ]
        },
        {
          "id": "api_42",
          "title": "Calculate Request Signature (AWS Signature V4)",
          "difficulty": 4,
          "description": "AWS APIs require signature. Understand signature building process (simplified).",
          "hints": [
            "Create canonical request from HTTP method, path, query, headers, body",
            "Sign with secret key using HMAC-SHA256",
            "Include timestamp in header"
          ],
          "solution": "\ndef build_aws_signature_parts(method, path, params):\n    # Simplified: just verify structure\n    return {\n        \"method\": method,\n        \"path\": path,\n        \"params\": sorted(params.items()),\n    }\n",
          "starter_code": "",
          "test_code": "assert 'build_aws_signature_parts' in dir(), \"Function 'build_aws_signature_parts' not defined. Did you write: def build_aws_signature_parts(...)?\"\n_r0 = build_aws_signature_parts('GET', '/api/users', {'id': '1'})\nassert _r0 == {'method': 'GET', 'path': '/api/users', 'params': [('id', '1')]}, \"Test 1: build_aws_signature_parts('GET', '/api/users', {'id': '1'}) returned \" + str(repr(_r0)) + \", expected {'method': 'GET', 'path': '/api/users', 'params': [('id', '1')]}\"",
          "concepts": [
            "AWS",
            "Signature",
            "Security"
          ]
        },
        {
          "id": "api_43",
          "title": "Handle Webhook Retry Validation",
          "difficulty": 4,
          "description": "Webhook request includes attempt number and max attempts. Validate that retry attempt is valid.",
          "hints": [
            "Check X-Webhook-Attempt header",
            "Check X-Webhook-Retry-Count header",
            "Validate attempt <= max_attempts"
          ],
          "solution": "\ndef validate_webhook_attempt(headers):\n    attempt = int(headers.get('X-Webhook-Attempt', 1))\n    max_attempts = int(headers.get('X-Webhook-Retry-Count', 3))\n    return attempt <= max_attempts\n",
          "starter_code": "",
          "test_code": "assert 'validate_webhook_attempt' in dir(), \"Function 'validate_webhook_attempt' not defined. Did you write: def validate_webhook_attempt(...)?\"\n_r0 = validate_webhook_attempt({'X-Webhook-Attempt': '1', 'X-Webhook-Retry-Count': '3'})\nassert _r0 == True, \"Test 1: validate_webhook_attempt({'X-Webhook-Attempt': '1', 'X-Webhook-Retry-Count': '3'}) returned \" + str(repr(_r0)) + ', expected True'\n_r1 = validate_webhook_attempt({'X-Webhook-Attempt': '4', 'X-Webhook-Retry-Count': '3'})\nassert _r1 == False, \"Test 2: validate_webhook_attempt({'X-Webhook-Attempt': '4', 'X-Webhook-Retry-Count': '3'}) returned \" + str(repr(_r1)) + ', expected False'",
          "concepts": [
            "Webhooks",
            "Retry handling",
            "Validation"
          ]
        },
        {
          "id": "api_44",
          "title": "Build Search Query with Filters",
          "difficulty": 4,
          "description": "Build complex search query: keyword + multiple filters (date range, status, etc.).",
          "hints": [
            "Include search term",
            "Add filter parameters",
            "Handle optional filters"
          ],
          "solution": "\nfrom urllib.parse import urlencode\n\ndef build_search_query(base_url, keyword, filters):\n    params = {\"q\": keyword}\n    params.update(filters)\n    return f\"{base_url}?{urlencode(params)}\"\n",
          "starter_code": "",
          "test_code": "assert 'build_search_query' in dir(), \"Function 'build_search_query' not defined. Did you write: def build_search_query(...)?\"\n_r0 = build_search_query('https://api.example.com/search', 'python', {'status': 'active'})\nassert _r0 == 'https://api.example.com/search?q=python&status=active', \"Test 1: build_search_query('https://api.example.com/search', 'python', {'status': 'active'}) returned \" + str(repr(_r0)) + \", expected 'https://api.example.com/search?q=python&status=active'\"\n_r1 = build_search_query('https://api.example.com/search', 'test', {'from': '2024-01-01', 'to': '2024-12-31'})\nassert _r1 == 'https://api.example.com/search?q=test&from=2024-01-01&to=2024-12-31', \"Test 2: build_search_query('https://api.example.com/search', 'test', {'from': '2024-01-01', 'to': '2024-12-31'}) returned \" + str(repr(_r1)) + \", expected 'https://api.example.com/search?q=test&from=2024-01-01&to=2024-12-31'\"",
          "concepts": [
            "Search",
            "Filtering",
            "Complex queries"
          ]
        },
        {
          "id": "api_45",
          "title": "Merge Paginated Results into Single Dataset",
          "difficulty": 4,
          "description": "Collect results from multiple pages and merge into single deduplicated dataset.",
          "hints": [
            "Iterate through all responses",
            "Collect items from each",
            "Deduplicate by id"
          ],
          "solution": "\ndef merge_paginated_results(responses):\n    items_dict = {}\n    for response in responses:\n        for item in response.get('items', []):\n            items_dict[item['id']] = item\n    return list(items_dict.values())\n",
          "starter_code": "",
          "test_code": "assert 'merge_paginated_results' in dir(), \"Function 'merge_paginated_results' not defined. Did you write: def merge_paginated_results(...)?\"\n_r0 = merge_paginated_results([{'items': [{'id': 1, 'name': 'A'}, {'id': 2, 'name': 'B'}]}, {'items': [{'id': 2, 'name': 'B'}, {'id': 3, 'name': 'C'}]}])\nassert _r0 == [{'id': 1, 'name': 'A'}, {'id': 2, 'name': 'B'}, {'id': 3, 'name': 'C'}], \"Test 1: merge_paginated_results([{'items': [{'id': 1, 'name': 'A'}, {'id': 2, 'name': 'B'}]}, {'items': [{'id': 2, 'name': 'B'}, {'id': 3, 'name': 'C'}]}]) returned \" + str(repr(_r0)) + \", expected [{'id': 1, 'name': 'A'}, {'id': 2, 'name': 'B'}, {'id': 3, 'name': 'C'}]\"",
          "concepts": [
            "Pagination",
            "Deduplication",
            "Data merging"
          ]
        },
        {
          "id": "api_46",
          "title": "Implement Sliding Window Rate Limiter",
          "difficulty": 5,
          "description": "Implement sliding window rate limiter: track requests in time window, reject if exceeds limit.",
          "hints": [
            "Keep list of request timestamps",
            "Remove timestamps outside window",
            "Check count against limit"
          ],
          "solution": "\ndef sliding_window_ratelimit(requests, limit, window_seconds):\n    # requests is list of timestamps\n    # Remove old timestamps - keep only those within the window\n    if not requests:\n        return True\n    cutoff = requests[-1] - window_seconds\n    recent = [r for r in requests if r > cutoff]\n    # Return True if count exceeds limit\n    return len(recent) > limit\n",
          "starter_code": "",
          "test_code": "assert 'sliding_window_ratelimit' in dir(), \"Function 'sliding_window_ratelimit' not defined. Did you write: def sliding_window_ratelimit(...)?\"\n_r0 = sliding_window_ratelimit([1, 2, 3, 4, 5], 3, 10)\nassert _r0 == True, 'Test 1: sliding_window_ratelimit([1, 2, 3, 4, 5], 3, 10) returned ' + str(repr(_r0)) + ', expected True'\n_r1 = sliding_window_ratelimit([1, 2, 3, 4, 5, 6, 7], 5, 3)\nassert _r1 == False, 'Test 2: sliding_window_ratelimit([1, 2, 3, 4, 5, 6, 7], 5, 3) returned ' + str(repr(_r1)) + ', expected False'",
          "concepts": [
            "Rate limiting",
            "Sliding window",
            "Algorithms"
          ]
        },
        {
          "id": "api_47",
          "title": "Build GraphQL Query",
          "difficulty": 5,
          "description": "GraphQL APIs use queries instead of URLs. Build a GraphQL query string.",
          "hints": [
            "GraphQL syntax: query { field { subfield } }",
            "Variables can be passed separately"
          ],
          "solution": "\ndef build_graphql_query(fields, filters):\n    filter_str = \", \".join(f\"{k}: {v}\" for k, v in filters.items())\n    field_str = \" \".join(fields)\n    return f\"query {{ users({filter_str}) {{ {field_str} }} }}\"\n",
          "starter_code": "",
          "test_code": "assert 'build_graphql_query' in dir(), \"Function 'build_graphql_query' not defined. Did you write: def build_graphql_query(...)?\"\n_r0 = build_graphql_query(['id', 'name'], {'limit': '10'})\nassert _r0 == 'query { users(limit: 10) { id name } }', \"Test 1: build_graphql_query(['id', 'name'], {'limit': '10'}) returned \" + str(repr(_r0)) + \", expected 'query { users(limit: 10) { id name } }'\"",
          "concepts": [
            "GraphQL",
            "Query language",
            "API design"
          ]
        },
        {
          "id": "api_48",
          "title": "Implement Request Deduplication",
          "difficulty": 5,
          "description": "Prevent duplicate requests by tracking request IDs. Return true if request is duplicate, false if new.",
          "hints": [
            "Keep set of seen request IDs",
            "Generate ID from method, path, params",
            "Check if ID already exists"
          ],
          "solution": "\ndef is_duplicate_request(request_id, seen_requests):\n    if request_id in seen_requests:\n        return True\n    seen_requests.add(request_id)\n    return False\n",
          "starter_code": "",
          "test_code": "assert 'is_duplicate_request' in dir(), \"Function 'is_duplicate_request' not defined. Did you write: def is_duplicate_request(...)?\"\n_r0 = is_duplicate_request('req_1', {'req_1'})\nassert _r0 == True, \"Test 1: is_duplicate_request('req_1', {'req_1'}) returned \" + str(repr(_r0)) + ', expected True'\n_r1 = is_duplicate_request('req_2', {'req_1'})\nassert _r1 == False, \"Test 2: is_duplicate_request('req_2', {'req_1'}) returned \" + str(repr(_r1)) + ', expected False'",
          "concepts": [
            "Idempotency",
            "Request deduplication",
            "State management"
          ]
        },
        {
          "id": "api_49",
          "title": "Process Streaming API Response",
          "difficulty": 5,
          "description": "Streaming APIs send data in chunks. Process each chunk and accumulate results.",
          "hints": [
            "Each chunk is a JSON line or partial response",
            "Accumulate into final result",
            "Handle incomplete chunks"
          ],
          "solution": "\nimport json\n\ndef process_stream(*chunks):\n    result = []\n    for chunk in chunks:\n        data = json.loads(chunk)\n        result.append(data)\n    return result\n",
          "starter_code": "",
          "test_code": "assert 'process_stream' in dir(), \"Function 'process_stream' not defined. Did you write: def process_stream(...)?\"\n_r0 = process_stream('{\"id\": 1}', '{\"id\": 2}', '{\"id\": 3}')\nassert _r0 == [{'id': 1}, {'id': 2}, {'id': 3}], 'Test 1: process_stream(\\'{\"id\": 1}\\', \\'{\"id\": 2}\\', \\'{\"id\": 3}\\') returned ' + str(repr(_r0)) + \", expected [{'id': 1}, {'id': 2}, {'id': 3}]\"",
          "concepts": [
            "Streaming",
            "Chunked responses",
            "Real-time data"
          ]
        },
        {
          "id": "api_50",
          "title": "Build Complete API Client Pattern",
          "difficulty": 5,
          "description": "Combine all skills: build a function that makes a simulated API request with all proper components.",
          "hints": [
            "Include URL building, headers, body, validation, error handling",
            "Simulate response with mock data",
            "Return structured result"
          ],
          "solution": "\nimport json\n\ndef simulated_api_request(method, endpoint, data, token):\n    # Build request\n    headers = {\n        \"Content-Type\": \"application/json\",\n        \"Authorization\": f\"Bearer {token}\",\n    }\n    body = json.dumps(data) if data else None\n\n    # Simulate response\n    mock_response = {\n        \"status\": 200,\n        \"data\": {\"success\": True, \"id\": 123},\n        \"headers\": headers,\n    }\n    return mock_response\n",
          "starter_code": "",
          "test_code": "assert 'simulated_api_request' in dir(), \"Function 'simulated_api_request' not defined. Did you write: def simulated_api_request(...)?\"\n_r0 = simulated_api_request('POST', '/users', {'name': 'Alice'}, 'token123')\nassert _r0 == {'status': 200, 'data': {'success': True, 'id': 123}, 'headers': {'Content-Type': 'application/json', 'Authorization': 'Bearer token123'}}, \"Test 1: simulated_api_request('POST', '/users', {'name': 'Alice'}, 'token123') returned \" + str(repr(_r0)) + \", expected {'status': 200, 'data': {'success': True, 'id': 123}, 'headers': {'Content-Type': 'application/json', 'Authorization': 'Bearer token123'}}\"",
          "concepts": [
            "Complete API pattern",
            "Integration",
            "Full workflow"
          ]
        }
      ]
    }
  ]
}