# factors.py

Created by ikario198

Created on September 26, 2022

8.42 KB

Factors v1.4.
Python Game for Numworks, all models.
By Ilyas RAHMOUN & Vincent ROBERT. April 2022.

#### Changelog

Factors v1.0 - 14/04/2022:
- Initial game

Factors v1.1 - 15/04/2022:
- Fixed saving of average after retrying a level
- Fixed the disappearance of the top arrow in the menu

Factors v1.2 - 21/04/2022:
- Fixed displaying of average with impossible rounding

Factors v1.3 - 28/08/2022:
- Fixed the disappearance of the cursor when pressing several inputs at the same time when accessing the menu

Factors v1.4 - 19/09/2022 (latest):
- The [OK] key now starts the progress feature
- The [Ans] key is now used to exit the program cleanly

```from kandinsky import *
from random import randint
from ion import *

# Factors 1.4 NumWorks, 19.09.2022
# Par Ilyas RAHMOUN & Vincent ROBERT
# https://nsi.xyz/factors <3

l_c,l_m,cursor,avg = 1,1,0,1.0
last_key,retry,in_level = None,False,False

rec = fill_rect
txt = draw_string

grid,pos = [1+i for i in range(16)],[]
sco = {0:0}
try:
get_keys()
os_c = (192,53,53)
except NameError:
os_c = (255,183,52)

grey_c, dark_c, game_c, white_c = (196,196,196),(42,42,42),(148,113,222),(255,255,255)

# Le tuple `numbers` ainsi que la fonction `draw_number()` viennent d'Eric Schrafstetter
numbers = (31599,18724,29671,31207,18925,31183,31695,18727,31727,31215)
letters = (37583,188271,234063,74903,252783,186351,248271)

def fill(n,s):
return "0"*(s-len(str(n)))+str(n)

def boot(key=420010100620):
global l_c,l_m,avg,sco,last_key,retry,in_level
if (key//1000)%sum(white_c)==key%1000 :
l_m = int(str(key)[2:5])
l_c = l_m
avg = int(str(key)[5:7])+int(str(key)[7:10])/1000
sco = {0:0,1:1}
for level in range(1,l_m):
sco[level] = 1
for i in range(int((avg-1)*l_m)):
sco[randint(max(l_m-10,1),max(l_m-1,1))] += 1
last_key,retry,in_level = None,False,False
factors()
else:
print("Invalid Key! Try again XD")

def generate_key():
global l_m,avg
if avg>99 or l_m>999:
return "No backup possible"
else:
code_str = "42"+fill(l_m,3)+fill(int(avg),2)+fill(int((avg%1)*1000),2)
hash_code = int(code_str)%sum(white_c)
return code_str+fill(hash_code,3)

def save():
print("[OK] Save progress feature ^^")
print(generate_key())
print("boot("+generate_key()+")")
print("Press any key to continue")
input()

def gui():
for k in range(7):
for i in range(19):
if letters[k]>>i&1==1:
rec(7+12*k+(i%3)*3,10+(i//3)*3,3,3,os_c)
txt("Lvl",55,69,dark_c)
txt("Avg",55,157,dark_c)
rec(139,200,174,22,os_c)
txt("Designed by",22,202,grey_c)
txt("nsi.xyz/factors",152,202,white_c,os_c)

global l_c,avg,last_key,in_level
rec(7,145,42,42,grey_c)
avg_aff = str(round(avg)) if avg>=10 else str(round(avg,1))[:3]
txt(str(avg_aff),13+5*(10<= avg<100),158,dark_c,grey_c)
rec(7,57,42,42,game_c)
refresh_scoreboard()
txt("Play",8,37,dark_c)
txt("Best",55,113,dark_c)
rec(95,13,42,42*4+6,white_c)
arrow(90,71,3,os_c)
for i in range(4):
for j in range(4):
rec(139+44*j,13+44*i,42,42,grey_c)
while not keydown(51) and not keydown(3):
if keydown(1) and last_key!=1 and l_c!=l_m:
l_c += 1
last_key = 1
refresh_scoreboard()
if keydown(2) and last_key!=2 and l_c!=1:
l_c -= 1
last_key = 2
refresh_scoreboard()
if not (keydown(0) or keydown(1) or keydown(2) or keydown(3)):
last_key = None
in_level = False
last_key = 3
else:
rec(7,57,42,42,grey_c)
draw_number(l_c,7+44//2+center(l_c),13+58,dark_c)
txt("Play",8,37,white_c)
txt("Best",55,113,white_c)
rec(0,101,60,42,white_c)
if l_c==42:
txt("^_^",55,113,game_c)

def refresh_scoreboard():
rec(7,57,42,42,game_c)
draw_number(l_c,7+44//2+center(l_c),13+58,dark_c)
rec(0,101,42,42,white_c)
if l_c!=l_m or (sco.get(l_c) is not None):
txt(str(sco[l_c]),18+4*(sco[l_c]<10),113,dark_c)
arrow(62,57,1,os_c if l_c!=l_m else white_c)
else:
arrow(62,57,1)
if l_c != 1:
arrow(62,92,2,os_c)
else:
arrow(62,92,2)

def center(nbr):
if 0<nbr<10:
ecart = -6
elif 10<=nbr<100:
ecart = -12
elif 100<=nbr<1000:
ecart = -18
else:
ecart = -26
return ecart

def draw_number(n,x,y,c):
if n>0:
for k,j in enumerate(str(n)):
for i in range(16):
if numbers[int(j)]>>i&1==1:
rec(x+12*k+(i%3)*3,y+(i//3)*3,3,3,c)

def arrow(x,y,d,c=white_c):
for i in range(6):
if d==0:
rec(x+i,y+6-i,1,2+2*i,c)
if d==1:
rec(x+6-i,y+i,2+2*i,1,c)
if d==2:
rec(x+i,y+i,12-2*i,1,c)
if d==3:
rec(x+i,y+i,1,12-2*i,c)

def generate_grid():
for i in range(16):
j = randint(1,15)
grid[i],grid[j] = grid[j],grid[i]

def start_level(re=0,new=0):
global cursor,pos,retry,l_c,l_m
if new == 1:
l_c += 1
if l_c == l_m + 1:
l_m += 1
cursor = l_c
pos = [0,1]
arrow(62,57,1)
arrow(62,92,2)
arrow(90,71,3)
arrow(0,71,0)
rec(95,57,42,42,game_c)
draw_number(l_c,d_p(pos[0])[0]+44//2+center(l_c),d_p(0,pos[1])[1]+44//2-8,dark_c)
if not re:
generate_grid()
rec(d_p(5)[0],d_p(0,4)[1],0-176,0-176,white_c)
k = 0
for i in range(4):
for j in range(4):
rec(139+44*j,13+44*i,42,42,game_c)
draw_number(grid[k],(139+44*j)+44//2+center(grid[k]),
(13+44*i)+44//2-8,white_c)
k += 1
retry = False

def move(key=3):
global cursor,pos
if 0<=pos[0]<=4 and 0<=pos[1]<=3:
if key==3:
rec(d_p(pos[0]-1)[0],d_p(pos[0],pos[1])[1],42,42,white_c)
rec(d_p(pos[0])[0],13,42,42*4+3*2,white_c)
number_interact=get_number(pos[0]-1,pos[1])
if cursor%number_interact==0:
cursor=cursor//number_interact
else:
cursor=cursor+number_interact
rec(d_p(pos[0])[0],d_p(0,pos[1])[1],42,42,game_c)
draw_number(cursor,d_p(pos[0])[0]+44//2+center(cursor),d_p(0,pos[1])[1]+44//2-8,dark_c)
else:
rec(d_p(pos[0])[0],d_p(pos[0],pos[1]+(-1 if key==2 else 1))[1],42,42,white_c)
rec(d_p(pos[0])[0],d_p(0,pos[1])[1],42,42,game_c)
draw_number(cursor,d_p(pos[0])[0]+44//2+center(cursor),d_p(0,pos[1])[1]+44//2-8,dark_c)

def get_number(x,y):
return grid[y*4+x]

def d_p(p_x=0,p_y=0):
return [95+44*p_x,13+44*p_y]

def level_transition(s):
global l_c,l_m,avg,sco,pos
k=0
while d_p(pos[0])[0]+k != d_p(4)[0]:
rec(d_p(pos[0])[0]+k,d_p(0,pos[1])[1],42,42,game_c)
k+=1
pos=[4,pos[1]]
k=0
while d_p(0,pos[1])[1]+k != d_p(0,3)[1]:
rec(d_p(pos[0])[0],d_p(0,pos[1])[1]+k,42,42,game_c)
k+=1
pos=[4,3]
k=0
while k!=175:
rec(d_p(pos[0]+1)[0]-2,d_p(0,pos[1]+1)[1]-2,0-k,0-k,game_c)
k+=1
txt("Perfect" if s==1 else "Well done" if s<=avg else "Can do better!!!",150 if s>avg else 185,50,white_c,game_c)
draw_number(s,210,75,dark_c)
txt("Retry",156,120,white_c,game_c)
txt("Next",256,120,white_c,game_c)
arrow(176,142,0,dark_c)
arrow(266,143,3,dark_c)
if l_c in sco:
sco[l_c]=min(sco[l_c],s)
else:
sco[l_c]=s
somme=0
for value in sco.values():
somme+=value
avg=somme/(len(sco)-1*(len(sco)!=1))
pos[0]=42

def factors():
global cursor, pos, last_key, retry, in_level
while not keydown(51):
if in_level:
if keydown(3) and last_key != 3:
pos[0] += 1
last_key = 3
move(3)
if keydown(0) and last_key != 0 and pos[0] > 0:
retry = True
last_key = 0
elif keydown(0) and last_key != 0 and pos[0] == 0:
pos[0] -= 1
if keydown(1) and last_key != 1 and pos[1] > 0:
pos[1] -= 1
last_key = 1
move(1)
if keydown(2) and last_key != 2 and pos[1] < 3:
pos[1] += 1
last_key = 2
move(2)
if pos[0] == -1:
if retry:
start_level(1)
if pos[0] == 4 or (cursor == 1 and not ((-1 <= pos[0] <= 0) or 42 <= pos[0] <= 43)):
level_transition(cursor)
if pos[0] == 43:
start_level(0, 1)
if not (keydown(0) or keydown(1) or keydown(2) or keydown(3)):
last_key = None
if keydown(4):
save()
break
else:
gui()