File size: 2,624 Bytes
3040767
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import random
from typing import Callable, List, Optional, Tuple

def generate(difficulty: int, seed: Optional[int] = None) -> Tuple[str, str]:
    """Generate a Python code execution problem."""
    rng = random.Random(seed) if seed is not None else random
    if difficulty == 1:
        return _level_1(rng)
    if difficulty == 2:
        return _level_2(rng)
    if difficulty == 3:
        return _level_3(rng)
    if difficulty == 4:
        return _level_4(rng)
    if difficulty == 5:
        return _level_5(rng)
    raise ValueError(f"difficulty must be in 1..5, got {difficulty}")

def _run_and_format(code: str, val: int) -> Tuple[str, str]:
    local_env = {}
    exec(code, local_env, local_env)
    f = local_env['f']
    result = f(val)
    if isinstance(result, float) and result.is_integer():
        result = int(result)
    ans = str(result)
    q = f"Given this Python function:\n```python\n{code}\n```\nwhat does f({val}) return?"
    return q, ans

def _level_1(rng) -> Tuple[str, str]:
    val = rng.randint(1, 10)
    c = rng.randint(1, 10)
    code = f"def f(x):\n    return x + {c}"
    return _run_and_format(code, val)

def _level_2(rng) -> Tuple[str, str]:
    val = rng.randint(1, 20)
    c = rng.randint(5, 15)
    op = rng.choice([">", "<", ">=", "<=", "=="])
    ret1 = rng.randint(1, 100)
    ret2 = rng.randint(1, 100)
    code = f"def f(x):\n    if x {op} {c}:\n        return {ret1}\n    else:\n        return {ret2}"
    return _run_and_format(code, val)

def _level_3(rng) -> Tuple[str, str]:
    val = rng.randint(2, 5)
    start = rng.randint(1, 10)
    op = rng.choice(["+", "*"])
    if op == "+":
        code = f"def f(x):\n    total = {start}\n    for i in range(x):\n        total += i\n    return total"
    else:
        code = f"def f(x):\n    total = {start}\n    for i in range(x):\n        total = total * {rng.randint(2, 3)}\n    return total"
    return _run_and_format(code, val)

def _level_4(rng) -> Tuple[str, str]:
    val = rng.randint(3, 6)
    c = rng.randint(2, 5)
    code = f"def f(x):\n    total = 0\n    for i in range(1, x + 1):\n        if i % 2 == 0:\n            total += {c}\n        else:\n            total *= 2\n    return total"
    return _run_and_format(code, val)

def _level_5(rng) -> Tuple[str, str]:
    val = rng.randint(3, 6)
    base = rng.randint(1, 5)
    c = rng.randint(2, 5)
    code1 = f"def f(x):\n    if x <= 0:\n        return {base}\n    return {c} + f(x - 1)"
    code2 = f"def f(x):\n    if x <= 0:\n        return {base}\n    return x * f(x - 1)"
    code = rng.choice([code1, code2])
    return _run_and_format(code, val)