MokaByte 78 - 8bre 2003 
Robocode
I parte: le basi
di
Simone Chiaretta
Da Alphaworks IBM un gioco per imparare a programmare object oriented in Java, costruendo robot sw che si sfidano in un’arena virtuale.

Introduzione
Inizia questo mese una serie di articoli dedicati al simulatore di battaglie tra robot lanciato da IBM lo scorso anno e che ha ormai appassionato centinaia di sviluppatori in tutto il mondo.
Nel corso dei prossimi mesi parlerò degli aspetti base del gioco, di quelli più avanzati usati dai robot di punta, passando da una breve storia del gioco per arrivare infine alle competizioni on-line e alla MokaRoboLeague.
In questo numero vedremo come iniziare ad usare questo programma, e le basi di funzionamento per permettervi di costruire il vostro primo “Bot”.

 

Cos’è Robocode?
Robocode è un simulatore di battaglia robotica facile da usare e portabile su tutte le piattaforme che supportano Java 2. Chiunque può costruire il suo robot, metterlo sul campo di battaglia, e lasciarlo combattere con gli avversari creati da altri sviluppatori.
Ma anche se far scontrare i robot è molto divertente, lo scopo primario di Robocode è quello di insegnare la programmazione in Java: invece che il costruire il solito front-end per un database o un componente di middleware, Robocode permette di costruire il “cervello” di un robot virtuale e di infondergli tutta l’intelligenza possibile.
Gli sviluppatori alla prime armi potranno imparare le conoscenze basilari, come ereditarietà, polimorfismo, gestione degli eventi, classi interne e simili. Gli sviluppatori esperti, potranno invece testare algoritmi e concetti quali intelligenza artificiale, algoritmi di ricerca ottimizzati, pattern matching, cercando di costruire un robot che sconfigga tutti gli avversari.

 

