from common import *
from fractions import Fraction as F
R = lambda r,a,b: r.randint(a,b)
def g(x):
    x=F(x); 
    return str(x.numerator) if x.denominator==1 else (f"{float(x):.2f}".rstrip("0").rstrip("."))
# ---------------- PHYSICS ----------------
P = Bank("physics", seed=31)
def p_speed(r):
    d,t=R(r,2,60)*10,R(r,2,20)
    if d%t: return False
    v=d//t; return P.add(f"A body covers {d} m in {t} s at constant speed. Find its speed.", f"{v} m/s", [f"{x} m/s" for x in (v*t//2 if v*t//2 else v+4,v+t,d*t if d*t!=v else 3,v-1)],"Motion","Easy")
def p_accel(r):
    u,v,t=R(r,0,20),R(r,25,80),R(r,2,10)
    if (v-u)%t: return False
    a=(v-u)//t; return P.add(f"A car accelerates uniformly from {u} m/s to {v} m/s in {t} s. Find its acceleration.", f"{a} m/s²", [f"{x} m/s²" for x in (a+1,a*t,a+2,max(a-1,0.5))],"Motion")
def p_suvat(r):
    u,a,t=R(r,0,12),R(r,1,6),R(r,2,9); s=u*t+F(a*t*t,2)
    return P.add(f"A body starts with velocity {u} m/s and accelerates uniformly at {a} m/s² for {t} s. Find the distance covered.", f"{g(s)} m", [f"{g(x)} m" for x in (u*t+a*t*t,u*t,s+a,F(a*t*t,2))],"Motion","Medium")
def p_force(r):
    m,a=R(r,2,60),R(r,1,12)
    return P.add(f"What force is needed to give a mass of {m} kg an acceleration of {a} m/s²?", f"{m*a} N", [f"{x} N" for x in (m+a,m*a*10,m*a+m,m*a-a)],"Dynamics","Easy")
def p_weight(r):
    m=R(r,2,90); return P.add(f"Calculate the weight of a body of mass {m} kg. (g = 10 m/s²)", f"{m*10} N", [f"{x} N" for x in (m,m*100,m*9,m+10)],"Dynamics","Easy")
