Programmeerimise algkursus Harjutus 4
Meie eelmises tunnis ehitatud vastaseid sihtiv robot laseb juba päris hästi. Paraku saavad teised talle veel paremini pihta. "Seisev tank on surnud tank," ütlevad sõjaväelased. Paneme oma tanki liikuma.
Sisukord
Dingel-dangel kellapendel: sügame edasi-tagasi
Algoritm võiks olla selline:
- Teeme radariga tiiru
- Sõidame edasi
- Teeme radariga tiiru
- Sõidame tagasi
Kuna radari koodi ei ole mõistlik Copy-Paste-da, siis teeme sõidusuuna jaoks eraldi muutuja. Miks just globaalmuutuja? Sest ma kahtlustan, et seda läheb rohkem kui ühes meetodis vaja.
public class LollRobot extends Robot {
String siga_sihikul; // Siga, mida me seekord sihime
String uus_siga; // Vahemuutujad uue lähima vastase leidmiseks
double min_kaugus;
double laksuTugevus = 2.0; // Kui kõvasti me kavatseme laskma hakata?
int suund = 1; // Kas sõidame parasjagu edasi või tagasi?
...
Nüüd paneme tankiniru edasi-tagasi sõitma. Teeme radaritiiru ära, sõidame natuke aega etteantud suunas, muudame suuna vastupidiseks ja hakkame otsast peale.
public void run() {
// Ära keera tukki koos kerega ega radarit koos tukiga!
setAdjustGunForRobotTurn(true);
setAdjustRadarForGunTurn(true);
while(true) {
// Enne otsimist on lähim siga lõpmata kaugel
min_kaugus = Double.POSITIVE_INFINITY;
// Radari scan
turnRadarLeft(360);
// Kuningas on surnud, elagu kuningas
siga_sihikul = uus_siga;
// Dingel-dangel, kellapendel
ahead(100 * suund);
suund = -suund;
}
}
Põikleme paremini: keerame end vastasega risti
Vastase kuulide eest ära põiklemine tuleb märksa paremini välja, kui me oleme kuuli lennutrajektooriga võimalikult risti (vaata joonist). Vastasega risti keeramise kood on meil tegelikult olemas onHitByBullet meetodis, selle võiks sealt nüüd välja võtta, natuke mõistlikumaks kohendada (nurk tuleb normaliseerida) ja õigesse kohta asetada. Loogika võiks olla selline, et hoiame end parasjagu välja valitud vastasega risti: tõenäoliselt teevad lähemal paiknevad vennad mulle rohkem haiget kui kaugemal sitsivad.
public void onScannedRobot(ScannedRobotEvent e) {
double vastase_kaugus = e.getDistance();
double vastase_peilung = e.getBearing();
String vastase_nimi = e.getName();
// Kas on meie väljavalitu?
if(vastase_nimi.equals(siga_sihikul)) {
// Keerame tuki sea suunda ja anname tina!
double keeramisnurk = arvutaKeeramisnurk(vastase_peilung);
keeramisnurk = normalRelativeAngle(keeramisnurk + arvutaEttelaskmisnurk(e));
turnGunRight(keeramisnurk);
fire(laksuTugevus);
// Keerame ennast vastasega risti
keeramisnurk = normalRelativeAngle(90 - vastase_peilung);
turnLeft(keeramisnurk);
}
// Kas on lähemal, kui kõik teised?
if(vastase_kaugus < min_kaugus) {
uus_siga = vastase_nimi;
min_kaugus = vastase_kaugus;
}
}
Iseseisev töö
- Tanki keeramine vastasega risti võiks olla efektiivsem. Kuna me sõidame niikuinii edasi-tagasi, siis ei ole vahet kumbale poole on meie esiosa. Seetõttu ei tohiks tanki keerata kunagi rohkem kui 90 kraadi. Lisa koodi sobilikud if laused, mis selle loogika realiseerivad: kui tanki keeramise nurk on suurem kui 90 või väiksem kui -90 kraadi, siis vastavalt liida või lahuta sealt 180 kraadi maha (umbes nagu normalRelativeAngle teeb).
- Praegu võib robot jääda kergesti nurka või seina äärde pendeldama, samuti ei sõida ta eriti kaugemale oma esialgsest tekkimiskohast. Intelligentsem oleks sõita mitte päris risti vastasega, vaid natuke diagonaalis tema poole. Paras nurk on umbes 15 kraadi. Lisa see tarkus tanki keeramisnurga arvutamisse: olenevalt sõidusuunast kas liida või lahuta keeramisnurgast 15 kraadi.
Lisalugemist
Nagu ikka, need kes head koodi tahavad ei saa jääda lihtsate ja lollide asjade juurde. Õppida, õppida õppida.
- http://www.codepoet.org/~markw/robocode/basic_movement.html
- http://www.ibm.com/developerworks/java/library/j-antigrav/
- http://testwiki.roborumble.org/w/index.php?title=AntiGravityMovement
- http://robowiki.net/cgi-bin/robowiki?WaveSurfing
- http://testwiki.roborumble.org/w/index.php?title=Movement
- http://robowiki.net/cgi-bin/robowiki?Movement