Old version page
Crobots Tox Theory
Sebbene sicuramente non sia la persona più indicata per spiegarvi il significato di certi numeri nelle funzioni di fuoco, tuttavia tenterò di rendervi partecipi delle idee che mi sono fatto su tali formule che, in effetti, ad una prima occhiata sembrano qualcosa di assurdo e incomprensibile!!
Ovviamente le conclusioni a cui sono giunto non
saranno del tutto esatte (tutt'altro) per cui prego coloro che hanno
maggiore esperienza di me a correggere tutti gli errori che ci saranno nella mia
interpretazione!
Leggendo le mail degli ultimi giorni mi sono reso
conto che alcuni di voi si sono posti le stesse domande che mi sono posto
io lo scorso ottobre leggendo il codice dei Crobots dell'anno
scorso!
Un esempio eclatante può essere quello riportato
in una delle mail precedenti:
cannon((oang+(ang-oang)*3-(sin(ang-dir)/19500)),(range*200/(200+orange-range-(cos(ang-dir)/4167))));
Vediamo come si potrebbe giungere ad un risultato
del genere:
Cosa deve fare una buona funzione di fuoco?
Ovviamente colpire l'avversario con maggiore
precisione e velocità possibile!
Per la velocità, a quanto ho capito, bisogna
lavorare parecchio per ottenere buoni risultati. Questo perché sono
innumerevoli i fattori che influenzano tale parametro:
per prima cosa il fatto che la funzione CANNON ha
bosogno di un tot di cicli virtuali per ricaricarsi. Quindi è necessario
impiegare bene il tempo che per forza di cose deve intercorrere fra un
colpo e il successivo! Tale intervallo tra un colpo e un
altro tuttavia non è sempre uguale! Infatti nel frattempo il robot deve
anche spostarsi e compiere qualunque altro tipo di controllo abbiamo ritenuto
necessario inserire nel codice! Questo porta ad una difficoltà oggettiva nel
riuscire a trovare la famosa e agognata routine di fuoco a cicli fissi che
porterebbe a non perdere neanche un attimo fra la ricarica della funzione cannon
e il fuoco successivo!
Tuttavia è possibile avvicinarsi a tale risultato
almeno in due modi totalmente diversi:
Il primo: Routine di puntamento molto breve e
veloce che si ripete più e più volte in attesa che la cannon si
ricarichi!
Il secondo: Routine di puntamento molto lunga che
impieghi invece tutti i cicli necessari alla ricarica della cannon in modo
proficuo (praticamente cercando di approssimare al meglio la posizione
dell'avversario)!
[Ovviamente è possibile realizzare routines che
impieghino circa la metà o un terzo del tempo di ricarica, ma bisogna fare in
modo che esse sieno ben sincronizzate col resto del codice, cosicchè al momento
in cui la cannon è pronta a sparare, si sia giunti nell'esecuzione del codice
il più vicino possibile al successivo comando Cannon!]
Sulla velocità di fuoco abbiamo l'onore di
avere dei maestri qui il ML!! Ricordo il mio stupore nella lettura dei codici
dei Robot di Simone Ascheri o Daniele Nuzzo! (non me ne vogliano
gli altri ma mica potevo leggere tutti i sorgenti :) Questi ho letto:) ) In
tali robot le funzioni erano scritte seguendo tali principi!
Ricordo altresi' (non vorrei sbagliarmi ma l'ho
provato solo una volta) che il famoso Tox invece aveva una funzione che puntava
bene l'avversario ma lasciava a desiderare per quanto riguarda la velocità di
sparare i colpi!
Veniamo adesso alla precisione (che era anche il
motivo per cui volovo scrivere questa mail):
I paramentri che dobbiamo tenere in considerazione
quando tentiamo di colpire un avversario sono i seguenti:
Moto dell'avversario.
Moto del proprio robot.
Tempo che passa da quando scanniamo la prima volta
a quando scanniamo la volta successiva.
Tempo che passa da quando scanniamo l'ultima volta
a quando facciamo partire il colpo.
Tempo che passa da quando parte il colpo a quando
arriva il colpo!
Riferendomi per prima cosa alla seconda parte della
formula (correzione di gittata):
Gittata=range*200/(200+orange-range-(cos(ang-dir)/4167))
(Per la correzione di angolo si possono fare le
stesse considerazioni ovviamente modificando parametri e costanti!)
Moto dell'avversario: scanniamo due volte in modo
da trovare la differenza di distanza!
Chiamiamo orange il risultato
del primo scan, range il risultato del secondo!
dalla differenza dei due valori
possiamo scoprire se il rob avversario si avvicina o allontana da
noi.
Tramite la semplicissima formula
range*2-orange abbiamo trovato la distanza a cui in
teoria dovrebbe trovarsi l'avversario esattamente dopo lo stesso tempo
intercorso tra il primo e il secondo scan! Questo è fondamentale!
Dobbiamo quindi apportare la prima modifica alla
gittata trovata dovuta al fatto che il missile impiegherà un tot di tempo ad
arrivare fino al bersaglio, e tale tempo non è uguale al tempo intercorso tra i
due scan! Come possiamo trovare tale tempo? Innanzitutto dobbiamo calcolare la
velocità a cui vanno i missili!! Questo mi ricordo di averlo calcolato facendo
prove sparando ad una distanza fissa e aiutandomi con routines sincronizzate!
CMQ, veniva fuori (ovviamente non sono assolutamente sicuro di tali valori!! Si
tratta di valori empirici!!) che il missile viaggia a 3,333 metri a ciclo!
Insomma, in 30 cicli fa 100 metri!
Ora possiamo calcolare quanti cicli ci vogliono per
arrivare al bersaglio! basta dividere la distanza del bersaglio per i metri
percorsi a ciclio dal missile! Ovviamente la distanza è ancora una incognita!
Chiamiamola Gittata. Quindi num di
clicli per arrivare al
bersaglio=Gittata/3.333.
Abbiamo calcolato quanti cicli ci vogliono per
arrivare al bersaglio! Sappiamo quanti cicli ci sono tra le due scan (le abbiamo
scritte noi!).. dividiamo i due valori e otteniamo la costante che ci serve per
correggere la formula! Questa costante non fa altro che tenere conto del
movimento del nemico e del tempo che passa da quando lo individuamo a quando il
colpo arriva sul bersaglio!
Quindi prendiamo la nostra formula
(Gittata=range*2/orange) e la
modifichiamo:
< Gittata=(range*2/orange)*((Gittata/3.33)/(num cicli fra
i due scan))
Tramite semplici passaggi algebrici (portiamo la
variabile a sinistra:)) otteniamo:
Gittata=(range*j)/(j+orange-range) con
j costante.
Possiamo vedere subito come questa formula inizi ad
essere molto simile a quella assurda formula di cui si parlava prima!! Il
200 della formula è proprio la costante j di questa! Tali costanti devono tener
conto del numero di cicli fra gli scan etc etc quindi dipenderanno molto dal
nostro codice! Nel mio Crobot ad esempio questo valore era 60. Ovviamente alla
fine il modo migliore per trovare tale valore è provare e riprovare tante volte
fino a quando si ottengono i risultati migliori :))
Non abbiamo ancora considerato tuttavia il moto del
nostro robot!! Infatti, nel frattempo, anche il nostro robot si è mosso (tranne
se non avete programmato un pazzo masochista che sta fermo a beccarsi i
colpi!!)
Adesso il discorso si fa un pò più complicato..
almeno per me lo è stato!
Come possiamo considerare il nostro moto?
Innanzitutto sappiamo in che direzione ci stiamo muovendo(basta salvare su una
variabile l'angolo quando cambiamo direzione) e possiamo sapere anche a che
velocità lo stiamo facendo (funzione speed()).
Chiamiamo dir proprio la
direzione verso cui ci stiamo muovendo!
Adesso sarebbe molto utile un bel disegnino
esplicativo..
Riflettiamo un attimo.. noi ci avviciniamo al
nemico se la differenza fra l'angolo in cui abbiamo individuato il
nemico(chiamiamola ang) e l'angolo verso cui ci
stiamo muovendo (la nostra dir)è minore di 90 gradi!
Se tale differenza è maggiore di 90 gradi allora ci stiamo allontanando dal
nemico! Tra l'altro, minore è questa differenza, maggiore sarà la velocità
verso cui ci avviciniamo al nemico! Infatti, se la differenza sarà giusto 0,
vuol dire che ci stiamo muovendo esattamente verso il nemico! Se ci fate
caso vale anche il contrario: se la differenza è proprio 180 ci stiamo
dirigendo esattamente dalla parte opposta rispetto al nemico! Per fortuna la
matematica ci viene (una volta tanto) incontro e ci fornisce una bella funzione
che risponde a queste nostre esigenze! Ovviamente mi riferisco alla funzione
COSENO! Tale funzione è esattamente proporzionale alla velocità con cui ci
avviciniamo o ci allontaniamo dal nemico! Infatti
cos(ang-dir)=1 per
ang-dir=0;
cos(ang-dir)=-1 per
ang-dir=180;
cos(ang-dir)=0 per
ang-dir=90 o -90;
Cosa possiamo farci con questo
cos(ang-dir) ? Possiamo moltiplicarlo ad una bella
costante e aggiungerlo (o meglio sottrarlo visti i segni!) alla nostra
formula per tenere conto quindi anche del nostro movimento!
Io avevo fatto di più nella mia funzione di fuoco:
avevo moltiplicato cos(ang-dir) (oltre che alla
costante) anche allo speed() in quanto anche la nostra
velocità (e non solo la direzione) influisce sul movimento! tuttavia ritengo
che si possa soprassedere visto che magari la perdita di cicli dovuti alla
chiamata di tale funzione fa perdere piuttosto che guadagnare in precisione!
Meglio considerare la velocità a cui di solito ci muoviamo e aggiungerla alla
costante!
La nostra costante come deve essere calcolata?
Semplice: tenendo presente
1) quella che riteniamo la velicità a cui ci
muoviamo di solito (immagino 100)
2) le solite considerazioni sui cicli!
3) Importantissimo: la scala con cui vengono
forniti i risultati delle funzioni trigonometriche!!
Poiche la scala è molto alta allora ci conviene
dividere per l'inverso della costante trovata piuttosto che moltiplicare (visto
anche che è possibile utilizzare solo numeri interi!) Infatti la costante che
viene fuori è un num compreso tra 0 e 1 e tendente allo
0!
Ed ecco che viene fuori la formula
finale:
Gittata=(range*j)/(j+orange-range-(cos(ang-dir)/k))
dove k è la nuova costante
trovata!
La formula, a meno delle costanti, è identica a
quella iniziale!
Ovviamente al posto della / si puo mettere >>
e al posto del * si può mettere << (operazioni sui bit che, per chi non
lo sapesse, corrispondono alla divisione o moltiplicazione per le potenze di 2).
In questo modo le costanti utilizzate possono essere soltanto potenze di due
(come aveva fatto notare qualche tempo fa credo Daniele).. tuttavia si tratta
solo di abitudine o preferenze personali perché credo che nel caso di Crobot
non cambi la velocità di esecuzione fra una divisione normale o uno spostamento
di bit..:) (ma anche qui potrei sbagliarmi alla grande!)!
Spero di aver chiarito qualche dubbio e vi prego di
operare tutte le correzioni e aggiunte che vi verranno in mente!
Fate conto che, vista la lunghezza, non mi va di rileggere il tutto :)
Spero di non aver fatto almeno errori grammaticali!!
Ciao,
Michele Miccar Cardinale.