Intelligence artificielle utilisant le machine learning. Nécessite la bibliothèque numpy, uniquement accessible avec Upsilon. Il est aussi possible de sauvegarder et charger les meilleurs cerveaux.
from time import * from ulab import numpy as np from random import * from kandinsky import fill_rect as rect, draw_line as line, draw_string as txt from ion import keydown as key # MADE BY ARMAND JAMET # STARTED 10.11.22, ENDED 16.11.22 rate=lambda step,fdEaten: fdEaten-step/15 r=lambda x,i:str(x)[0:i] saveName='brain.ia' def save(name,brain): print('Saving...') with open(name,'w') as f: f.truncate(0) sav='' for i in [0,1]: for j in range(len(brain[i])): sav+=':'.join([r(k,4) for k in brain[i][j]]) sav+=';' sav+='/' f.write(sav) del sav def load(name,sav='0'): print('LOADING...') with open(name,'r') as f: line,brain,out=1,[],[[],]*4 while line!='': line=f.readline() sav+=str(line) out[0]=sav.split('/') for i in [0,1]: out[1]=out[0][i].split(';')# 4 lists of 8 str out[2]=[] for j in range(4): out[3]=out[1][j].split(':')# 1 list of 8 str() if out[0]=='0':out[3]=out[3][1:] out[2].append(np.array([float(out[3][k]) for k in range(len(out[3]))])) brain.append(np.array(out[2])) return brain class Graphics(): def __init__(slf,pos,fdPos,conf,col): slf.conf,slf.col,slf.fdPos=conf,col,fdPos slf.drawGrid(conf) slf.refresh(pos,1) def drawGrid(slf,conf,bg=False): rect(0,0,322,222,bg if bg else slf.col[2]) for x in range(0,(conf[2]+1)*10,10):line(conf[0]+x,conf[1],conf[0]+x,conf[1]+conf[3]*10,slf.col[1]) for y in range(0,(conf[3]+1)*10,10):line(conf[0],conf[1]+y,conf[0]+conf[2]*10,conf[1]+y,slf.col[1]) rect(slf.fdPos[0]*10+slf.conf[0]+1,slf.fdPos[1]*10+slf.conf[1]+1,9,9,'green') def refresh(slf,pos,rep,fdPos=0): if rep:rect(pos[0]*10+slf.conf[0]+1,pos[1]*10+slf.conf[1]+1,9,9,slf.col[0]) else:rect(pos[0]*10+slf.conf[0]+1,pos[1]*10+slf.conf[1]+1,9,9,slf.col[2]) def showStats(slf,i,info=['None'],bg=0,x=195,y=70): rect(x,y,125,125,slf.col[2]) for i in range(len(info)):txt(str(info[i]),x,y+i*10,slf.col[1],slf.col[2],1) def name(slf,i,col,bg):txt('AGENT '+str(i+1)+': '+['A','B','C','MA','MA1','MB','MB1','MC','MC1','AB','R','R1'][i],185,42,col,bg) class Game(): def __init__(slf,anim=1,s=.2,perGen=12,conf=[30,61,10,10],col=['red','gray',(0,0,50)]): slf.conf,slf.col,slf.perGen,slf.anim,slf.s,sav=conf,col,perGen,anim,s,0 if input('Hello, user !\nLoad sav ?\n... ')=='':sav=load(saveName) if anim=='in':slf.anim=bool(input('Enable graphics ?\n... ')=='') if not sav:slf.ai=Agent(perGen) else:slf.ai=Agent(perGen,sav) slf.main() def newFdPos(slf): if slf.anim: slf.graph.fdPos=[randint(0,slf.conf[2]-1),randint(0,slf.conf[3]-1)] return slf.graph.fdPos return [randint(0,slf.conf[2]-1),randint(0,slf.conf[3]-1)] def get_input_layer(slf,pos,fdPos): return np.array([ # DIST TO FOOD pos[1]-fdPos[1], # UP fdPos[1]-pos[1], # DOWN pos[0]-fdPos[0], # LEFT fdPos[0]-pos[0], # RIGHT # DIAGONALS ( IN BIN ) (pos[1]>fdPos[1] and pos[0]>fdPos[0]), # UL (pos[1]>fdPos[1] and pos[0]<fdPos[0]), # UR (pos[1]<fdPos[1] and pos[0]<fdPos[0]), # DR (pos[1]<fdPos[1] and pos[0]>fdPos[0])]) # DL def train(slf,pos,fdPos,i,step=0,fdEaten=0): while 0<=pos[0]<slf.conf[2] and 0<=pos[1]<slf.conf[3]: inp=slf.get_input_layer(pos,fdPos) out=slf.ai.compute(inp,i) dir=np.argmax(out) if slf.anim: slf.graph.refresh(pos,1) slf.graph.showStats(i,['IN: OUT:','']+[str(inp[i])+' - '+str(round(out[i],2))+' '+'UDLR'[i] for i in range(4)]+[str(inp[i]) for i in range(4,8)]+['OUT:'+[' UP',' DOWN',' LEFT','RIGHT'][dir],'GRADE:'+r(rate(step,fdEaten),len(str(int(rate(step,fdEaten))))+2)]) sleep(slf.s) slf.graph.refresh(pos,0) pos[dir in [0,1]]+=[-1,1][dir%2] if key(17) or step>15 or fdEaten>10:break step+=1 if pos[0]==fdPos[0] and pos[1]==fdPos[1]: fdEaten+=1 fdPos,step=slf.newFdPos(),0 if slf.anim: for j in [(0,125,0),slf.col[2]]: slf.graph.drawGrid(slf.conf,j) slf.graph.refresh(pos,1) slf.graph.name(i,(120,160,200),(0,125,0)) sleep(j==(0,125,0)) if slf.anim: slf.graph.drawGrid(slf.conf,(125,0,0)) slf.graph.refresh(pos,1) sleep(.4) return rate(step,fdEaten) def trainGen(slf,s,gen): grades=[] for i in range(slf.perGen): seed(s) pos=[randint(0,slf.conf[2]-1),randint(0,slf.conf[3]-1)] fdPos=[randint(0,slf.conf[2]-1),randint(0,slf.conf[3]-1)] if slf.anim: slf.graph=Graphics(pos,fdPos,slf.conf,slf.col) slf.graph.name(i,(120,160,200),slf.col[2]) grades.append(slf.train(pos,fdPos,i)) if key(6): slf.anim=not slf.anim input('Graphics turned '+['off','on'][slf.anim]+'... ') if not slf.anim:print('GEN',gen,': AVG.',int(sum(grades)/len(grades)),'\n → GRADES',', '.join([str(int(i)) for i in grades])) if key(4):save(saveName,[slf.ai.brain[0],slf.ai.brain[1]]) slf.ai.evolve(grades) def main(slf): print(' **** START OF SIMULATION ****') for i in range(100_000):slf.trainGen(int(monotonic()),i) class Agent(): def __init__(ai,perGen,sav=[],learningRate=.5,defaultVal=(-1,1)): ai.brain,ai.lRate,ai.dval=[],learningRate,defaultVal ai.sigm=lambda x: np.array([1])/(np.exp(-x)+1)-.5 if sav!=[]: ai.brain=sav ai.evolve([1,1,1]) else: for i in range(perGen):ai.brain.append(ai.createBrain(defaultVal)) def createBrain(ai,defaultVal):return np.array([np.array([uniform(defaultVal[0],defaultVal[1]) for _ in range(8)]) for _ in range(4)]) def compute(ai,input,i):return ai.sigm(np.dot(ai.brain[i],input)) def evolve(ai,grades): best=[] for _ in range(3): best.append(ai.brain[grades.index(max(grades))]) grades.remove(max(grades)) ai.brain=best del best for i in [0,1,2]: for j in [0,1]:ai.brain.append(ai.brain[i]+ai.createBrain([-ai.lRate,ai.lRate])) for _ in range(2):ai.brain+=[ai.createBrain(ai.dval)] ai.brain.append((ai.brain[0]+ai.brain[1])/2) game=Game('in',0.2)