"""Code and multi-step reasoning suite; labels fixed by execution/enumeration before inference."""
import contextlib, io, itertools, json, sqlite3
from fractions import Fraction
from pathlib import Path
cases=[]
def execute(code):
 out=io.StringIO()
 with contextlib.redirect_stdout(out):exec(code,{})
 return out.getvalue().strip()
def add(kind,title,domain,state,answer,proof,options=None):
 if kind=='Choice':
  values=list(options)
  assert str(answer) in values and len(set(values))==len(values)
  # Rotate options independently of their correct answer.
  n=len(cases)%len(values);values=values[n:]+values[:n]
  question={'type':'choice','instructions':'Reason through the problem and select the exact answer. Code follows the specified language semantics.','criteria':{v:None for v in values}}
  expected=str(answer)
 elif kind=='Noul':
  question={'type':'noul','instructions':'Determine whether the stated claim follows from the supplied rules or code. Return the probability that the claim is true.'}
  expected=bool(answer)
 else:
  assert isinstance(answer,int) and 0<=answer<=9
  question={'type':'score','instructions':'Compute the exact integer answer. Use the rubric level with that number; concentrate probability on that level.','criteria':['The exact answer is '+str(i) for i in range(10)]}
  expected=answer
 cases.append({'id':'r'+str(len(cases)+1).zfill(2),'category':kind,'domain':domain,'title':title,'request':{'model':'jev-latest','state':state,'questions':{'decision':question}},'expected':expected,'rationale':proof})
def code_choice(title,code,options):
 result=execute(code)
 add('Choice',title,'Code reasoning',{'language':'Python 3','code':code,'question':'What exactly is printed?'},result,'Reference: execute the complete displayed Python program and capture stdout. Expected stdout: '+result,options)
code_choice('Aliased nested lists','rows = [[0]] * 3\nrows[0].append(2)\nprint([sum(row) for row in rows])',['[2, 0, 0]','[2, 2, 2]','[0, 0, 2]','[6]'])
code_choice('Mutable default across calls','def collect(x, bag=[]):\n    bag.append(x)\n    return bag.copy()\nprint([collect(1), collect(2), collect(3, []), collect(4)])',['[[1], [2], [3], [4]]','[[1], [1, 2], [3], [1, 2, 4]]','[[1, 2, 4], [1, 2, 4], [3], [1, 2, 4]]','[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]'])
code_choice('Closures: bound and unbound','a = [lambda: i for i in range(3)]\nb = [lambda i=i: i for i in range(3)]\nprint([f() for f in a] + [f() for f in b])',['[0, 1, 2, 0, 1, 2]','[2, 2, 2, 2, 2, 2]','[2, 2, 2, 0, 1, 2]','[0, 1, 2, 2, 2, 2]'])
code_choice('A consumed generator','g = (x * x for x in range(5))\na = next(g)\nb = sum(g)\nprint((a, b, list(g)))',['(0, 30, [])','(0, 30, [0, 1, 4, 9, 16])','(1, 29, [])','(0, 14, [16])'])
code_choice('Return value and finally mutation','def f():\n    x = [1]\n    try:\n        return x\n    finally:\n        x.append(2)\n        x = [9]\nprint(f())',['[1]','[1, 2]','[9]','None'])
code_choice('Exception flow through finally','def f():\n    log = []\n    try:\n        log.append("A")\n        raise ValueError()\n    except ValueError:\n        log.append("B")\n        return log\n    finally:\n        log.append("C")\nprint("".join(f()))',['A','AB','ABC','AC'])
solutions=[(a,b,c) for a,b,c in itertools.product([False,True],repeat=3) if a==(not b) and b==(a==c) and c==a]
assert solutions==[(False,True,False)]
add('Choice','Consistent truth-teller assignment','Multi-step logic','Each of A, B and C is either always truthful or always lying. Each makes one statement. A: "B is a liar." B: "A and C are the same type." C: "A is truthful." Who is truthful?', 'B only','Exhaustive enumeration of all 8 type assignments leaves (A=false, B=true, C=false).',['A only','B only','C only','A and C'])
orders=[p for p in itertools.permutations('ABCD') if p.index('A')>p.index('B') and p.index('C')<p.index('A') and p.index('D')==p.index('C')+1 and p.index('B')!=0]
assert orders==[('C','D','B','A')]
add('Choice','Four-person ordering constraints','Multi-step logic','A, B, C and D fill four consecutive slots, one person per slot. A is after B. C is before A. D is immediately after C. B is not first. What is the order from first to last?','C D B A','Exhaustive enumeration of all 24 permutations gives one valid order.',['B C D A','C D B A','C B D A','D C B A'])
code='rows = [[] for _ in range(3)]\nrows[0].append(7)\nprint(rows[1])'
add('Noul','Independent list-comprehension rows','Code reasoning',{'language':'Python 3','code':code,'claim':'The program prints [7].'},execute(code)=='[7]','Executing the displayed program prints []; each row is a separate list.')
code='events = []\ndef fallback():\n    events.append("called")\n    return 99\nd = {"x": 5}\ny = d.get("x", fallback())\nprint(events)'
add('Noul','Eager argument evaluation','Code reasoning',{'language':'Python 3','code':code,'claim':'fallback is called even though the key x exists.'},execute(code)=="['called']",'Executing the program records one call; function arguments are evaluated before get is called.')
code='out = []\nfor x in range(0):\n    out.append("loop")\nelse:\n    out.append("else")\nprint(out)'
add('Noul','Loop else with zero iterations','Code reasoning',{'language':'Python 3','code':code,'claim':'The else block runs.'},execute(code)=="['else']",'Execution prints [\'else\']; no break occurs.')
conn=sqlite3.connect(':memory:');result=conn.execute('WITH t(id) AS (VALUES (1),(2),(3)) SELECT id FROM t WHERE id NOT IN (2,NULL)').fetchall();conn.close()
add('Noul','SQL NULL in NOT IN','Code reasoning',{'language':'SQL (SQLite; ordinary three-valued NULL logic)','query':'WITH t(id) AS (VALUES (1),(2),(3)) SELECT id FROM t WHERE id NOT IN (2,NULL);','claim':'The query returns rows with ids 1 and 3.'},result==[(1,),(3,)],'Executed with SQLite: zero rows. For ids other than 2, NOT IN with NULL is unknown, not true.')
# Nonempty A subset B, B intersects C, but A and C disjoint: search a finite countermodel.
sets=[set(i for i in range(3) if mask&(1<<i)) for mask in range(8)]
counter=next((a,b,c) for a in sets for b in sets for c in sets if a and a<=b and b&c and not a&c)
assert counter
add('Noul','Quantifier inference with existence','Multi-step logic','All A are B. At least one A exists. Some B are C. Claim: these facts logically imply that some A are C.',False,'Countermodel on two objects: A={0}, B={0,1}, C={1}. All premises hold while A and C are disjoint.')
intervals=[(0,3),(2,5),(3,6),(5,7),(6,8)]
max_rooms=max(sum(a<=t<b for a,b in intervals) for t in range(9))
add('Noul','Half-open scheduling intervals','Multi-step logic',{'intervals':intervals,'rules':'Each pair is [start,end). A room can be reused at the exact end time. Every interval must be scheduled without overlap in its room.','claim':'Two rooms are sufficient.'},max_rooms<=2,'Sweep over all integer event times: the maximum overlap is 2; interval partitioning therefore needs 2 rooms.')
final=Fraction(80)*Fraction(125,100)*Fraction(80,100)
add('Noul','Successive percentage changes','Applied reasoning','A product costs $80. Its price is increased by 25%, then the increased price is discounted by 20%. Claim: its final price equals its original price.',final==80,'Exact rational arithmetic: 80×(5/4)×(4/5)=80.')
posterior=Fraction(1,100)*Fraction(9,10)/(Fraction(1,100)*Fraction(9,10)+Fraction(99,100)*Fraction(9,100))
add('Noul','Base rate versus positive result','Applied reasoning','A condition occurs in 1% of a population. A test is positive for 90% of people with the condition and 9% of people without it. A random person tests positive. Claim: the probability this person has the condition is at least 50%.',posterior>=Fraction(1,2),'Bayes with exact fractions: 0.009/(0.009+0.0891) = '+str(posterior)+', below 1/2.')
def code_score(title,code):
 result=int(execute(code));add('Score',title,'Code reasoning',{'language':'Python 3','code':code,'question':'What integer is printed?'},result,'Reference: execute the displayed program and capture the printed integer, '+str(result)+'.')
