from common import *
from fractions import Fraction as F
from math import comb, perm, gcd
B = Bank("further_mathematics", seed=21)
R = lambda r,a,b: r.randint(a,b)
def poly(co):  # co: list of (coef, power) highest first
    out=""
    for i,(c,p) in enumerate(co):
        if c==0: continue
        sgn="−" if c<0 else "+"; a=abs(c)
        term=("" if (a==1 and p>0) else str(a))+("x" if p==1 else f"x^{p}" if p>1 else "")
        out+=(("−" if c<0 else "")+term) if not out else f" {sgn} {term}"
    return out
def fmt_signed(n): return f"+ {n}" if n>=0 else f"− {-n}"
def t_diff(r):
    a,b,c=R(r,1,6),R(r,-8,8),R(r,-9,9); n=R(r,2,4)
    d=[(a*n,n-1),(b,0)] if False else None
    f=poly([(a,3),(b,2),(c,1)]); v=f"{3*a}x² {fmt_signed(2*b)}x {fmt_signed(c)}"
    return B.add(f"Differentiate y = {f} with respect to x.", v, [f"{a}x² {fmt_signed(2*b)}x {fmt_signed(c)}",f"{3*a}x² {fmt_signed(b)}x {fmt_signed(c)}",f"{3*a}x² {fmt_signed(2*b)}x",f"{a}x⁴ {fmt_signed(b)}x³ {fmt_signed(c)}x²"],"Calculus")
def t_diffpt(r):
    a,b,x=R(r,1,5),R(r,-6,6),R(r,-3,4); v=2*a*x+b
    return B.add(f"Find the gradient of the curve y = {poly([(a,2),(b,1)])} at x = {x}.", v, near(r,v,[a*x+b,2*a*x,a*x*x+b*x]),"Calculus")
def t_stat(r):
    a,b=R(r,1,4),R(r,-8,8); x=R(r,1,3); 
    return B.add(f"Find the stationary (turning) value of x for y = {poly([(a,2),(b*2*a,1)])}.", -b, [b,-2*b,2*b,-b+1],"Calculus","Hard")
def t_integ(r):
    a,n,u=R(r,1,6),R(r,1,4),R(r,1,3); 
    v=F(a*(u**(n+1)),n+1)
    s=str(v.numerator) if v.denominator==1 else f"{v.numerator}/{v.denominator}"
    ws=[str(x) if x.denominator==1 else f"{x.numerator}/{x.denominator}" for x in (F(a*u**n),F(a*u**(n+1)*(n+1)),v+1,v-F(1,2))]
    return B.add(f"Evaluate the definite integral of {a}x^{n} from 0 to {u}.", s, ws,"Calculus","Hard")
def t_det(r):
    a,b,c,d=R(r,-6,9),R(r,-6,9),R(r,-6,9),R(r,-6,9); v=a*d-b*c
    return B.add(f"Find the determinant of the matrix [[{a}, {b}], [{c}, {d}]].", v, [a*d+b*c,b*c-a*d,a*c-b*d,a+d],"Matrices")
def t_trace(r):
    a,b,c,d,e,f,g,h=[R(r,-4,6) for _ in range(8)]; v=a*e+b*g
    return B.add(f"If P = [[{a}, {b}], [{c}, {d}]] and Q = [[{e}, {f}], [{g}, {h}]], find the element in the first row, first column of PQ.", v, [a*e+c*g,a*e-b*g,a+e+b+g,a*f+b*h],"Matrices","Medium")
def t_dot(r):
    a=[R(r,-5,7) for _ in range(3)]; b=[R(r,-5,7) for _ in range(3)]; v=sum(x*y for x,y in zip(a,b))
    return B.add(f"Find the scalar product of the vectors ({a[0]}, {a[1]}, {a[2]}) and ({b[0]}, {b[1]}, {b[2]}).", v, near(r,v,[a[0]*b[0]+a[1]*b[1],sum(x+y for x,y in zip(a,b))]),"Vectors")
def t_mod(r):
    a,b,c=r.choice([(3,4,5),(6,8,10),(5,12,13),(8,15,17),(9,12,15)])
    return B.add(f"Find the magnitude of the vector {a}i + {b}j.", c, [a+b,c+1,a*b,c-1],"Vectors","Easy")
def t_cplx(r):
    a,b,c,d=R(r,-6,8),R(r,-6,8),R(r,-6,8),R(r,-6,8)
    re,im=a*c-b*d,a*d+b*c
    f=lambda x,y:f"{x} {'+' if y>=0 else '−'} {abs(y)}i"
    return B.add(f"Simplify ({a} {'+' if b>=0 else '−'} {abs(b)}i)({c} {'+' if d>=0 else '−'} {abs(d)}i).", f(re,im), [f(a*c+b*d,a*d+b*c),f(re,a*d-b*c),f(a*c-b*d,a*d-b*c),f(a+c,b+d)],"Complex Numbers","Hard")
def t_i(r):
    n=R(r,2,60); v={0:"1",1:"i",2:"−1",3:"−i"}[n%4]
    return B.add(f"Evaluate i^{n}, where i = √−1.", v, [x for x in ("1","i","−1","−i") if x!=v],"Complex Numbers")