Prepariamo l’ambiente
Dopo aver verificato di possedere una versione di Java 1.4 o superiore, bisogna scaricare dal sito ufficiale di Robocode il package di installazione (http://robocode.alphaworks.ibm.com/installer/index.html). Da notare che è sufficiente solo la Runtime di Java, visto che il programma può usare per la compilazione dei robot anche
Jikes, il compilatore di IBM fornito con Robocode. Una volta scaricato il file basta lanciare il comando

java -jar robocode-setup.jar

per installare il programma che poi potrete lanciare direttamente dall’icona sul desktop o con i file batch. A questo punto vi comparirà il campo di battaglia con in corso una partita demo tra due dei robot predefiniti forniti come esempio insieme al simulatore.


Figura 1 – Tutti i robot di esempio in campo

L’IDE è composto da due parti: il campo di battaglia e l’editor dei robot.


Figura 2 – L’IDE di Robocode

Il campo di battaglia ospita il motore di simulazione e permette di creare nuove battaglie scegliendo i robot presenti nella directory, oppure importarne di nuovi dopo averli scaricati dai repository on-line. Da qui si posso visualizzare anche tutte le statistiche dei robot presenti sul campo di gioco e comandare l’esecuzione della battaglia.
L’editor è invece un semplice editor di testo con syntax highlighting per modificare il sorgente dei robot senza usare altri programmi. Integra inoltre la chiamata al compilatore ed il packager per creare i file JAR necessari per scambiare i robot su internet. Una volta compilati i robot sono pronti per essere inseriti direttamente nel campo di battaglia, senza ulteriori azioni da parte dello sviluppatore. Anatomia di un Robot e suo funzionamento
Un robot è costituito da 3 elementi, che ruotano e che possono muoversi indipendentemente gli uni dagli altri:

• La base
• La torretta con il cannone
• Il radar


Figura 3 – Parti di un robot Robocode

 

Comandi del robot
Iniziamo ora, prima di vedere la struttura tipo di un programma Bot, a elencare i comandi basilari presenti nella API di Robocode:

  • turnRight(double degree) e turnLeft(double degree) fanno ruotare tutto il robot di un certo
    angolo
  • ahead(double distance) e back(double distance) muovono il robot aventi o indietro di un certo numero di pixel
  • turnGunRight(double degree) e turnGunLeft(double degree) ruota la torretta
  • turnRadarRight(double degree) e turnRadarLeft(double degree) ruota la il radar che si trova sopra la torretta

Tutti questi comandi sono bloccanti, cioè non ritornano al chiamante fino a che non hanno finito di spostare ilrobot. Inoltre, ruotando una parte del robot, ruotano di conseguenza anche gli elementi superiori (es: ruoto la base, e ruotano anche torretta e radar). Questo comportamento può essere modificato chiamando il comando
setAdjustGunForRobotTurn(boolean flag): con flag a true la torretta rimane puntata nella stessa direzione mentre il robot gira sotto di essa (esistono due metodi analoghi anche per Radar su Robot e Radar su Torretta).

  • getX() e getY() ottengono la posizione nello schermo
  • getHeading(), getGunHeading(), getRadarHeading() ottengono la direzione nella quale puntano le 3 parti del robot
  • fire(double firePower) e fireBuller(double firePower) sparano usando un certa quantità di
    energia.

Per spiegare cosa sia il firePower bisogna guardare come è gestita l’energia e la vita dei robot. Ogni robot inizia la battaglia con un determinato livello di energia (100 punti) e ogni volta che viene colpito perde una quantità di energia proporzionale alla potenza del proiettile che lo ha colpito. Inoltre dei punti di energia vengono persi quando due robot si scontrano o quando un robot urta un muro.
Un robot muore quando la sua energia scende sotto 0.
La differenza tra i due metodi di sparo è che la versione fireBullet, oltre a sparare, ritorna il riferimento all’oggetto di tipo Bullet sparato, che poi può essere usato per elaborazioni successive dai robot più avanzati.
Infine diamo un’occhiata agli eventi che vengono sollevati: il principale è quello sollevato quando un robot entra nel cono di scansione del radar. Il Robot base ha già degli handler vuoti per tutti i possibili eventi, ma per ottenere delle reazioni utili dai propri robot, un programmatore deve overridarli e implementare delle operazioni utili basate sull’evento accaduto.

  • ScannedRobotEvent viene alzato quando un robot viene “scovato” dal radar
  • HitByBulletEvent viene alzato quando il proprio robot viene colpito da un proiettile
  • HitRobotEvent viene alzato quando ci si scontra con un altro robot
  • HitWallEvent viene alzato quando il robot sbatte contro un muro
  • BulletHitEvent viene alzato quando un proprio proiettile colpisce un nemico
  • RobotDeathEven viene alzato quando un avversario muore
  • WinEvent e DeathEvent vengono alzati quando finisce il round (in un caso il robot vince, nell’altro è stato ucciso)

La costruzione del Robot
Ora che abbiamo imparato le basi, possiamo iniziare a costruire il nostro robot. Per la realizzazione userò l’editor di testo integrato con l’IDE, ma si può anche usare un qualsiasi IDE o anche usare direttamente javac (Basta inserire nel classpath il file Robocode.jar).

Una volta aperto il Robot Editor, selezionare File>New>Robot: verrà chiesto il nome del Robot, che poi sarà anche il nome della class Java: inserire MokaRobot. In seguito verranno chieste le iniziali dell’autore, che diventerà il nome del package: inserire moka.
Nella finestra comparirà il codice sorgente di un robot basilare che va avanti e indietro e che spara dritto appena vede un avversario.
Questo è una versione abbreviata del codice proposto dall’editor:

package moka;
import robocode.*;

/**
* MokaRobot - a robot by (your name here)
*/
public class MokaRobot extends Robot{

  /* ZONA 1 */
  /**
  * run: MokaRobot's default behavior
  */
  public void run() {

  /* ZONA 2 */
  while(true) {
  
 /* ZONA 3 */
  }
 }

  /* ZONA 4 */
  /**
  * onScannedRobot: What to do when you see another robot
  */
  public void onScannedRobot(ScannedRobotEvent e) {
    fire(1);
  }


}


Questa è la struttura con quale ogni robot, dal più semplice al più avanzato, è realizzato.
Le zone marcate in rosso sono quelle nelle quali inserire il codice di gestione del robot:

Zona 1
In questa zona vengono dichiarate la variabili di classe accessibili da tutti i metodi del robot. Nel caso le variabili vengono dichiarate come static possono essere anche usate per mantenere lo stato tra i vari round di una battaglia
Zona 2
Il metodo run() è chiamato dal simulatore all’inizio di ogni round: tipicamente in questa zona ci sono le chiamate per inizializzare degli oggetti o lo stato di alcune parti del robot.
Zona 3
Qui si trova il cuore del robot: in questo loop infinito ci saranno le chiamate alle funzione per muovere il robot, prendere la mira e sparare.
Zona 4
Fuori dal metodo run() vengono definite tutte le funzioni di supporto usate per comandare il robot. In questa zona si trovano anche tutti gli eventhandlers che si vogliono usare: in questo esempio è implementato l’handler onScannedRobot per sparare non appena viene rilevato un robot nemico.

Ora inseriamo nelle zone di sopra delle chiamate alle API di Robocode per realizzare un robot che faccia qualcosa di interessante.

package moka;
import robocode.*;
import java.awt.Color;
/**
* MokaRobot - a robot by (your name here)
*/
public class MokaRobot extends Robot{
/**
* run: MokaRobot's default behavior
*/
public void run() {
  setColors(Color.red,Color.blue,Color.green);
  turnRadarRight(360);
  while(true) {
    turnRight(90);
    ahead(200);
    turnLeft(360);
    ahead(300);
    turnLeft(180);
    ahead(200);
  }
}
  /**
  * onScannedRobot: What to do when you see another robot
  */
  public void onScannedRobot(ScannedRobotEvent e) {
    fire(1);
  }
  /**
  * onHitByBullet: What to do when you're hit by a bullet
  */
  public void onHitWall(HitWallEvent e) {
    turnLeft(110 - getHeading());
    ahead(100);
  }
}

Analizziamo il codice che è stato messo in questo semplice robot:
Zona 1
Lasciata vuota: generalmente variabili di classe servono in robot più complessi per salvare lo stato attraverso i
round
Zona 2
In questo caso ho inizializzato il colore del robot e gli abbiamo fatto fare una scansione preliminare del campo
di battaglia
Zona 3
Fino a che il robot vive farà sempre questi movimenti:
• Gira a destra di 90°
• Va avanti di 200px
• Fa una scansione completa del campo (gira il radar di 360°)
• Fa inversione (gira di 180°)
• Va avanti di altri 200px
Zona 4
Ho implementato, oltre all’handler fornito dall’editor per l’evento di avvistamento robot, anche un metodo per reagire all’impatto con un muro (semplicemente giro di 110° e vado avanti di 100px). Siamo ora pronti per compilare il robot.

 

La prima battaglia
Una volta compilato il robot con il comando di Menu Compiler>Compile, torniamo al campo di battaglia, e apriamo la finestra per la creazione di una nuova battaglia (che sarà simile a quella in figura 4). Da qui selezioniamo il nostro robot MokaRobot e come avversario scegliamo il robot di esempio SittingDuck, poi premendo “Start Battle” avrà inizio la prima partita.


Figura 4
– Finestra New Battle

Effettivamente combattere con un robot che sta fermo non è una grossa sfida, ma potete testare il vostro nuovo robot con gli altri robot presenti tra quelli d’esempio. Volendo potete guardare nel file di risorse, un altro esempio di robot, con dei movimenti meno casuali e con un maggior controllo della torretta e del radar.

 


Conclusioni

In questo primo articolo della serie abbiamo visto come iniziare ad giocare con robocode, come funziona un robot e abbiamo realizzato il primo MokaRobot.
Ora avete le basi per poter iniziare a sperimentare le varie API di Robocode, costruendo i vostri robot, e,perché, partecipando ad una della leghe organizzate in rete. Vi esorto inoltre a visitare i siti riportati nelle Webliografia per approfondire l’argomento.
Nel prossimo articolo entreremo nel dettaglio di come funziona il simulatore di battaglia, e affronteremo la costruzione di un robot avanzato e di una squadra di robot.

 

Webliografia
[1] http://www.alphaworks.ibm.com/tech/robocode - Sito ufficiale di Robocode
[2] http://www.ecs.soton.ac.uk/~awo101/robocode.html - SnippetBot tutorial: tutti i primi robocoder hanno iniziato da lì
[3] http://robowiki.dyndns.org/perl/robowiki - Un wiki su Robocode, il punto di ritrovo attuale di tutti i robocoders
[4] http://www.robocoderepository.com – Il primo sito su robocode, e ancora ora repository generale per tutti i robot sviluppati e resi disponibili
[5] http://www.eternal-rumble.com – Sito che gestisce una ranking list generale

 

Risorse
Scarica il codice descritto nell’articolo

Simone Chiaretta – Laureato in Ingegneria Informatica al Politecnico di Milano, lavora presso una webagency di Milano con ruolo di progettista software e programmatore su tecnologia .NET. Nel tempo libero sviluppa applicativi web su piattaforma Tomcat e applicativi desktop con J2SE. Da oltre 1 anno e mezzo partecipa alla comunità di Robocode: al momento sta realizzando un programma per il tuning di robot con algoritmi basati su parametri lineari.

 
MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it