2003/druzil.r
001 | /****************************************************************************/ |
002 | /* */ |
003 | /* Torneo di CRobots di IoProgrammo (2003) */ |
004 | /* */ |
005 | /* CROBOT: Druzil.r */ |
006 | /* */ |
007 | /* CATEGORIA: 2000 istruzioni */ |
008 | /* */ |
009 | /* AUTORE: Daniele Nuzzo */ |
010 | /* */ |
011 | /****************************************************************************/ |
012 |
013 | /* |
014 |
015 | SCHEDA TECNICA: |
016 | |
017 | Le differenze rispetto a Elminster sono la FASE 3 e quindi anche il f2f e una |
018 | FASE 1 un po' piu' lunga. |
019 | Inizialmente il robot calcola alcuni parametri e si reca velocemente nell'angolo |
020 | piu' vicino (FASE 0). |
021 | |
022 | Quindi esegue in sequenza 3 strategie di gioco distinte (se il combattimento e' |
023 | un f2f passa direttamente all'ultima fase di gioco). |
024 | |
025 |
026 | FASE 1: |
027 | |
028 | La FASE 1 di gioco prevede un comportamento estremamente cauto e difensivo. |
029 | |
030 | Il movimento nell'angolo ricorda quello di Drizzt e si basa su oscillazioni |
031 | brevi verso i due angoli adiacenti rimanendo in prossimita' dei bordi |
032 | dell'arena. |
033 | Ci sono tuttavia notevoli differenze rispetto ai robottini dello scorso anno: |
034 | |
035 | 1) Le oscillazioni non sono alternate verso i due angoli adiacenti, ma sono |
036 | determinate in ogni oscillazione da una scelta ben precisa: la direzione |
037 | e' quella dell'avversario piu' distante. L'idea e' quella di far variare |
038 | il piu' possibile l'angolo di scansione dell'avversario piu' vicino e di |
039 | allontanarsi risultando un bersaglio difficile da trovare. |
040 | 2) Nell'avvicinamento verso l'avversario piu' distante il robot non si ferma |
041 | sempre in prossimita' dell'angolo iniziale: se l'avversario piu' distante |
042 | e' molto lontano il robot si avvicina fino a una "distanza di sicurezza" |
043 | da cui decide se sparare contro l'altro robot che era piu' vicino e da cui |
044 | si e' allontanato oppure se creare un fuoco di sbarramento verso il robot |
045 | verso cui si e' avvicinato nel caso in cui risulti l'avversario piu' vicino. |
046 | 3) In questa fase non si perde piu' tempo a contare gli avversari, ma si |
047 | utilizzano criteri differenti per decidere se passare alla fase successiva. |
048 | |
049 | Controlli per decidere se passare alla fase successiva: |
050 | |
051 | 1) Dopo 260 oscillazioni si passa comunque alla fase 2; |
052 | 2) Se prima delle 140 oscillazioni subisce un certo danno (70%) allora cambia |
053 | subito tattica, perche' probabilmente la difesa non paga; |
054 | 3) Da 140 oscillazioni in poi, se non vede avversari nell'angolo opposto allora |
055 | passa alla seconda fase poiche' immagina che sicuramente c'e' un avversario |
056 | in meno e almeno un secondo e' in difficolta'; |
057 | 4) Se in uno degli angoli adiacenti non trova un avversario controlla nell'altro |
058 | angolo adiacente e se non c'e' un avversario neanche li o se si e' allontanato |
059 | dall'angolo per recarsi in quello opposto allora passa alla fase 2. |
060 | |
061 | La routine di fuoco utilizzata in questa fase di gioco non esegue correzioni sulla |
062 | distanza poiche' si adatta al movimento del robot che tende ad allontanarsi o a |
063 | mantenere una distanza di sicurezza dagli avversari. Le correzioni sull'angolo |
064 | sono determinate invece da scansioni con risoluzione limitata in quanto gli |
065 | avversari probabilmente sono ben distanti e quindi l'angolo non deve variare molto. |
066 | |
067 | FASE 2: |
068 | |
069 | La FASE 2 di gioco prevede un comportamento estremamente offensivo dall'angolo e |
070 | contemporaneamente dinamico in quanto prevede cambi di angolo. |
071 | |
072 | Il robot controlla i due angoli adiacenti: se trova un avversario lo attacca finche' |
073 | non subisce danni altrimenti prova a cambiare angolo. |
074 | L'attacco dall'angolo e' effettuato tramite un triangolo (dopo i quadrati di Fizban e |
075 | i rettangoli di Zorn non potevano mancare i triangoli) molto allungato in direzione |
076 | dell'avversario e schiacciato lungo il bordo dell'arena. L'idea e' quella di |
077 | allontanarsi eventualmente da un secondo avversario, provare ad avvicinarsi il piu' |
078 | possibile verso il bersaglio, eludere le routine di fuoco cambiando una volta la |
079 | direzione in avvicinamento e riallontanarsi a massima velocita'. Vengono registrati |
080 | inoltre i danni subiti durante l'attacco preferendo la direzione in cui si subiscono |
081 | meno danni. |
082 | Il cambio di angolo viene effettuato solo dopo alcuni controlli ridondanti e piu' |
083 | accurati verso il quadrante di destinazione. |
084 | Dopo il cambio dell'angolo il robot aspetta un certo numero di iterazioni (che variano |
085 | in base al tempo gia' trascorso e ai danni subiti) prima di riproporre l'attacco a |
086 | triangolo. Durante i cambi di angolo si controlla anche che non sia rimasto un unico |
087 | avversario; in tal caso, a meno di non aver subito danni notevoli (90%), si passa alla |
088 | fase 3. |
089 | |
090 | Durante l'attacco a triangolo il robot fissa la direzione di fuoco sull'avversario e |
091 | la routine di fuoco non perde mai il bersaglio, invece durante i cambi d'angolo la |
092 | routine di fuoco cambia bersaglio quando quello puntato diventa troppo distante. |
093 | |
094 | La routine di attacco a triangolo si e' dimostrata molto efficace soprattutto con |
095 | i robot piu' recenti, ma soffre i robot che attendono molto nell'angolo e che utilizzano |
096 | le toxiche (spero che quest'anno siano veramente pochi!); in particolare volevo fare i |
097 | complimenti ad Andrea Creola che con il suo Pippo2a vera bestia nera nei test dello scorso |
098 | anno insieme a Stanlio: senza questi due nei test Elminster ottiene il 76,5% e Druzil il |
099 | 79%! Di sicuro almeno pippo3 quest'anno sara' molto ostico per i miei robottini, quindi |
100 | nonostante i report ottimi da 2k1 in avanti, di punti deboli ce ne sono e la competizione |
101 | sara' durissima come sempre. |
102 | |
103 |
104 | FASE 3: |
105 | |
106 | La routine offensiva della fase 3 e' molto semplice: fino al 50% di danno esegue un |
107 | quadrato minimo al centro dell'arena, dopo il 50% di danni il quadrato si allarga |
108 | di 200 unita' in tutte le direzioni e l'oscillazione e' quindi molto lunga. |
109 | |
110 | Questa routine rende un po' meno nei test del 2k2, ma credo che sia piu' adatta |
111 | per il nuovo torneo soprattutto come FASE 3 del 4vs4. |
112 | |
113 | Soffre le toxiche ovviamente! |
114 |
115 | ROUTINE DI FUOCO: |
116 |
117 | La routine di fuoco e' derivata da un mix di quelle dello scorso anno con quelle |
118 | di Zorn e Rudolf di Alessandro Carlin. |
119 | |
120 | 1) La temporizzazione non � ottimale come lo scorso anno, ma in compenso la |
121 | precisione � migliorata grazie al puntamento primario delle routine di Ale |
122 | che ho modificato lievemente per renderle piu' veloci nell'esecuzione e |
123 | piu' precise nella prima correzione dell'angolo (ho aumentato a 10 la |
124 | risoluzione del primo scan). |
125 | 2) Il puntamento secondario rimane ampio (10) anche nelle correzioni dell'angolo |
126 | seguendo in maniera efficiente anche i nemici vicini. |
127 | 3) In un'unica chiamata (Fire) vengono scansionati 160 gradi e non piu' 180, per creare |
128 | una piccola intersezione dell'area di scansione tra 2 chiamate successive. |
129 | 4) Nel f2f non viene mai perso il nemico puntato, nel 4vs4 invece la scelta del cambio |
130 | del bersaglio in caso di distanza eccessiva e' determinata dalla variabile chdeg. |
131 |
132 |
133 | RINGRAZIAMENTI: |
134 |
135 | Un ringraziamento a tutti i "veterani" che continuano ad alimentare con i loro |
136 | robot, le loro utilities e soprattutto con la loro passione questo gioco meraviglioso: |
137 | in particolare a Simone Ascheri, Michelangelo Messina, Alessandro Carlin, Maurizio |
138 | Camangi e Andrea Creola che sono anche sempre presenti nella ML e che costituiscono di |
139 | fatto lo "sponsor umano" di Crobots. |
140 | Un grazie anche alle nuove "matricole", che quest'anno hanno contribuito a stabilire un |
141 | nuovo record di affluenza al torneo, e che spero continuino a partecipare ai prossimi |
142 | tornei e soprattutto si divertano. |
143 |
144 | In bocca al lupo a tutti e buon torneo 2k3! |
145 |
146 | */ |
147 |
148 |
149 | /*********************/ |
150 | /* Variabili globali */ |
151 | /*********************/ |
152 |
153 | int deg,rng,dir,odeg,orng,dam,t; |
154 | int xs,ys,en,xd,yd,zd,xmd,ymd,ez; |
155 | int timer,dmin,dmax,xdam,ydam,xyl,xyh,xyel,xyeh,chdeg,dd,dd2,tx; |
156 |
157 |
158 | /****************************************/ |
159 | /* Routines di movimento e di scansione */ |
160 | /****************************************/ |
161 |
162 |
163 | Up(d) { while (loc_y()<d) Fire(drive(90,100)); drive(90,0); } |
164 | Dw(d) { while (loc_y()>d) Fire(drive(270,100)); drive(270,0); } |
165 | Dx(d) { while (loc_x()<d) Fire(drive(0,100)); drive(0,0); } |
166 | Sx(d) { while (loc_x()>d) Fire(drive(180,100)); drive(180,0); } |
167 |
168 | Ymin(d1,d2) { while (loc_y()<d1) Fire(drive(d2,100)); drive(d2,0); } |
169 | Ymax(d1,d2) { while (loc_y()>d1) Fire(drive(d2,100)); drive(d2,0); } |
170 | Xmin(d1,d2) { while (loc_x()<d1) Fire(drive(d2,100)); drive(d2,0); } |
171 | Xmax(d1,d2) { while (loc_x()>d1) Fire(drive(d2,100)); drive(d2,0); } |
172 |
173 | Look(d) { return (scan(d-10,10)+scan(d+10,10)); } |
174 |
175 |
176 | /**********************/ |
177 | /* ROUTINE PRINCIPALE */ |
178 | /**********************/ |
179 |
180 |
181 | main() |
182 | { |
183 |
184 | /****************************************************/ |
185 | /* FASE 0: Calcolo parametri e ritirata nell'angolo */ |
186 | /****************************************************/ |
187 |
188 | chdeg=1; |
189 |
190 | if (xs=loc_x()>499) Dx(900); else Sx(100); |
191 | if (ys=loc_y()>499) Up(880); else Dw(120); |
192 | |
193 | Params(); |
194 | |
195 | xyl=95; xyh=905; xyel=55; xyeh=945; chdeg=0; t=40; |
196 | |
197 | Radar(); |
198 | |
199 | /******************************/ |
200 | /* FASE 1: Difesa nell'angolo */ |
201 | /******************************/ |
202 |
203 | if (en>1) { |
204 | while (++timer<260) { |
205 | if (tx) { |
206 | |
207 | if (xs) { |
208 | Run(180); while (loc_x()>950) LookX(); Stop(180); |
209 | Run(0); while (loc_x()<955) ; Stop(0); |
210 | } else { |
211 | Run(0); while (loc_x()<50) LookX(); Stop(0); |
212 | Run(180); while (loc_x()>45) ; Stop(180); |
213 | } |
214 | |
215 | } else { |
216 | |
217 | if (ys) { |
218 | Run(270); while (loc_y()>950) LookY(); Stop(270); |
219 | Run(90); while (loc_y()<955) ; Stop(90); |
220 | } else { |
221 | Run(90); while (loc_y()<50) LookY(); Stop(90); |
222 | Run(270); while (loc_y()>45) ; Stop(270); |
223 | } |
224 | |
225 | } |
226 | } |
227 | if (damage()<40) t=25; |
228 | if (timer<300) t-=20; |
229 | } |
230 | |
231 | if (en>1) Radar(); |
232 | |
233 | /***********************************************/ |
234 | /* FASE 2: Attacco dall'angolo e cambio angolo */ |
235 | /***********************************************/ |
236 |
237 | while (en>1) { |
238 | while (scan(xd,10) && (xdam<3)) { |
239 | deg=xd; |
240 | dam=damage(); |
241 | if (xs) { |
242 | if (ys) { Ymax(845,210); Ymin(945,150); } else { Ymin(155,150); Ymax(55,210); } |
243 | Dx(900); |
244 | } else { |
245 | if (ys) { Ymax(845,330); Ymin(945,30); } else { Ymin(155,30); Ymax(55,330); } |
246 | Sx(100); |
247 | } |
248 | xdam=damage()-dam; |
249 | } |
250 | if ((ydam-=3)<0) ydam=0; |
251 | if (!Look(xd)) { |
252 | chdeg=1; |
253 | if (xs=!xs) { Dx(300); if (!Look(xmd)) Dx(900); else { deg=xmd; Sx(100); xs=!xs; chdeg=0; } } else { Sx(700); if (!Look(xmd)) Sx(100); else { deg=xmd; Dx(900); xs=!xs; chdeg=0; } } |
254 | --t; |
255 | if (chdeg) { |
256 | Params(); |
257 | if (!Look(yd)) Radar(); |
258 | chdeg=0; |
259 | if ((t>1)) ydam=5; |
260 | } |
261 | xdam=0; |
262 | } |
263 |
264 | |
265 | while (scan(yd,10) && (ydam<3)) { |
266 | deg=yd; |
267 | dam=damage(); |
268 | if (ys) { |
269 | if (xs) { Xmax(845,240); Xmin(945,300); } else { Xmin(155,300); Xmax(55,240); } |
270 | Up(900); |
271 | } else { |
272 | if (xs) { Xmax(845,120); Xmin(945,60); } else { Xmin(155,60); Xmax(55,120); } |
273 | Dw(100); |
274 | } |
275 | ydam=damage()-dam; |
276 | } |
277 | if ((xdam-=3)<0) xdam=0; |
278 | if (!Look(yd)) { |
279 | chdeg=1; |
280 | if (ys=!ys) { Up(300); if (!Look(ymd)) Up(900); else { deg=ymd; Dw(100); ys=!ys; chdeg=0; } } else { Dw(700); if (!Look(ymd)) Dw(100); else { deg=ymd; Up(900); ys=!ys; chdeg=0; } } |
281 | --t; |
282 | if (chdeg) { |
283 | Params(); |
284 | if (!Look(xd)) Radar(); |
285 | chdeg=0; |
286 | if ((t>1)) xdam=5; |
287 | } |
288 | ydam=0; |
289 | } |
290 | |
291 | } |
292 | /****************************************/ |
293 | /* FASE 3: Attacco al centro dell'arena */ |
294 | /****************************************/ |
295 |
296 | chdeg=0; |
297 | |
298 | while (damage()<50) { |
299 | while (loc_x()<500) Fire(drive(0,100)); |
300 | Fire(drive(90,0)); |
301 | while (loc_y()<500) Fire(drive(90,100)); |
302 | Fire(drive(180,0)); |
303 | while (loc_x()>499) Fire(drive(180,100)); |
304 | Fire(drive(270,0)); |
305 | while (loc_y()>499) Fire(drive(270,100)); |
306 | Fire(drive(0,0)); |
307 | } |
308 |
309 | while (1) { |
310 | while (loc_x()<700) Fire(drive(0,100)); |
311 | Fire(drive(90,0)); |
312 | while (loc_y()<700) Fire(drive(90,100)); |
313 | Fire(drive(180,0)); |
314 | while (loc_x()>300) Fire(drive(180,100)); |
315 | Fire(drive(270,0)); |
316 | while (loc_y()>300) Fire(drive(270,100)); |
317 | Fire(drive(0,0)); |
318 | } |
319 |
320 | } |
321 |
322 |
323 | /*******************************/ |
324 | /* Routine di fuoco principale */ |
325 | /*******************************/ |
326 |
327 | Fire() |
328 | { |
329 | if (chdeg) if (rng>880) { rng=700; return deg+=120; } |
330 | if (rng=scan(odeg=deg,10)) |
331 | { |
332 | if (scan(deg-13,10)) { if (scan(deg-=5,2)) ; else deg-=4; return (cannon(deg+(deg-odeg),2*scan(deg,10)-rng)); } |
333 | if (scan(deg+13,10)) { if (scan(deg+=5,2)) ; else deg+=4; return (cannon(deg+(deg-odeg),2*scan(deg,10)-rng)); } |
334 | if (scan(deg,10)) { if (scan(deg-=2,2)) ; else deg+=4; return (cannon(deg+(deg-odeg),2*scan(deg,10)-rng)); } |
335 | |
336 | } else { |
337 | |
338 | if (rng=scan(deg+=340,10)) return cannon(deg,rng); |
339 | if (rng=scan(deg+=40,10)) return cannon(deg,rng); |
340 | if (rng=scan(deg+=300,10)) return cannon(deg,rng); |
341 | if (rng=scan(deg+=80,10)) return cannon(deg,rng); |
342 | if (rng=scan(deg+=260,10)) return cannon(deg,rng); |
343 | if (rng=scan(deg+=120,10)) return cannon(deg,rng); |
344 | if (rng=scan(deg+=220,10)) return cannon(deg,rng); |
345 | |
346 | deg+=230; |
347 | |
348 | } |
349 | } |
350 |
351 |
352 | /**********************************/ |
353 | /* Routine di conteggio avversari */ |
354 | /**********************************/ |
355 |
356 | Radar() |
357 | { |
358 | if (damage()>90) return (en=3); |
359 | en=0; |
360 | while (dmin<=dmax) en+=(scan(dmin+=20,10)>0); |
361 | dmin=zd-60; |
362 | } |
363 |
364 | /*********************************************/ |
365 | /* Routine per calcolo parametri dell'angolo */ |
366 | /*********************************************/ |
367 |
368 | Params() |
369 | { |
370 | xd=180*xs; |
371 | dmax=(dmin=(zd=(yd=90+180*ys)-45+90*(xs^ys))-60)+100; |
372 | if (xs) { |
373 | if (ys) { xmd=210; ymd=240; } else { xmd=150; ymd=120; } |
374 | } else { |
375 | if (ys) { xmd=330; ymd=300; } else { xmd=30; ymd=60; } |
376 | } |
377 | } |
378 |
379 | /*********************************/ |
380 | /* Routines utilizzate in FASE 1 */ |
381 | /*********************************/ |
382 |
383 | LookX() |
384 | { |
385 | LookZ(deg=yd); |
386 | if (dd=scan(xd,10)) { |
387 | if ((dd<(dd2=scan(yd,10))) || (!dd2)) { deg=xd; tx=!tx; } |
388 | } else LookAgain(xd,xmd); |
389 | } |
390 |
391 | LookY() |
392 | { |
393 | LookZ(deg=xd); |
394 | if (dd=scan(yd,10)) { |
395 | if ((dd<(dd2=scan(xd,10))) || (!dd2)) { deg=yd; tx=!tx; } |
396 | } else LookAgain(yd,ymd); |
397 | } |
398 |
399 | LookZ() |
400 | { |
401 | if (timer>140) { if (!Look(zd)) timer=10000; } else if (damage()>70) timer=10000; |
402 | } |
403 |
404 | LookAgain(d1,d2) { if (!Look(d1) && !scan(d2,10)) timer=10000; } |
405 |
406 | Run(d) |
407 | { |
408 | drive(d,100); |
409 | while (speed()<70) drive(d,100); |
410 | } |
411 |
412 | Stop(d) |
413 | { |
414 | if (d==deg) while (scan(d,10)>840) ; |
415 | drive(d,0); |
416 |
417 | if (!((rng=scan(odeg=deg,10)) && rng<880)) |
418 | if (!(rng=scan(deg+=340,10))) |
419 | if (!(rng=scan(deg+=40,10))) { while (speed()>59) drive(d,0); return ; } |
420 | |
421 | |
422 | if (scan(deg+10,10)) deg+=3; else deg+=357; |
423 | if (scan(deg+350,10)) deg+=358; else deg+=2; |
424 | if (scan(deg+10,10)) deg+=1; else deg+=359; |
425 | |
426 | cannon(deg,rng); |
427 | |
428 | while (speed()>59) drive(d,0); |
429 | } |