code_score('Shallow copy versus shared row','a = [[1], [2]]\nb = a.copy()\nb[0].append(3)\nb[1] = [9]\nprint(sum(sum(row) for row in a))')
code_score('Short-circuit side effects','calls = []\ndef f(x):\n    calls.append(x)\n    return x\na = f(0) and f(1)\nb = f(2) or f(3)\nc = f(4) and f(5)\nprint(len(calls))')
code_score('Nested slice order','a = list(range(9))\nb = a[1:8:2][::-1]\nprint(b[0] - b[-1])')
code_score('Shared iterator in zip','it = iter(range(11))\npairs = list(zip(it, it))\nprint(len(pairs))')
cover=[{1,2,3},{3,4},{4,5},{5,6},{1,6}];universe=set(range(1,7))
minimum=next(k for k in range(1,6) if any(set().union(*c)==universe for c in itertools.combinations(cover,k)))
add('Score','Minimum set cover','Multi-step logic',{'sets':[sorted(s) for s in cover],'question':'What is the minimum number of these sets whose union contains all of {1,2,3,4,5,6}?'},minimum,'Enumerate subsets by increasing size and test their union; minimum = '+str(minimum)+'.')
valid=[p for p in itertools.permutations('ABCDE') if p.index('A')<p.index('C') and p.index('B')<p.index('C') and p.index('C')<p.index('D') and p.index('C')<p.index('E')]
add('Score','Counting valid task orders','Multi-step logic','Five distinct tasks A,B,C,D,E each run once in a sequence. A and B must both precede C. C must precede both D and E. How many valid sequences exist?',len(valid),'Enumeration of all 120 permutations leaves 4 sequences: two orders for A/B times two orders for D/E.')
affordable=max(k for k in range(20) if 12*k<=96)
add('Score','Budget after a fixed reservation','Applied reasoning','A lab has $125. It must reserve $29 for shipping. Each complete kit costs $12. Kits cannot be split and shipping is paid only once. What is the maximum number of kits it can buy?',affordable,'Exact integer constraint: floor((125−29)/12)=8.')
pairs=[(a,b) for a in range(1,7) for b in range(1,7) if a+b>=10]
add('Score','Ordered outcomes of two dice','Applied reasoning','Two ordinary six-sided dice are labeled first and second. How many ordered outcomes (first,second) have sum at least 10?',len(pairs),'Enumerate the 36 ordered outcomes: three give sum 10, two give sum 11, one gives sum 12; total 6.')
assert len(cases)==24
assert all(sum(c['category']==t for c in cases)==8 for t in ['Choice','Noul','Score'])
assert sum(c['expected'] is True for c in cases if c['category']=='Noul')==4
Path('scripts').mkdir(exist_ok=True)
Path('scripts/reasoning-cases.json').write_text(json.dumps(cases,indent=2,ensure_ascii=False)+'\n')
print('24 code/reasoning cases generated and checked before evaluation.')
