""" CodeDebugger Bug Dataset — 30 buggy Python problems. Schema per problem: id, difficulty, title, description, buggy_code, fixed_code, test_cases, error_type, hint. Each problem has exactly 4 test cases. """ # ═══════════════════════════════════════════════════════════════ # EASY BUGS (1–10) # ═══════════════════════════════════════════════════════════════ EASY_BUGS = [ # 1 { "id": "bug_001", "difficulty": "easy", "title": "Off-by-one in list index", "description": "Fix the bug in this function that retrieves the last element.", "buggy_code": ( "def get_last(lst):\n" " return lst[len(lst)]\n" ), "fixed_code": ( "def get_last(lst):\n" " return lst[len(lst) - 1]\n" ), "test_cases": [ {"input": "[1, 2, 3]", "expected": "3"}, {"input": "[10]", "expected": "10"}, {"input": "[5, 6, 7, 8]", "expected": "8"}, {"input": "[0]", "expected": "0"}, ], "error_type": "IndexError", "hint": "list indices are 0-based; the last valid index is len(lst)-1.", }, # 2 { "id": "bug_002", "difficulty": "easy", "title": "Wrong comparison operator (> instead of >=)", "description": "Fix the function that checks whether a score is passing (>= 50).", "buggy_code": ( "def is_passing(score):\n" " return score > 50\n" ), "fixed_code": ( "def is_passing(score):\n" " return score >= 50\n" ), "test_cases": [ {"input": "75", "expected": "True"}, {"input": "50", "expected": "True"}, {"input": "49", "expected": "False"}, {"input": "100", "expected": "True"}, ], "error_type": "LogicError", "hint": "A score of exactly 50 should pass; use >= not >.", }, # 3 { "id": "bug_003", "difficulty": "easy", "title": "Missing return statement", "description": "Fix the function that should return the square of a number.", "buggy_code": ( "def square(n):\n" " result = n * n\n" ), "fixed_code": ( "def square(n):\n" " result = n * n\n" " return result\n" ), "test_cases": [ {"input": "4", "expected": "16"}, {"input": "0", "expected": "0"}, {"input": "-3", "expected": "9"}, {"input": "10", "expected": "100"}, ], "error_type": "LogicError", "hint": "The function computes the result but never returns it.", }, # 4 { "id": "bug_004", "difficulty": "easy", "title": "Wrong variable name used", "description": "Fix the function that converts Celsius to Fahrenheit.", "buggy_code": ( "def celsius_to_fahrenheit(c):\n" " f = c * 9 / 5 + 32\n" " return c\n" ), "fixed_code": ( "def celsius_to_fahrenheit(c):\n" " f = c * 9 / 5 + 32\n" " return f\n" ), "test_cases": [ {"input": "0", "expected": "32.0"}, {"input": "100", "expected": "212.0"}, {"input": "37", "expected": "98.6"}, {"input": "-40", "expected": "-40.0"}, ], "error_type": "LogicError", "hint": "The formula stores the result in `f` but the wrong variable is returned.", }, # 5 { "id": "bug_005", "difficulty": "easy", "title": "Wrong string method: split vs strip", "description": "Fix the function that removes leading/trailing whitespace from a string.", "buggy_code": ( "def clean(s):\n" " return s.split()\n" ), "fixed_code": ( "def clean(s):\n" " return s.strip()\n" ), "test_cases": [ {"input": "' hello '", "expected": "hello"}, {"input": "'world'", "expected": "world"}, {"input": "' '", "expected": ""}, {"input": "' a b '", "expected": "a b"}, ], "error_type": "TypeError", "hint": "strip() removes whitespace; split() splits into a list.", }, # 6 { "id": "bug_006", "difficulty": "easy", "title": "Missing -1 in length calculation", "description": "Fix the function that returns the second-to-last element of a list.", "buggy_code": ( "def second_to_last(lst):\n" " return lst[len(lst) - 1]\n" ), "fixed_code": ( "def second_to_last(lst):\n" " return lst[len(lst) - 2]\n" ), "test_cases": [ {"input": "[1, 2, 3]", "expected": "2"}, {"input": "[10, 20]", "expected": "10"}, {"input": "[5, 6, 7, 8]", "expected": "7"}, {"input": "[0, 1]", "expected": "0"}, ], "error_type": "LogicError", "hint": "The second-to-last index is len(lst)-2, not len(lst)-1.", }, # 7 { "id": "bug_007", "difficulty": "easy", "title": "Wrong list method: append vs extend", "description": "Fix the function that adds all elements of one list into another.", "buggy_code": ( "def combine(base, items):\n" " base.append(items)\n" " return base\n" ), "fixed_code": ( "def combine(base, items):\n" " base.extend(items)\n" " return base\n" ), "test_cases": [ {"input": "[1, 2], [3, 4]", "expected": "[1, 2, 3, 4]"}, {"input": "[], [1]", "expected": "[1]"}, {"input": "[0], []", "expected": "[0]"}, {"input": "[1], [2, 3, 4]", "expected": "[1, 2, 3, 4]"}, ], "error_type": "LogicError", "hint": "append() adds the list as a single element; extend() unpacks it.", }, # 8 { "id": "bug_008", "difficulty": "easy", "title": "Comparing to None with == instead of is", "description": "Fix the function that checks whether a value is None.", "buggy_code": ( "def is_empty(val):\n" " return val == None\n" ), "fixed_code": ( "def is_empty(val):\n" " return val is None\n" ), "test_cases": [ {"input": "None", "expected": "True"}, {"input": "0", "expected": "False"}, {"input": "''", "expected": "False"}, {"input": "[]", "expected": "False"}, ], "error_type": "LogicError", "hint": "Use `is None` for identity check, not `== None`.", }, # 9 { "id": "bug_009", "difficulty": "easy", "title": "Integer division instead of float division", "description": "Fix the function that calculates the average of a list.", "buggy_code": ( "def average(nums):\n" " return sum(nums) // len(nums)\n" ), "fixed_code": ( "def average(nums):\n" " return sum(nums) / len(nums)\n" ), "test_cases": [ {"input": "[1, 2, 3, 4]", "expected": "2.5"}, {"input": "[10, 20]", "expected": "15.0"}, {"input": "[7]", "expected": "7.0"}, {"input": "[1, 1, 1, 1]", "expected": "1.0"}, ], "error_type": "LogicError", "hint": "Use / for true division; // performs floor division.", }, # 10 { "id": "bug_010", "difficulty": "easy", "title": "Wrong list index: -1 vs 0", "description": "Fix the function that returns the first element of a list.", "buggy_code": ( "def get_first(lst):\n" " return lst[-1]\n" ), "fixed_code": ( "def get_first(lst):\n" " return lst[0]\n" ), "test_cases": [ {"input": "[1, 2, 3]", "expected": "1"}, {"input": "[10]", "expected": "10"}, {"input": "[5, 6, 7, 8]", "expected": "5"}, {"input": "[99, 0]", "expected": "99"}, ], "error_type": "LogicError", "hint": "Index 0 is the first element; -1 is the last.", }, ] # ═══════════════════════════════════════════════════════════════ # MEDIUM BUGS (11–20) # ═══════════════════════════════════════════════════════════════ MEDIUM_BUGS = [ # 11 { "id": "bug_011", "difficulty": "medium", "title": "Wrong loop termination condition", "description": "Fix the function that counts down from n to 1 and returns the sum.", "buggy_code": ( "def countdown_sum(n):\n" " total = 0\n" " while n > 1:\n" " total += n\n" " n -= 1\n" " return total\n" ), "fixed_code": ( "def countdown_sum(n):\n" " total = 0\n" " while n >= 1:\n" " total += n\n" " n -= 1\n" " return total\n" ), "test_cases": [ {"input": "5", "expected": "15"}, {"input": "1", "expected": "1"}, {"input": "10", "expected": "55"}, {"input": "3", "expected": "6"}, ], "error_type": "LogicError", "hint": "`n > 1` stops too early and skips adding 1; use `n >= 1` to include it.", }, # 12 { "id": "bug_012", "difficulty": "medium", "title": "Wrong recursion base case value", "description": "Fix the recursive factorial function that returns the wrong result for n=0.", "buggy_code": ( "def factorial(n):\n" " if n == 0:\n" " return 0\n" " return n * factorial(n - 1)\n" ), "fixed_code": ( "def factorial(n):\n" " if n == 0:\n" " return 1\n" " return n * factorial(n - 1)\n" ), "test_cases": [ {"input": "0", "expected": "1"}, {"input": "1", "expected": "1"}, {"input": "5", "expected": "120"}, {"input": "7", "expected": "5040"}, ], "error_type": "LogicError", "hint": "0! is defined as 1, not 0. The base case must return 1.", }, # 13 { "id": "bug_013", "difficulty": "medium", "title": "Wrong sort order (missing reverse=True)", "description": "Fix the function that should return a list sorted in descending order.", "buggy_code": ( "def sort_desc(lst):\n" " return sorted(lst)\n" ), "fixed_code": ( "def sort_desc(lst):\n" " return sorted(lst, reverse=True)\n" ), "test_cases": [ {"input": "[3, 1, 2]", "expected": "[3, 2, 1]"}, {"input": "[5, 5, 5]", "expected": "[5, 5, 5]"}, {"input": "[1]", "expected": "[1]"}, {"input": "[10, 3, 7, 1]", "expected": "[10, 7, 3, 1]"}, ], "error_type": "LogicError", "hint": "sorted() returns ascending order by default; pass reverse=True for descending.", }, # 14 { "id": "bug_014", "difficulty": "medium", "title": "Missing edge case for empty list", "description": "Fix the function that returns the max of a list — it crashes on empty input.", "buggy_code": ( "def safe_max(lst):\n" " return max(lst)\n" ), "fixed_code": ( "def safe_max(lst):\n" " if not lst:\n" " return None\n" " return max(lst)\n" ), "test_cases": [ {"input": "[]", "expected": "None"}, {"input": "[3]", "expected": "3"}, {"input": "[1, 5, 2]", "expected": "5"}, {"input": "[-1, -3, -2]", "expected": "-1"}, ], "error_type": "ValueError", "hint": "max() raises ValueError on an empty sequence; guard with an empty-list check.", }, # 15 { "id": "bug_015", "difficulty": "medium", "title": "Wrong string format (% vs .format)", "description": "Fix the function that formats a greeting using .format().", "buggy_code": ( "def greet(name, age):\n" " return 'Hello %s, you are %d years old' % (name,)\n" ), "fixed_code": ( "def greet(name, age):\n" " return 'Hello {}, you are {} years old'.format(name, age)\n" ), "test_cases": [ {"input": "'Alice', 30", "expected": "Hello Alice, you are 30 years old"}, {"input": "'Bob', 25", "expected": "Hello Bob, you are 25 years old"}, {"input": "'Z', 1", "expected": "Hello Z, you are 1 years old"}, {"input": "'Dev', 99", "expected": "Hello Dev, you are 99 years old"}, ], "error_type": "TypeError", "hint": "The % format string has two placeholders but only one argument is passed.", }, # 16 { "id": "bug_016", "difficulty": "medium", "title": "Wrong dictionary key access", "description": "Fix the function that retrieves a value from a dict safely.", "buggy_code": ( "def get_value(d, key):\n" " return d[key]\n" ), "fixed_code": ( "def get_value(d, key):\n" " return d.get(key, None)\n" ), "test_cases": [ {"input": "{'a': 1}, 'a'", "expected": "1"}, {"input": "{'b': 2}, 'x'", "expected": "None"}, {"input": "{}, 'k'", "expected": "None"}, {"input": "{'z': 0}, 'z'", "expected": "0"}, ], "error_type": "KeyError", "hint": "Use dict.get(key, default) to avoid KeyError on missing keys.", }, # 17 { "id": "bug_017", "difficulty": "medium", "title": "Wrong boolean logic (and vs or)", "description": "Fix the function that returns True only when both flags are True.", "buggy_code": ( "def both_true(a, b):\n" " return a or b\n" ), "fixed_code": ( "def both_true(a, b):\n" " return a and b\n" ), "test_cases": [ {"input": "True, True", "expected": "True"}, {"input": "True, False", "expected": "False"}, {"input": "False, True", "expected": "False"}, {"input": "False, False", "expected": "False"}, ], "error_type": "LogicError", "hint": "`or` returns True if either is True; use `and` to require both.", }, # 18 { "id": "bug_018", "difficulty": "medium", "title": "Wrong range bounds (range(n) vs range(n+1))", "description": "Fix the function that sums integers from 0 to n inclusive.", "buggy_code": ( "def sum_to_n(n):\n" " return sum(range(n))\n" ), "fixed_code": ( "def sum_to_n(n):\n" " return sum(range(n + 1))\n" ), "test_cases": [ {"input": "5", "expected": "15"}, {"input": "0", "expected": "0"}, {"input": "1", "expected": "1"}, {"input": "10", "expected": "55"}, ], "error_type": "LogicError", "hint": "range(n) stops before n; use range(n+1) to include n.", }, # 19 { "id": "bug_019", "difficulty": "medium", "title": "Missing int() type conversion", "description": "Fix the function that reads a number from a string and doubles it.", "buggy_code": ( "def double_str(s):\n" " return s * 2\n" ), "fixed_code": ( "def double_str(s):\n" " return int(s) * 2\n" ), "test_cases": [ {"input": "'5'", "expected": "10"}, {"input": "'0'", "expected": "0"}, {"input": "'3'", "expected": "6"}, {"input": "'21'", "expected": "42"}, ], "error_type": "TypeError", "hint": "Multiplying a string by 2 repeats it; convert to int first.", }, # 20 { "id": "bug_020", "difficulty": "medium", "title": "Wrong list slicing ([1:] vs [:1])", "description": "Fix the function that returns all elements except the first.", "buggy_code": ( "def tail(lst):\n" " return lst[:1]\n" ), "fixed_code": ( "def tail(lst):\n" " return lst[1:]\n" ), "test_cases": [ {"input": "[1, 2, 3]", "expected": "[2, 3]"}, {"input": "[10]", "expected": "[]"}, {"input": "[5, 6, 7, 8]", "expected": "[6, 7, 8]"}, {"input": "[0, 0]", "expected": "[0]"}, ], "error_type": "LogicError", "hint": "lst[:1] returns only the first element; lst[1:] skips it.", }, ] # ═══════════════════════════════════════════════════════════════ # HARD BUGS (21–30) # ═══════════════════════════════════════════════════════════════ HARD_BUGS = [ # 21 { "id": "bug_021", "difficulty": "hard", "title": "Binary search off-by-one in mid update", "description": "Fix the binary search that infinite-loops when the target is absent.", "buggy_code": ( "def binary_search(arr, target):\n" " lo, hi = 0, len(arr) - 1\n" " while lo <= hi:\n" " mid = (lo + hi) // 2\n" " if arr[mid] == target:\n" " return mid\n" " elif arr[mid] < target:\n" " lo = mid\n" " else:\n" " hi = mid\n" " return -1\n" ), "fixed_code": ( "def binary_search(arr, target):\n" " lo, hi = 0, len(arr) - 1\n" " while lo <= hi:\n" " mid = (lo + hi) // 2\n" " if arr[mid] == target:\n" " return mid\n" " elif arr[mid] < target:\n" " lo = mid + 1\n" " else:\n" " hi = mid - 1\n" " return -1\n" ), "test_cases": [ {"input": "[1, 2, 3, 4, 5], 3", "expected": "2"}, {"input": "[1, 2, 3, 4, 5], 6", "expected": "-1"}, {"input": "[10, 20, 30], 10", "expected": "0"}, {"input": "[7], 7", "expected": "0"}, ], "error_type": "InfiniteLoop", "hint": "lo and hi must actually shrink: use mid+1 and mid-1.", }, # 22 { "id": "bug_022", "difficulty": "hard", "title": "Wrong DP state transition (Fibonacci)", "description": "Fix the DP Fibonacci that stores the wrong value at each step.", "buggy_code": ( "def fib_dp(n):\n" " if n <= 1:\n" " return n\n" " dp = [0] * (n + 1)\n" " dp[1] = 1\n" " for i in range(2, n + 1):\n" " dp[i] = dp[i - 1] + dp[i - 1]\n" " return dp[n]\n" ), "fixed_code": ( "def fib_dp(n):\n" " if n <= 1:\n" " return n\n" " dp = [0] * (n + 1)\n" " dp[1] = 1\n" " for i in range(2, n + 1):\n" " dp[i] = dp[i - 1] + dp[i - 2]\n" " return dp[n]\n" ), "test_cases": [ {"input": "0", "expected": "0"}, {"input": "1", "expected": "1"}, {"input": "6", "expected": "8"}, {"input": "10", "expected": "55"}, ], "error_type": "LogicError", "hint": "Fibonacci recurrence is dp[i-1] + dp[i-2], not dp[i-1] + dp[i-1].", }, # 23 { "id": "bug_023", "difficulty": "hard", "title": "Wrong graph traversal: visited check in wrong place", "description": "Fix BFS that revisits nodes because it marks them visited too late.", "buggy_code": ( "from collections import deque\n" "def bfs_count(graph, start):\n" " visited = set()\n" " queue = deque([start])\n" " count = 0\n" " while queue:\n" " node = queue.popleft()\n" " if node in visited:\n" " continue\n" " visited.add(node)\n" " count += 1\n" " for nb in graph.get(node, []):\n" " queue.append(nb)\n" " return count\n" ), "fixed_code": ( "from collections import deque\n" "def bfs_count(graph, start):\n" " visited = set([start])\n" " queue = deque([start])\n" " count = 0\n" " while queue:\n" " node = queue.popleft()\n" " count += 1\n" " for nb in graph.get(node, []):\n" " if nb not in visited:\n" " visited.add(nb)\n" " queue.append(nb)\n" " return count\n" ), "test_cases": [ {"input": "{0:[1,2],1:[],2:[]}, 0", "expected": "3"}, {"input": "{0:[1],1:[0]}, 0", "expected": "2"}, {"input": "{0:[]}, 0", "expected": "1"}, {"input": "{0:[1,2],1:[2],2:[0]}, 0", "expected": "3"}, ], "error_type": "LogicError", "hint": "Mark nodes visited when enqueuing, not when dequeuing.", }, # 24 { "id": "bug_024", "difficulty": "hard", "title": "Missing memoization causing exponential recursion", "description": "Fix the recursive function that recomputes overlapping subproblems.", "buggy_code": ( "def fib_memo(n, memo={}):\n" " if n <= 1:\n" " return n\n" " return fib_memo(n - 1) + fib_memo(n - 2)\n" ), "fixed_code": ( "def fib_memo(n, memo={}):\n" " if n <= 1:\n" " return n\n" " if n in memo:\n" " return memo[n]\n" " memo[n] = fib_memo(n - 1, memo) + fib_memo(n - 2, memo)\n" " return memo[n]\n" ), "test_cases": [ {"input": "0", "expected": "0"}, {"input": "1", "expected": "1"}, {"input": "10", "expected": "55"}, {"input": "20", "expected": "6765"}, ], "error_type": "LogicError", "hint": "Check memo before recursing and store the result after computing.", }, # 25 { "id": "bug_025", "difficulty": "hard", "title": "Wrong two-pointer movement direction", "description": "Fix two-pointer sum that moves the wrong pointer.", "buggy_code": ( "def two_sum_sorted(arr, target):\n" " lo, hi = 0, len(arr) - 1\n" " while lo < hi:\n" " s = arr[lo] + arr[hi]\n" " if s == target:\n" " return [lo, hi]\n" " elif s < target:\n" " hi -= 1\n" " else:\n" " lo += 1\n" " return []\n" ), "fixed_code": ( "def two_sum_sorted(arr, target):\n" " lo, hi = 0, len(arr) - 1\n" " while lo < hi:\n" " s = arr[lo] + arr[hi]\n" " if s == target:\n" " return [lo, hi]\n" " elif s < target:\n" " lo += 1\n" " else:\n" " hi -= 1\n" " return []\n" ), "test_cases": [ {"input": "[1, 2, 3, 4, 6], 6", "expected": "[1, 3]"}, {"input": "[1, 3, 5, 7], 8", "expected": "[0, 3]"}, {"input": "[1, 2], 3", "expected": "[0, 1]"}, {"input": "[1, 2, 3], 10", "expected": "[]"}, ], "error_type": "LogicError", "hint": "Sum too small → move lo up (increase); sum too large → move hi down.", }, # 26 { "id": "bug_026", "difficulty": "hard", "title": "Wrong greedy choice (min vs max)", "description": "Fix the greedy function that should pick the largest item that fits.", "buggy_code": ( "def greedy_knapsack(weights, capacity):\n" " weights = sorted(weights)\n" " total = 0\n" " for w in weights:\n" " if total + w <= capacity:\n" " total += w\n" " return total\n" ), "fixed_code": ( "def greedy_knapsack(weights, capacity):\n" " weights = sorted(weights, reverse=True)\n" " total = 0\n" " for w in weights:\n" " if total + w <= capacity:\n" " total += w\n" " return total\n" ), "test_cases": [ {"input": "[4, 3, 1], 5", "expected": "5"}, {"input": "[1, 2, 3], 4", "expected": "4"}, {"input": "[5], 5", "expected": "5"}, {"input": "[3, 3, 3], 6", "expected": "6"}, ], "error_type": "LogicError", "hint": "Sort descending to pick heaviest items first for max fill.", }, # 27 { "id": "bug_027", "difficulty": "hard", "title": "Off-by-one in sliding window boundary", "description": "Fix the sliding window that computes max sum of k consecutive elements.", "buggy_code": ( "def max_window_sum(arr, k):\n" " window = sum(arr[:k])\n" " best = window\n" " for i in range(1, len(arr) - k):\n" " window += arr[i + k - 1] - arr[i - 1]\n" " best = max(best, window)\n" " return best\n" ), "fixed_code": ( "def max_window_sum(arr, k):\n" " window = sum(arr[:k])\n" " best = window\n" " for i in range(1, len(arr) - k + 1):\n" " window += arr[i + k - 1] - arr[i - 1]\n" " best = max(best, window)\n" " return best\n" ), "test_cases": [ {"input": "[1, 3, -1, -3, 5, 3], 3", "expected": "5"}, {"input": "[2, 1, 5, 1, 3, 2], 3", "expected": "9"}, {"input": "[1, 2, 3], 2", "expected": "5"}, {"input": "[5], 1", "expected": "5"}, ], "error_type": "LogicError", "hint": "The range should go to len(arr)-k+1 to include the last window.", }, # 28 { "id": "bug_028", "difficulty": "hard", "title": "Wrong merge logic in merge sort", "description": "Fix the merge step that uses the wrong comparison operator.", "buggy_code": ( "def merge(left, right):\n" " result = []\n" " i = j = 0\n" " while i < len(left) and j < len(right):\n" " if left[i] > right[j]:\n" " result.append(left[i])\n" " i += 1\n" " else:\n" " result.append(right[j])\n" " j += 1\n" " result.extend(left[i:])\n" " result.extend(right[j:])\n" " return result\n" ), "fixed_code": ( "def merge(left, right):\n" " result = []\n" " i = j = 0\n" " while i < len(left) and j < len(right):\n" " if left[i] <= right[j]:\n" " result.append(left[i])\n" " i += 1\n" " else:\n" " result.append(right[j])\n" " j += 1\n" " result.extend(left[i:])\n" " result.extend(right[j:])\n" " return result\n" ), "test_cases": [ {"input": "[1, 3], [2, 4]", "expected": "[1, 2, 3, 4]"}, {"input": "[1], [2]", "expected": "[1, 2]"}, {"input": "[], [1, 2]", "expected": "[1, 2]"}, {"input": "[1, 2], []", "expected": "[1, 2]"}, ], "error_type": "LogicError", "hint": "Use <= to keep the merge stable and ascending.", }, # 29 { "id": "bug_029", "difficulty": "hard", "title": "Wrong heap operation (push vs pop)", "description": "Fix the function that finds the k-th largest element using a min-heap.", "buggy_code": ( "import heapq\n" "def kth_largest(nums, k):\n" " heap = []\n" " for n in nums:\n" " heapq.heappush(heap, n)\n" " if len(heap) > k:\n" " heapq.heappush(heap, heapq.heappop(heap))\n" " return heap[0]\n" ), "fixed_code": ( "import heapq\n" "def kth_largest(nums, k):\n" " heap = []\n" " for n in nums:\n" " heapq.heappush(heap, n)\n" " if len(heap) > k:\n" " heapq.heappop(heap)\n" " return heap[0]\n" ), "test_cases": [ {"input": "[3, 2, 1, 5, 6, 4], 2", "expected": "5"}, {"input": "[3, 2, 3, 1, 2, 4, 5, 5, 6], 4", "expected": "4"}, {"input": "[1], 1", "expected": "1"}, {"input": "[5, 4, 3, 2, 1], 3", "expected": "3"}, ], "error_type": "LogicError", "hint": "When the heap exceeds k elements just pop (remove smallest), don't re-push.", }, # 30 { "id": "bug_030", "difficulty": "hard", "title": "Wrong backtracking: missing undo step", "description": "Fix the backtracking permutation generator that forgets to un-choose.", "buggy_code": ( "def permutations(nums):\n" " result = []\n" " def backtrack(path, remaining):\n" " if not remaining:\n" " result.append(path[:])\n" " return\n" " for i in range(len(remaining)):\n" " path.append(remaining[i])\n" " backtrack(path, remaining[:i] + remaining[i+1:])\n" " backtrack([], nums)\n" " return sorted(result)\n" ), "fixed_code": ( "def permutations(nums):\n" " result = []\n" " def backtrack(path, remaining):\n" " if not remaining:\n" " result.append(path[:])\n" " return\n" " for i in range(len(remaining)):\n" " path.append(remaining[i])\n" " backtrack(path, remaining[:i] + remaining[i+1:])\n" " path.pop()\n" " backtrack([], nums)\n" " return sorted(result)\n" ), "test_cases": [ {"input": "[1, 2]", "expected": "[[1, 2], [2, 1]]"}, {"input": "[1]", "expected": "[[1]]"}, {"input": "[1, 2, 3]", "expected": "[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]"}, {"input": "[3, 1]", "expected": "[[1, 3], [3, 1]]"}, ], "error_type": "LogicError", "hint": "After each recursive call, pop the last element to undo the choice.", }, ] # ═══════════════════════════════════════════════════════════════ # Module-level exports # ═══════════════════════════════════════════════════════════════ ALL_PROBLEMS = EASY_BUGS + MEDIUM_BUGS + HARD_BUGS TRAINING_SCENARIOS = sorted( ALL_PROBLEMS, key=lambda x: ["easy", "medium", "hard"].index(x["difficulty"]), ) BUG_DATASET = ALL_PROBLEMS # backward-compat alias # ── Helper functions ──────────────────────────────────────────── def get_problem(problem_id: str) -> dict | None: """Return a single problem by ID, or None if not found.""" for p in ALL_PROBLEMS: if p["id"] == problem_id: return p return None def get_all_problems() -> list[dict]: """Return all 30 problems.""" return ALL_PROBLEMS def get_problem_ids() -> list[str]: """Return all problem IDs in order.""" return [p["id"] for p in ALL_PROBLEMS] def get_problems_by_difficulty(difficulty: str) -> list[dict]: """Return problems filtered by difficulty ('easy'|'medium'|'hard').""" return [p for p in ALL_PROBLEMS if p["difficulty"] == difficulty]