# More games at calcplex.com
d='quit'
Y='best solve  '
X=Exception
H=False
G=str
J=True
E=len
F=None
D=range
import random as h
try:import ti_draw as B,ti_system as K;M=J
except ImportError:M=H
P=[('EASY',3),('NORMAL',4),('HARD',5)]
i=5,9,14
def j(n):return[[0]*n for A in D(n)]
def Z(b,r,c):
	A=E(b)
	for(D,F)in((0,0),(-1,0),(1,0),(0,-1),(0,1)):
		B,C=r+D,c+F
		if 0<=B<A and 0<=C<A:b[B][C]^=1
def a(b):
	for A in b:
		if any(A):return H
	return J
def k(b,presses,rnd):
	A=E(b)
	while J:
		for B in b:
			for C in D(A):B[C]=0
		for F in D(presses):Z(b,rnd.randint(0,A-1),rnd.randint(0,A-1))
		if not a(b):return
def e(n):
	A=[]
	for F in D(n):
		for G in D(n):
			B=0
			for(H,I)in((0,0),(-1,0),(1,0),(0,-1),(0,1)):
				C,E=F+H,G+I
				if 0<=C<n and 0<=E<n:B|=1<<C*n+E
			A.append(B)
	return A
def f(b):
	A=E(b);B=0
	for C in D(A):
		for F in D(A):
			if b[C][F]:B|=1<<C*A+F
	return B