def t_perm(r):
    n,k=R(r,5,12),R(r,2,4); v=perm(n,k)
    return B.add(f"Evaluate ⁿPᵣ with n = {n} and r = {k} (the number of permutations of {n} things taken {k} at a time).", v, [comb(n,k),v+n,n**k,factorial_(n)//factorial_(n-k-1) if n-k-1>=0 else v+1],"Permutation and Combination")
def factorial_(n):
    from math import factorial; return factorial(n)
def t_comb(r):
    n,k=R(r,5,14),R(r,2,4); v=comb(n,k)
    return B.add(f"In how many ways can {k} students be chosen from {n} students?", v, [perm(n,k),v+n,n*k,comb(n,k+1)],"Permutation and Combination")
def t_arr(r):
    w=r.choice([("MATHS",120),("STONE",120),("FRIEND",720),("NIGERIA",5040),("ABUJA",120),("LAGOS",120),("PLANET",720),("SCHOOL",360),("BOOK",12),("LEVEL",30)]); 
    import math
    return B.add(f"In how many ways can the letters of the word {w[0]} be arranged?", w[1], [w[1]*2,w[1]//2,math.factorial(len(w[0])+1),w[1]+len(w[0])],"Permutation and Combination")
def t_binom(r):
    n=R(r,4,9); k=R(r,2,n-2); 
    return B.add(f"What is the coefficient of x^{k} in the expansion of (1 + x)^{n}?", comb(n,k), [comb(n,k)+n,comb(n,k-1)+comb(n,k+1) if comb(n,k-1)+comb(n,k+1)!=comb(n,k) else 7,perm(n,k),n*k],"Binomial Theorem")
def t_gpsum(r):
    a,rr,n=R(r,1,4),R(r,2,3),R(r,3,7); v=a*(rr**n-1)//(rr-1)
    return B.add(f"Find the sum of the first {n} terms of the GP with first term {a} and common ratio {rr}.", v, [a*rr**n,v+a,v-1,a*(rr**n+1)//(rr+1) if (rr**n+1)%(rr+1)==0 else v+2*a],"Sequence and Series","Medium")
def t_sinf(r):
    a=R(r,1,9)*R(r,1,3); d=r.choice([2,3,4,5]); a=a*d; v=F(a*d,d-1)
    return B.add(f"Find the sum to infinity of the GP with first term {a} and common ratio 1/{d}.", str(v) if v.denominator==1 else f"{v.numerator}/{v.denominator}", [str(a*d),str(a+a//d),str(F(a,d-1)),str(a*(d+1))],"Sequence and Series","Hard")
def t_disc(r):
    a,b,c=R(r,1,5),R(r,-9,9),R(r,-5,6); D=b*b-4*a*c
    ans="two distinct real roots" if D>0 else "equal real roots" if D==0 else "no real roots"
    return B.add(f"The quadratic equation {poly([(a,2),(b,1),(c,0)]).replace('x^0','')} = 0 has how many types of roots? Choose the correct description.".replace("has how many types of roots? Choose the correct description.","has:"), ans, [x for x in ("two distinct real roots","equal real roots","no real roots","two imaginary roots") if x!=ans],"Quadratic Equations","Medium")
def t_logs(r):
    a,b=R(r,2,9),R(r,2,9)
    return B.add(f"If log 2 = x and log 3 = y, express log {2**a*3**b} in terms of x and y.", f"{a}x + {b}y", [f"{b}x + {a}y",f"{a*b}(x + y)",f"{a}x − {b}y",f"({a}+{b})(x + y)"],"Logarithms","Medium")
def t_lines(r):
    m,c=R(r,1,6),R(r,-8,8); x1=R(r,-3,4); y1=m*x1+c
    return B.add(f"Find the equation of the line through ({x1}, {y1}) with gradient {m}.", f"y = {m}x {fmt_signed(c)}" if c else f"y = {m}x", [f"y = {m}x {fmt_signed(-c)}" if c else f"y = {m}x + 1",f"y = {m}x {fmt_signed(y1)}",f"y = {-m}x {fmt_signed(c)}" if c else f"y = {-m}x",f"y = x {fmt_signed(c+m)}"],"Coordinate Geometry","Medium")
def t_proj(r):
    a,b,c,d=R(r,1,4),R(r,1,4),R(r,1,4),R(r,1,4)
    return B.add(f"If a = {a}i + {b}j and b = {c}i + {d}j, find a + 2b.", f"{a+2*c}i + {b+2*d}j", [f"{a+c}i + {b+d}j",f"{a-2*c}i + {b-2*d}j",f"{2*a+c}i + {2*b+d}j",f"{a+2*c}i − {b+2*d}j"],"Vectors","Easy")
def t_chain(r):
    a,n,b=R(r,1,5),R(r,2,5),R(r,1,6)
    return B.add(f"Differentiate y = ({a}x + {b})^{n} with respect to x.", f"{a*n}({a}x + {b})^{n-1}" if n>2 else f"{a*n}({a}x + {b})", [f"{n}({a}x + {b})^{n-1}" if n>2 else f"{n}({a}x + {b})",f"{a}({a}x + {b})^{n-1}" if n>2 else f"{a}({a}x + {b})",f"{a*n}({a}x + {b})^{n}",f"({a}x + {b})^{n+1}/{n+1}"],"Calculus","Hard")
temps=[t_diff,t_diffpt,t_stat,t_integ,t_det,t_trace,t_dot,t_mod,t_cplx,t_i,t_perm,t_comb,t_arr,t_binom,t_gpsum,t_sinf,t_disc,t_logs,t_lines,t_proj,t_chain]
if __name__=="__main__":
    for t in temps: B.fill(t,120,tries=60)
    print("further_mathematics",B.save())
