1999/ka_aroth.r
001 | /* |
002 | KK KK AAAAAA ''' AAAAAA RRRRRR OOOOOO TTTTTTTT HH HH |
003 | KK KK AAAAAAAA '''' AAAAAAAA RRRRRRRR OOOOOOOO TTTTTTTT HH HH |
004 | KK KK AA AA '' AA AA RR RR OO OO TT HH HH |
005 | KK KK AA AA ' AA AA RR RR OO OO TT HH HH |
006 | KKKK AAAAAAAA AAAAAAAA RRRRRRRR OO OO TT HHHHHHHH |
007 | KK KK AA AA AA AA RR RR OO OO TT HH HH |
008 | KK KK AA AA AA AA RR RR OO OO TT HH HH |
009 | KK KK AA AA AA AA RR RR OOOOOOOO TT HH HH |
010 | KK KK AA AA AA AA RR RR OOOOOO TT HH HH |
011 |
012 | Nome : Ka'aroth.r (10-05-99) |
013 |
014 | Provenienza : Pianeta Vegeta |
015 |
016 | Razza : Sayian |
017 |
018 | Scopo : Difendere la terra degli attacchi dei perfidi Sayian |
019 |
020 | Autore : Simone Ascheri |
021 |
022 | LA STORIA |
023 | ========= |
024 |
025 | Un brutto giorno gli alieni del pianeta Vegeta, i potentissimi Sayian, arrivano |
026 | sulla Terra per sterminarne gli abitanti e vendere il pianeta al miglior |
027 | offerente. |
028 | Radish, Napa e Vegeta (praticamente e' come se l' imperatore del Giappone si |
029 | chiamasse Giappone) sono quasi invincibili: l' unico che puo' fermarli e' |
030 | Ka'aroth, anch' egli Sayian di nascita, ma terrestre d' adozione. |
031 | Attacca i nemici con tre tipi di colpi : |
032 | - Il SuperSayian: |
033 | Usato quando si e' a una certa distanza dai bordi, e' il piu' preciso, ma |
034 | anche il piu' lento. E' una routine di Diabolik.r (e di Tox prima) leggermente |
035 | modificata, con il blocco di Scan() mutuato da Coppi.r. |
036 | - Il KaiOKen: |
037 | Compromesso tra precisione e velocita'. Usato in prossimita' dei bordi e |
038 | nei colpi ravvicinati e' derivato direttamente da Arale.r, robot di cui ho |
039 | grande stima. |
040 | - L' onda KameAmeA: |
041 | E' la piu' veloce, ma di scarsa precisione. E' usata nei rallentamenti. |
042 |
043 | COMPORTAMENTO |
044 | ============= |
045 |
046 | La strategia di Ka'aroth e' abbastanza complicata. |
047 |
048 | Fase Iniziale |
049 | ------------- |
050 | All' inizio del Match Ka'aroth cerca un angolo libero, cominciando da quello |
051 | piu' vicino, e (non troppo) prontamente lo raggiunge. |
052 | Inizia quindi a muoversi parallelamente ad un lato e a sparare. |
053 | Ka'aroth e' un po' misantropo. |
054 | Se infatti si accorge di condividere il suo bell' angoletto con un altro |
055 | crobottino cambia posizione. |
056 |
057 | Fase Finale |
058 | ----------- |
059 | Dopo circa 150000 cicli Ka'aroth conta gli avversari: |
060 |
061 | 1 * Se c' e' piu' di un superstite continua il movimento |
062 |
063 | I * Con moto a pendolo sulla diagonale, se i danni sono inferiori al |
064 | 40%... |
065 | II * ...Altrimenti descrivendo dei mini-quadrati nel settore di appartenenza, |
066 | cambiando angolo ogni volta che i danni subiti sono ingenti. |
067 |
068 | 2 * Se invece si accorge di avere solo piu' un avversario Ka'aroth sceglie |
069 | una delle strategie seguenti: |
070 |
071 | A * Se il movimento precedente era sulla bisettrice e i danni inferiori al |
072 | 60%, inizia a scorrazzare lungo la diagonale, cambiando angolo ogni volta |
073 | che quello base e' occupato. |
074 | B * Altrimenti adotta un movimento a rombo con vertici nei punti medi dei |
075 | lati dell' arena, alternato con movimento a clessidra inclinata con |
076 | vertici negli stessi punti. |
077 |
078 | 3 * In tutti i casi, se ha subito piu' del 78% di danni, Ka'aroth lascia |
079 | perdere cio' che stava facendo, cerca un angolo libero e ivi si ferma, |
080 | adottando questo comportamento: |
081 |
082 | 1 * Se scopre che c' e' un solo superstite nell' arena, rimbalza di angolo |
083 | libero in angolo libero per cercare di distruggerlo... |
084 | 2 * ...Altrimenti si ferma in un cantuccio sparando ai cattivi con la massima |
085 | precisione di cui e' capace e muovendosi solo quando viene colpito. |
086 |
087 | Teoricamente questa tattica dovrebbe aiutarlo a pareggiare l' incontro |
088 | (Son-Goku.r non ci riusciva quasi mai), ma non so fino a che punto sia |
089 | efficace. |
090 |
091 | Routine di Movimento |
092 | -------------------- |
093 | La routine e' unica per tutte le posizioni dello schermo e per tre dei quattro |
094 | attacchi finali. |
095 | Calcola la distanza (al quadrato, evitando cosi' una radice) rispetto ad un |
096 | punto dato [(20,20)(980,20)(980,980)(20,980)], trova l' angolo necessario per |
097 | raggiungerlo e infine inizia a muoversi in quella direzione. Quando arriva a |
098 | destinazione si ferma. |
099 | Sceglie una direzione parallela ad uno dei lati (controllando dove si trova il |
100 | nemico) e si avvia, camminando fino a quando non si trova alla massima |
101 | distanza stabilita dal punto. |
102 | Inverte quindi il movimento e riinizia dal principio. |
103 |
104 | CONSIDERAZIONI |
105 | ============== |
106 |
107 | Il programma e' abbastanza commentato, nel caso improbabile qualcuno si |
108 | prendesse il disturbo di leggerlo. |
109 | Sono partito dalla struttura di base di Son-Goku.r, di cui Ka'aroth.r e' |
110 | (teoricamente) un' evoluzione, ma nel corso del lavoro ho modificato radicalmente |
111 | ogni punto. Infatti alcune procedure sono state riscritte completamente ed altre |
112 | ulteriormente ottimizzate. In piu' e' differente il mix delle varie tattiche e la |
113 | modalita' di scelta della direzione. Ho aggiunto inoltre un' oscillazione in |
114 | diagonale e sostituito l' inefficiente !-like con una Kill!-like. Ho inserito infine |
115 | una routine difensiva auspicabilmente migliore della precedente, mentre ho eliminato |
116 | la fase iniziale di 'studio' degli avversari. |
117 | Per la spiegazione delle routine di fuoco rimando ai crobot citati, o ai loro |
118 | eventuali ispiratori. |
119 | In ogni caso ora Ka'aroth utilizza il piu' possibile la Tox-like, relegando le altre |
120 | due a compiti marginali. |
121 |
122 | RINGRAZIAMENTI |
123 | ============== |
124 |
125 | Un sentito grazie a: |
126 | - Tom Poindexter (per averci donato Crobots) |
127 | - Maurizio 'JOSHUA' Camangi per: |
128 | * le sue indispensabili utilities |
129 | * la pazienza dimostrata nel 'guidarmi' alla scoperta di Linux |
130 | * le tonnellate di e-mail che ci siamo scambiati |
131 | - Michelangelo Messina per aver gentilmente assecondato tutte le mie richieste di |
132 | modifica alle sue utilities e aver trovato i bugs delle mie |
133 | - Tutti coloro con i quali ho scambiato pareri in questi mesi |
134 |
135 | Un enorme ringraziamento ad AKIRA TORIYAMA per aver creato DragonBall e |
136 | DragonBall Z. |
137 |
138 | */ |
139 |
140 | int timmax, max, min, ang, ang2, dx, dy; |
141 | int dan, park, ango, oang, range, orange; |
142 | int quad, flag3, flag2, flag1, flag; |
143 |
144 | main() |
145 | { |
146 | ang2=(Trova((dy=980-(loc_x(min=8500)>(flag2=500))*960), |
147 | (1000-(dx=(loc_y(max=70000)>500)*960+20)))/90*90); |
148 |
149 | Go(timmax=80); /*Trova un angolo libero e lo raggiunge*/ |
150 |
151 | while (timmax+=6) /*Inizia il ciclo principale*/ |
152 | { |
153 | while ((--timmax)&&(damage()<79)) /*Movimento oscillatorio*/ |
154 | { |
155 | if (!(flag%=630)) /*Se il movimento non e' diagonale...*/ |
156 | if (Ricerca(ang2)) /*...sceglie la direzione in base alla posizione del nemico*/ |
157 | flag=630; |
158 | drive (ang=(ang2+flag)%360,100); /*Si allontana dall' origine*/ |
159 | while ((Dista(dx,dy)<max)&&(speed())) /*Finche' non e' troppo lontano spara*/ |
160 | SuperSayian(1,1,0); |
161 |
162 | KameAmeA(); /*Rallenta*/ |
163 |
164 | if (Ricerca(ang+=180)) /*Controlla se ha un nemico alle spalle:*/ |
165 | Go(); /*e cambia angolo..*/ |
166 | else Arrivo(dx,dy,min); /*..altrimenti torna all' origine*/ |
167 | } |
168 |
169 | /*Comportamenti dopo i primi 100000 cicli o dopo il 78% di danni */ |
170 |
171 | if (damage(flag1=(Reeft(ang2+205,5)))>78) /*Gioca in difesa*/ |
172 | { |
173 | while (Go()) /*Cambia di angolo, fermandoti un po' se c'e' piu' di un superstite*/ |
174 | while ((dan==damage())&&(flag1)) /*Fai il finto Tox*/ |
175 | SuperSayian(0,0,0); |
176 | } |
177 | else if (!flag1) /*Controlla quanti sono i sopravvissuti*/ |
178 | { |
179 | if ((flag==315)&&(damage()<60)) /*Se il movimento era sulla bisettrice allora l' attacco finale e' diagonale*/ |
180 | max=1350000; /*Nuova ampiezza dell' oscillazione*/ |
181 | else |
182 | { |
183 | while (NuvolaSpeedy(500,60)) /*Attacco finale romboidale*/ |
184 | { |
185 | NuvolaSpeedy(flag2,flag2=1440-flag2); |
186 | NuvolaSpeedy(flag2,1440-flag2); |
187 | NuvolaSpeedy(60,500); |
188 | } |
189 | } |
190 | } |
191 | else |
192 | { |
193 | if (damage(min=15000)<40) /*Pendolo sulla bisettrice: Gundam-like*/ |
194 | { |
195 | flag=315; |
196 | } |
197 | else |
198 | { |
199 | while (((dan=damage())<79)&&(Reeft((ang=ang2)+205,5))) /*Quadrato nell' angolo*/ |
200 | { |
201 | while ((++quad)%5) |
202 | { |
203 | Arrivo(dx+=26000000/ cos (ang),dy+=26000000/ sin (ang),8000); /*Calcola di volta in volta le nuve coordinate*/ |
204 | ang+=270; |
205 | } |
206 | if (dan<damage()+(timmax=-5)) Go(); /*Decide se muoversi in un altro angolo*/ |
207 | } |
208 | } |
209 | } |
210 | } |
211 | } |
212 |
213 | /*Operazioni di servizio*/ |
214 |
215 | /*Routine di spostamento verso coordinate date*/ |
216 |
217 | NuvolaSpeedy(tx,ty) |
218 | int tx, ty; |
219 | { |
220 | Trova(tx,ty); /*Cerca la direzione in cui muoversi*/ |
221 | return Arrivo(tx,ty,6800); |
222 | } |
223 |
224 | /*Vai alla distanza minima dal punto*/ |
225 |
226 | Arrivo(fx,fy,m) |
227 | int fx, fy, m, h; |
228 | { |
229 | drive (ang,100); |
230 | while (((h=Dista(fx,fy))>m)&&(speed())) |
231 | SuperSayian(1,0,h<25000); |
232 | return KameAmeA(); |
233 | } |
234 |
235 | /*Individua l' angolazione necessaria per raggiungere le coordinate (mx,my)*/ |
236 |
237 | Trova(mx,my) |
238 | int mx, my; |
239 | { |
240 | return (ang=(360+((mx-=loc_x())<0)*180+ atan (((my-loc_y())*100000)/mx))); |
241 | } |
242 |
243 | /*Calcola la distanza rispetto ad un punto dato: si lascia il quadrato per risparmiare tempo*/ |
244 |
245 | Dista(nx,ny) |
246 | int nx, ny; |
247 | { |
248 | return (((nx-=loc_x())*nx+(ny-=loc_y())*ny)); |
249 | } |
250 |
251 | /*Valuta se un angolo e' libero*/ |
252 |
253 | Go() |
254 | { |
255 | while (Ricerca(Trova(OooHoo(ang2+=90),dy=park))>400); |
256 | return (dan=damage(NuvolaSpeedy(dx,dy))); |
257 | } |
258 |
259 | /*Effettua la rotazione degli angoli da controllare*/ |
260 |
261 | OooHoo() |
262 | { |
263 | park=dx; |
264 | return (dx=(1000-dy)); |
265 | } |
266 |
267 | /*Scan allargato a 40 gradi: non cade nel bug di scansione*/ |
268 |
269 | Ricerca(an) |
270 | int an; |
271 | { |
272 | return (scan(an+350,10))+(scan(an+10,10)); |
273 | } |
274 |
275 | /*Conta i superstiti*/ |
276 |
277 | Reeft(dsiete,dand) |
278 | int dsiete, dand, qsiete; |
279 | { |
280 | while (--dand) |
281 | qsiete+=(Ricerca(dsiete+=40)!=0); |
282 | return (qsiete>1); |
283 | } |
284 |
285 | /*Procedure di fuoco (spudoratamente copiate)*/ |
286 |
287 | /*Spara con media precisione*/ |
288 |
289 | KaiOKen() |
290 | { |
291 | if ((orange=scan(ango,10))&&(orange<770)) |
292 | { |
293 | if (range=scan(ango+353,4)) |
294 | cannon(ango+=350,3*range-2*orange); |
295 | else if (range=scan(ango,3)) |
296 | cannon(ango,3*range-2*orange); |
297 | else if (range=scan(ango+7,4)) |
298 | cannon(ango+=10,3*range-2*orange); |
299 | } |
300 | else |
301 | if ((range=scan(ango+=339,10))&&(range<700)) |
302 | cannon(ango,range); |
303 | else |
304 | if ((range=scan(ango+=42,10))&&(range<700)) |
305 | cannon(ango,range); |
306 | else |
307 | if ((range=scan(ango+=297,10))) |
308 | cannon(ango,range); |
309 | else |
310 | if ((range=scan(ango+=84,10))) |
311 | cannon(ango,range); |
312 | else |
313 | return (ango+=40); |
314 | } |
315 |
316 | /*Spara mentre decelera*/ |
317 |
318 | KameAmeA() |
319 | { |
320 | drive(ang,0); |
321 | while (speed()>49) |
322 | if ((range=scan(ango,10))&&(range<770)) |
323 | cannon (ango,range); |
324 | else |
325 | Ceck(); |
326 | } |
327 |
328 | /*Se non ha trovato avversari nella direzione originaria li cerca intorno e nella direzione in cui si sta muovendo*/ |
329 |
330 | Ceck() |
331 | { |
332 | if (range=scan(ango+=340,10)); |
333 | else if (range=scan(ango+=40,10)); |
334 | else if (range=scan(ang,10)) |
335 | ango=ang; |
336 | else |
337 | return (ango+=40); |
338 | return cannon(ango,2*scan(ango,10)-range); |
339 | } |
340 |
341 | /*Spara con buona precisione sia da fermo che in movimento*/ |
342 |
343 | SuperSayian(muovi,sposta,no) |
344 | int muovi, sposta, no; |
345 | { |
346 | if (orange=scan(ango,10)) |
347 | { |
348 | if ((((orange<400)||(orange>700))&&(sposta))||(no)) |
349 | return KaiOKen(); |
350 | else |
351 | { |
352 | if (scan(ango-=5,5)); else ango+=10; |
353 | ObaBa(); |
354 | if (orange=scan(oang=ango,5)) |
355 | { |
356 | ObaBa(); |
357 | if (range=scan(ango,10)) |
358 | return cannon((ango+(ango-oang)*((980+range)>>9)-( sin (ango-ang)>>14)*muovi),(range*200/(200+orange-range-( cos (ango-ang)>>12)*muovi))); |
359 | } |
360 | else |
361 | return KaiOKen(); |
362 | } |
363 | } |
364 | else |
365 | return Ceck(); |
366 | } |
367 |
368 | /*Questo viene da Coppi.r*/ |
369 |
370 | ObaBa() |
371 | { |
372 | if (scan(ango+354,1)) ango+=354; |
373 | if (scan(ango+6, 1)) ango+=6; |
374 | if (scan(ango+356,1)) ango+=356; |
375 | if (scan(ango+4, 1)) ango+=4; |
376 | if (scan(ango+358,1)) ango+=358; |
377 | if (scan(ango+2, 1)) ango+=2; |
378 | } |