def p_work(r):
    f,d=R(r,2,90),R(r,2,40); return P.add(f"A force of {f} N moves a body {d} m in the direction of the force. Calculate the work done.", f"{f*d} J", [f"{x} J" for x in (f+d,f*d*2,f*d//2 if f*d%2==0 else f*d+3,f*d+f)],"Work, Energy and Power","Easy")
def p_power(r):
    w,t=R(r,2,60)*100,R(r,2,20)
    if w%t: return False
    return P.add(f"A machine does {w} J of work in {t} s. What is its power?", f"{w//t} W", [f"{x} W" for x in (w*t,w//t+t,w//t*2,w//t-t if w//t>t else w//t+10)],"Work, Energy and Power")
def p_ke(r):
    m,v=R(r,1,20)*2,R(r,2,15); return P.add(f"Calculate the kinetic energy of a {m} kg body moving at {v} m/s.", f"{m*v*v//2} J", [f"{x} J" for x in (m*v*v,m*v,m*v//2,m*v*v//4 if m*v*v%4==0 else m*v*v//2+7)],"Work, Energy and Power","Medium")
def p_pe(r):
    m,h=R(r,1,60),R(r,2,50); return P.add(f"Find the potential energy of a {m} kg mass raised through {h} m. (g = 10 m/s²)", f"{m*h*10} J", [f"{x} J" for x in (m*h,m*h*100,m*h*9,m*h*10+m)],"Work, Energy and Power","Easy")
def p_ohm(r):
    i,rr=R(r,1,10),R(r,2,40); return P.add(f"A current of {i} A flows through a resistor of {rr} Ω. Find the potential difference across it.", f"{i*rr} V", [f"{x} V" for x in (i+rr,rr*rr,i*rr*2,i*rr+i)],"Current Electricity","Easy")
def p_series(r):
    a,b=R(r,2,30),R(r,2,30); return P.add(f"Two resistors of {a} Ω and {b} Ω are connected in series. Find the total resistance.", f"{a+b} Ω", [f"{g(F(a*b,a+b))} Ω",f"{a*b} Ω",f"{abs(a-b)} Ω",f"{a+b+1} Ω"],"Current Electricity","Easy")
def p_par(r):
    a=r.choice([2,3,4,6,8,10,12]); b=r.choice([2,3,4,6,8,10,12,15,20,30]); 
    if a==b or (a*b)%(a+b): return False
    v=a*b//(a+b); return P.add(f"Two resistors of {a} Ω and {b} Ω are connected in parallel. Find their effective resistance.", f"{v} Ω", [f"{a+b} Ω",f"{a*b} Ω",f"{v+1} Ω",f"{abs(a-b)} Ω"],"Current Electricity","Medium")
def p_elec_energy(r):
    pw,t=R(r,1,20)*100,R(r,1,10); return P.add(f"A {pw} W heater is used for {t} hours. How many kilowatt-hours of energy does it consume?", f"{g(F(pw*t,1000))} kWh", [f"{g(F(pw*t,100))} kWh",f"{pw*t} kWh",f"{g(F(pw,1000)+t)} kWh",f"{g(F(pw*t,10000))} kWh"],"Current Electricity","Medium")
def p_density(r):
    m,v=R(r,2,60)*10,R(r,2,30)
    if m%v: return False
    d=m//v; return P.add(f"A body has mass {m} g and volume {v} cm³. Find its density.", f"{d} g/cm³", [f"{x} g/cm³" for x in (m*v,d+1,d*2,max(d-1,1))],"Density and Pressure","Easy")
def p_pressure(r):
    f,a=R(r,2,60)*10,R(r,2,20)
    if f%a: return False
    p=f//a; return P.add(f"A force of {f} N acts on an area of {a} m². Calculate the pressure.", f"{p} Pa", [f"{x} Pa" for x in (f*a,p+a,p*2,max(p-a,1))],"Density and Pressure","Easy")
def p_wave(r):
    f,l=R(r,2,50)*10,R(r,1,10); return P.add(f"A wave has frequency {f} Hz and wavelength {l} m. Find its speed.", f"{f*l} m/s", [f"{x} m/s" for x in (f+l,f//l if f%l==0 else f*l+7,f*l*2,f*l-l)],"Waves","Easy")
def p_period(r):
    f=r.choice([2,4,5,10,20,25,50]); return P.add(f"A source vibrates with frequency {f} Hz. What is its period?", f"{g(F(1,f))} s", [f"{f} s",f"{g(F(f,2))} s",f"{g(F(1,f*2))} s",f"{g(F(2,f))} s"],"Waves","Easy")
def p_heat(r):
    m,c,t=R(r,1,20),R(r,2,9)*100,R(r,5,60); return P.add(f"How much heat is needed to raise the temperature of {m} kg of a substance of specific heat capacity {c} J/(kg·K) by {t} K?", f"{m*c*t} J", [f"{x} J" for x in (m*c+t,m*c*t*2,c*t,m*t)],"Heat","Medium")
def p_latent(r):
    m,l=R(r,1,10),R(r,2,30)*10000; return P.add(f"Find the energy required to melt {m} kg of a solid at its melting point if its specific latent heat of fusion is {l} J/kg.", f"{m*l} J", [f"{x} J" for x in (l//m if l%m==0 else l+m,m*l*10,m*l+l,l)],"Heat","Medium")
def p_lens(r):
    f=r.choice([5,10,15,20,25,30]); u=R(r,2,5)*f//1; 
    v=F(u*f,u-f) if u!=f else None
    if v is None or v.denominator!=1: return False
    return P.add(f"An object is placed {u} cm from a converging lens of focal length {f} cm. Find the image distance.", f"{v} cm", [f"{x} cm" for x in (u+f,u-f,v+f,f)],"Light","Hard")
def p_mom(r):
    m,v=R(r,1,60),R(r,2,30); return P.add(f"Find the momentum of a {m} kg body moving at {v} m/s.", f"{m*v} kg m/s", [f"{x} kg m/s" for x in (m+v,m*v*2,m*v//2 if m*v%2==0 else m*v+5,m*v+m)],"Dynamics","Easy")
def p_eff(r):
    inp,pct=R(r,2,40)*100,r.choice([20,25,40,50,60,75,80]); out=inp*pct//100
    return P.add(f"A machine receives {inp} J of energy and delivers {out} J as useful output. Find its efficiency.", f"{pct}%", [f"{x}%" for x in (pct+10,pct-10,100-pct,pct//2)],"Work, Energy and Power","Easy")
def p_vr(r):
    l,e=R(r,2,12)*5,R(r,1,10)*5; 
    return P.add(f"In a lever system the load is {l*2} N and the effort is {e*2} N. Calculate the mechanical advantage.", g(F(l,e)), [g(F(e,l)),g(F(l,e)+1),g(F(l*e,10)),g(F(l+e,e))],"Simple Machines","Medium")
P_temps=[p_speed,p_accel,p_suvat,p_force,p_weight,p_work,p_power,p_ke,p_pe,p_ohm,p_series,p_par,p_elec_energy,p_density,p_pressure,p_wave,p_period,p_heat,p_latent,p_lens,p_mom,p_eff,p_vr]

# ---------------- CHEMISTRY ----------------
C = Bank("chemistry", seed=41)
AM={"H":1,"C":12,"N":14,"O":16,"Na":23,"Mg":24,"Al":27,"S":32,"Cl":35.5,"K":39,"Ca":40,"Fe":56,"Cu":64,"Zn":65}
def mm(f):
    return sum(AM[e]*n for e,n in f)
cmp_=[("NaCl",[("Na",1),("Cl",1)]),("H₂O",[("H",2),("O",1)]),("CO₂",[("C",1),("O",2)]),("CaCO₃",[("Ca",1),("C",1),("O",3)]),("H₂SO₄",[("H",2),("S",1),("O",4)]),("NaOH",[("Na",1),("O",1),("H",1)]),("HCl",[("H",1),("Cl",1)]),("MgO",[("Mg",1),("O",1)]),("NH₃",[("N",1),("H",3)]),("CH₄",[("C",1),("H",4)]),("KOH",[("K",1),("O",1),("H",1)]),("CuSO₄",[("Cu",1),("S",1),("O",4)]),("Al₂O₃",[("Al",2),("O",3)]),("ZnO",[("Zn",1),("O",1)]),("Fe₂O₃",[("Fe",2),("O",3)]),("CaO",[("Ca",1),("O",1)]),("HNO₃",[("H",1),("N",1),("O",3)]),("Na₂CO₃",[("Na",2),("C",1),("O",3)]),("MgSO₄",[("Mg",1),("S",1),("O",4)]),("C₂H₅OH",[("C",2),("H",6),("O",1)])]
def gm(x): return f"{x:g}"
def c_molmass(r):
    n,f=r.choice(cmp_); v=mm(f); return C.add(f"Calculate the relative molecular mass of {n}. (H = 1, C = 12, N = 14, O = 16, Na = 23, Mg = 24, Al = 27, S = 32, Cl = 35.5, K = 39, Ca = 40, Fe = 56, Cu = 64, Zn = 65)", gm(v), [gm(v+d) for d in (2,-2,16,-16,1,4)],"Mole Concept","Easy")
def c_moles(r):
    n,f=r.choice(cmp_); M=mm(f); k=R(r,1,10); 
    if (M*k)!=int(M*k): return False
    return C.add(f"How many moles are contained in {gm(M*k)} g of {n}? (Molar mass = {gm(M)} g/mol)", k, [x for x in (k+1,k*2,max(k-1,0.5),F(k,2) if k%2 else k+2)],"Mole Concept")
def c_mass(r):
    n,f=r.choice(cmp_); M=mm(f); k=R(r,1,8)/2; v=M*k
    return C.add(f"Calculate the mass of {gm(k)} mole(s) of {n}. (Molar mass = {gm(M)} g/mol)", f"{gm(v)} g", [f"{gm(x)} g" for x in (M+k,M/k if k else M,v+M,v*2)],"Mole Concept")
def c_conc(r):
    n,f=r.choice([x for x in cmp_ if x[0] in ("NaCl","H₂SO₄","NaOH","HCl","KOH","CuSO₄","HNO₃","Na₂CO₃","MgSO₄")]); M=mm(f); c=R(r,1,4)/2; V=R(r,1,5)/2; m=M*c*V
    return C.add(f"What mass of {n} (molar mass {gm(M)} g/mol) is needed to prepare {gm(V)} dm³ of a {gm(c)} mol/dm³ solution?", f"{gm(m)} g", [f"{gm(x)} g" for x in (M*c,M*V,m*2,m+M)],"Solutions","Hard")
def c_molarity(r):
    mol,V=R(r,1,10)/2,R(r,1,10)/2; return C.add(f"{gm(mol)} mole of a solute is dissolved in {gm(V)} dm³ of solution. Find the concentration in mol/dm³.", gm(round(mol/V,3)), [gm(round(x,3)) for x in (mol*V,mol/V+0.5,V/mol,mol+V)],"Solutions")
def c_dilution(r):
    c1,v1,v2=R(r,2,10),R(r,1,5)*10,R(r,2,8)*10
    if v2<=v1 or (c1*v1)%v2: return False
    return C.add(f"{v1} cm³ of {c1} mol/dm³ acid is diluted to {v2} cm³. Find the new concentration (mol/dm³).", c1*v1//v2, [c1*v2//v1 if (c1*v2)%v1==0 else c1+3,c1+1,c1*v1//v2+1,c1],"Solutions","Medium")
def c_ph(r):
    n=R(r,1,13); return C.add(f"A solution has hydrogen ion concentration 1 × 10^−{n} mol/dm³. What is its pH?", n, [x for x in (14-n,n+1,n-1 if n>1 else 8,7)],"Acids, Bases and Salts","Medium")
def c_gas(r):
    n=R(r,1,6); return C.add(f"What volume does {n} mole(s) of any gas occupy at s.t.p.? (Molar volume = 22.4 dm³)", f"{gm(round(22.4*n,1))} dm³", [f"{gm(round(x,1))} dm³" for x in (24*n,22.4*n+22.4,11.2*n,22.4/n if n>1 else 44.8)],"Gas Laws","Easy")
def c_charles(r):
    v1,t1,t2=R(r,1,10)*100,R(r,2,5)*100,R(r,6,10)*100; v2=F(v1*t2,t1)
    return C.add(f"A gas occupies {v1} cm³ at {t1} K. Find its volume at {t2} K at constant pressure.", f"{g(v2)} cm³", [f"{g(x)} cm³" for x in (F(v1*t1,t2),v1+t2-t1,v1*(t2-t1)//t1 if True else 0,v2+t1)],"Gas Laws","Medium")
def c_boyle(r):
    p1,v1,p2=R(r,1,6)*100,R(r,2,10)*10,R(r,2,5)*100
    v2=F(p1*v1,p2); return C.add(f"A gas has volume {v1} cm³ at pressure {p1} kPa. What is its volume at {p2} kPa (constant temperature)?", f"{g(v2)} cm³", [f"{g(x)} cm³" for x in (F(p2*v1,p1),v1+p2-p1 if v1+p2-p1>0 else v1+9,v2+v1,v1*2)],"Gas Laws","Medium")
def c_atom(r):
    p,n=R(r,3,30),R(r,3,35); return C.add(f"An atom has {p} protons and {n} neutrons. What is its mass number?", p+n, [p,n,abs(p-n)+1 if p!=n else p+7,p+n+1],"Atomic Structure","Easy")
def c_neutron(r):
    z,a=R(r,3,30),R(r,32,70); return C.add(f"An element has atomic number {z} and mass number {a}. How many neutrons does it have?", a-z, [a+z,z,a,a-z+1],"Atomic Structure","Easy")
def c_elec(r):
    el=r.choice([("sodium",11,"2, 8, 1"),("chlorine",17,"2, 8, 7"),("magnesium",12,"2, 8, 2"),("aluminium",13,"2, 8, 3"),("oxygen",8,"2, 6"),("carbon",6,"2, 4"),("nitrogen",7,"2, 5"),("sulphur",16,"2, 8, 6"),("potassium",19,"2, 8, 8, 1"),("calcium",20,"2, 8, 8, 2"),("fluorine",9,"2, 7"),("neon",10,"2, 8"),("lithium",3,"2, 1"),("phosphorus",15,"2, 8, 5"),("silicon",14,"2, 8, 4"),("argon",18,"2, 8, 8")])
    pool=[x for x in ("2, 8, 1","2, 8, 7","2, 8, 2","2, 8, 3","2, 6","2, 4","2, 5","2, 8, 6","2, 8, 8, 1","2, 7","2, 8","2, 1","2, 8, 5","2, 8, 4","2, 8, 8") if x!=el[2]]; r.shuffle(pool)
    return C.add(f"What is the electronic configuration of {el[0]} (atomic number {el[1]})?", el[2], pool[:3],"Atomic Structure","Easy")
def c_titr(r):
    ca,va,vb=R(r,1,4)/10,R(r,10,25),R(r,10,25); cb=ca*va/vb
    return C.add(f"In a titration, {va} cm³ of {gm(ca)} mol/dm³ HCl neutralised {vb} cm³ of NaOH solution (HCl + NaOH → NaCl + H₂O). Find the concentration of the NaOH (mol/dm³).", f"{cb:.3f}", [f"{x:.3f}" for x in (ca*vb/va,ca+va/vb/10,cb*2,cb+0.1)],"Acids, Bases and Salts","Hard")
def c_percent(r):
    n,f=r.choice(cmp_[:10]); M=mm(f); e,k=f[0]; v=AM[e]*k/M*100
    return C.add(f"Calculate the percentage by mass of {e} in {n}. ({', '.join(f'{x} = {gm(y)}' for x,y in AM.items() if x in {a for a,_ in f})})", f"{v:.1f}%", [f"{x:.1f}%" for x in (100-v,v/2,v+10,v-8)],"Mole Concept","Hard")
C_temps=[c_molmass,c_moles,c_mass,c_conc,c_molarity,c_dilution,c_ph,c_gas,c_charles,c_boyle,c_atom,c_neutron,c_elec,c_titr,c_percent]
if __name__=="__main__":
    for t in P_temps: P.fill(t,100,tries=80)
    for t in C_temps: C.fill(t,100,tries=80)
    print("physics",P.save()); print("chemistry",C.save())