def c(b):
	J=E(b);A=J*J;W=e(J);X=f(b);B=[]
	for Q in D(A):
		P=0
		for R in D(A):
			if W[R]&1<<Q:P|=1<<R
		if X&1<<Q:P|=1<<A
		B.append(P)
	Y=[-1]*A;H=0;L=[]
	for G in D(A):
		M=-1
		for I in D(H,A):
			if B[I]&1<<G:M=I;break
		if M<0:continue
		B[H],B[M]=B[M],B[H]
		for I in D(A):
			if I!=H and B[I]&1<<G:B[I]^=B[H]
		L.append((G,H));Y[G]=H;H+=1
	for I in D(H,A):
		if B[I]&(1<<A)-1==0 and B[I]>>A&1:return
	Z=set(A for(A,B)in L);N=[A for A in D(A)if A not in Z];S=1<<E(N)if E(N)<=16 else 0;K=F
	if S:
		for a in D(S):
			C=[0]*A
			for(c,G)in enumerate(N):C[G]=a>>c&1
			for(G,O)in L:
				d=B[O]>>A&1;T=0;g=B[O]
				for U in N:
					if g&1<<U:T^=C[U]
				C[G]=d^T
			V=sum(C)
			if K is F or V<K[0]:K=V,C
	else:
		C=[0]*A
		for(G,O)in L:C[G]=B[O]>>A&1
		K=sum(C),C
	h,C=K;return[(A//J,A%J)for A in D(A)if C[A]]
def l(b):A=c(b);return F if A is F else E(A)
Q=250,205,55
R=255,235,150
T=36,40,58
U=70,78,108
g=240,250,255
I=14,16,28
def N(k):
	try:return int(k)
	except(ValueError,TypeError):return 0
def S():
	while N(K.get_key(0))!=0:pass
	while J:
		A=N(K.get_key(0))
		if A!=0:
			while N(K.get_key(0))!=0:pass
			return A
def A(col):A=col;B.set_color(A[0],A[1],A[2])
def C(y,txt):B.draw_text((319-(E(txt)*10-2))//2,y,txt)
def m(n):A=168;B=min(48,A//n);C=B*n;D=(319-C)//2;E=34+(A-C)//2;return B,D,E
def L(b,r,c,C,ox,oy,cur,hint=H):
	D,E=ox+c*C,oy+r*C;F=b[r][c];G=Q if F else T;A(I);B.fill_rect(D,E,C,C);A(G);B.fill_rect(D+2,E+2,C-4,C-4);A(R if F else U);B.fill_rect(D+2,E+2,C-4,3);B.fill_rect(D+2,E+2,3,C-4)
	if hint:A((80,230,120));B.fill_rect(D+C//2-4,E+C//2-4,8,8)
	if cur==(r,c):A(g);B.fill_rect(D+3,E+3,C-6,2);B.fill_rect(D+3,E+C-5,C-6,2);B.fill_rect(D+3,E+3,2,C-6);B.fill_rect(D+C-5,E+3,2,C-6)
def n(b,C,ox,oy,cur):
	A=E(b)
	for B in D(A):
		for F in D(A):L(b,B,F,C,ox,oy,cur)
def o(name,par):A(I);B.fill_rect(0,0,319,30);A((235,225,120));B.draw_text(6,22,name);A((150,235,170));B.draw_text(250,22,'PAR '+G(par))
def b(moves):A(I);B.fill_rect(150,2,95,20);A((150,205,235));B.draw_text(150,22,'MOVES '+G(moves))
V='LOEA','LONO','LOHA'
def W(mi):
	if not M:return 0
	try:return int(list(K.recall_list(V[mi]))[0])
	except X:return 0
def p(mi,v):
	if M:
		try:K.store_list(V[mi],[float(v)])
		except X:pass
def O(y,txt,col):A(I);B.fill_rect(0,y-18,319,22);A(col);C(y,txt)
def q():
	A(I);B.fill_rect(0,0,319,209);A((250,210,60));C(20,'HOW TO PLAY');A((205,214,230));E=['Each square is a light.','Press one and it FLIPS itself','AND its 4 neighbours (up, down,','left, right) on and off.','Goal: turn EVERY light off.','The catch: a press changes 5',"lights, so it's a puzzle.",'PAR = fewest presses possible.','2nd = a hint toward an optimum.'];D=44
	for F in E:B.draw_text(6,D,F);D+=16
	A((130,140,170));C(206,'any key = back');S()
def r(mi):
	F=mi
	def L():
		A(I);B.fill_rect(0,0,319,209);E=26;L=3*E;M=(319-L)//2;N=24;O={(0,0),(0,2),(1,1),(2,0),(2,2)}
		for H in D(3):
			for J in D(3):F,G=M+J*E,N+H*E;K=(H,J)in O;A(I);B.fill_rect(F,G,E,E);A(Q if K else T);B.fill_rect(F+2,G+2,E-4,E-4);A(R if K else U);B.fill_rect(F+2,G+2,E-4,3)
		A((250,210,60));C(126,'LIGHTS OUT');A((150,165,200));C(148,'<- -> mode    up/dn help');C(168,'ENTER press    2nd hint')
	def K(m):
		C,A=P[m];B=W(m);O(190,'< '+C+'  '+G(A)+'x'+G(A)+' >',(215,235,245))
		if B:O(206,Y+G(B),(150,235,170))
		else:O(206,'turn every light off',(120,130,160))
	L();K(F)
	while J:
		H=S()
		if H==45:return
		if H==24:F=(F-1)%E(P);K(F)
		elif H==26:F=(F+1)%E(P);K(F)
		elif H in(25,34):q();L();K(F)
		elif H==105:return F
def s(mi):
	p,G=P[mi];E=j(G);k(E,i[mi],h);W=l(E);M,N,O=m(G);T=0;C=G//2,G//2;H=F;B.clear();A(I);B.fill_rect(0,0,319,209);o(p,W);b(T);n(E,M,N,O,C)
	while J:
		K=S()
		if K==45:return d,0,W
		U,V=C
		if K==25:U=(C[0]-1)%G
		elif K==34:U=(C[0]+1)%G
		elif K==24:V=(C[1]-1)%G
		elif K==26:V=(C[1]+1)%G
		elif K==105:
			if H is not F:e,f=H;H=F
			else:e=f=F
			q=[A[:]for A in E];Z(E,C[0],C[1]);T+=1
			for Q in D(G):
				for R in D(G):
					if E[Q][R]!=q[Q][R]or(Q,R)==C or(Q,R)==(e,f):L(E,Q,R,M,N,O,C)
			b(T)
			if a(E):return'win',T,W
			continue
		elif K==21:
			g=c(E);X=H;H=g[0]if g else F
			if X is not F:L(E,X[0],X[1],M,N,O,C)
			if H is not F:L(E,H[0],H[1],M,N,O,C,hint=J)
			continue
		else:continue
		if(U,V)!=C:Y=C;C=U,V;L(E,Y[0],Y[1],M,N,O,C,hint=Y==H);L(E,C[0],C[1],M,N,O,C,hint=C==H)
def t(moves,par):
	B=par;A=moves
	if A<=B:return'OPTIMAL!'
	if A<=B+2:return'GREAT'
	if A<=B+5:return'GOOD'
	return'SOLVED'
def u():
	D=1
	while J:
		M=r(D)
		if M is F:break
		D=M;K=J
		while K:
			R,T=P[D];Q,E,N=s(D)
			if Q==d:K=H;continue
			L=W(D)
			if L==0 or E<L:p(D,E);L=E
			A(I);B.fill_rect(0,0,319,209);A((250,210,60));C(52,t(E,N));A((235,235,245));C(84,G(E)+' presses   par '+G(N));A((150,235,170));C(108,Y+G(L));A((150,165,200));C(140,'ENTER play again');C(164,'<- -> back to menu');C(188,'CLEAR quit');O=S()
			if O==45:K=H
			elif O in(24,26):K=H
	B.clear()
if M:u()