Forum

Example Bot
ZonkYo
08.12.10 - 19:09
Ich muss mal schauen ob der funktioniert, aber ich bin mir nicht sicher wie ich zwei Bots auf einem Account verwalte. Aber dennoch, als ein kurzes Beispiel sollte er funktionieren:


package Cosair::AI::Bot::TestBot;

use strict;

use Cosair::AI::Agent;
use Cosair::AI::Bot;
use Cosair::AI::Control;
use Cosair::AI::Fleet;
use Cosair::AI::Nation;
use Cosair::AI::NmeNation;
use Cosair::AI::NmePlanet;
use Cosair::AI::OwnNation;
use Cosair::AI::OwnPlanet;
use Cosair::AI::Planet;
use Cosair::AI::Util;

our(@ISA);
@ISA = qw(Cosair::AI::Bot);

sub name {
return 'TestBot';
}

### start editing from here on ###

use feature "switch";

# if your bot needs any initialisation,
# implement it in the following method.

sub init {
my $self = shift;
# sets initial values...
$self->set_mem('state',$self->STATES->{PREPARE});
$self->set_mem('attack_start',0);
$self->set_mem('attack_failed',0);
}


# these are the methods you may want to overwrite from "Cosair::AI::Bot"
# check the API reference documentation on the project website for more details

sub init_turn {
my $self = shift; # hier wird das Klassenobjekt uebergeben, wichtig!

$self->decide_target; # Aufruf einer selbst geschriebenen Methode

my $newstate = $self->decide_state; # Aufruf der FSM

if ($self->state ne $newstate) { # schauen ob sich was aendert
$self->log_message("Changed state to $newstate"); # das funktioniert nur mit "", mit '' nicht
# wenn ihr für sowas '' nutzt, dann so: $self->log_message('Changed state to %s', $newstate);
}
$self->set_mem('state', $newstate);

if ($self->nation->has_all_techs) { # so ruft man auch die eigene Nation auf
# das has_all_techs ist in der Nation.pm
$self->decide_taxrate;
}
}

sub decide_state {
my ($self) = @_; # das kann man auch so machen, wenn man mehr Parameter hat macht das auch Sinn ;)
# sprich, wenn ihr eine Methode mit 5 Parametern habt könnt ihr aussuchen, ob ihr
# my $bla = shift; my $blubb = shift; ... macht oder
# my ($bla, $blubb, $ente, ....) = @_;
# auch Arrays können so sehr nett übergeben werden:
# my ($self, @array) = @_; wird den ersten Parameter von @_ ($_[0]) nehmen, in $self
# packen und den rest in @array :-)

my $newstate = $self->state;
my $ship_count = 0;
$ship_count += $_->stationed_fleet for($self->control->own_nation->planets);
given($self->state) {
when ($self->STATES->{PREPARE}) {

if ($ship_count > 50) {
$newstate = $self->STATES->ATTACK
}
}

when ($self->STATES->{ATTACK}) {
if ($ship_count < 50) {
$newstate = $self->STATES->PREPARE;
}
}

}
}

sub decide_taxrate {
my $self = shift; # wir übergeben den Aufrufer. Immer!

my @tax_rates = qw(10 20 30 40 50 60 70 80); # damit man mal sieht was qw macht
# qw nimmt sich den hinten dran stehenden String und macht folgendes
# es nimmt den gegebenen Parameter und teilt ihn an jedem Leerzeichen
# und macht aus den einzlnen Parametern ein Array.
# Alternativ:
# my $string = "10 20 30 40 50 60 70 80";
# my @tax_rate = split(/ /, $string);
# erstellt ebenfalls ein Array aus dem String, / / ist Pattern Matching nach
# Perl Manier, man kann auch ' ' schreiben stattdessen.
return $tax_rates[rand $#tax_rates]; # macht folgendes:
# @tax_rates <- array, $tax_rates[PARAMETER] <- Inhalt an der Stelle Parameter;
# $#tax_rates <- gibt Laenge des Arrays wieder (also Anzahl Elemente - 1)
# rand <- randomize, wähle beliebige Zahl aus kleiner gleich wert.
}

sub decide_target {
my $self = shift;

my @nme_planets = $self->control->nme_planets; #so einfach bekommt man alle gegnerischen Planeten
@nme_planets = sort {
$a->distance_to_nation($self->nation)
<=>
$b->distance_to_nation($self->nation)} @nme_planets;

# so einfach geht sort; $a, $b sind implizite Parameter;
# die Methode macht also folgendes:
# forall p in @nme_planets forall o in sorted(@nme_planets): Wenn die Entfernung
# von p zum nächsten Planeten unserer Nation kleiner ist als die vom ersten in
# der sortieren Reihenfolge, dann kommt p vor den Planten, sonst wird weitergeschaut
# zumindest reicht das als einfache Erklärung, intern wird ein Bubblesort genutzt.
# man kann auch merge_sort nutzen (macht aber nicht so viel Sinn bei den paar Planeten)

my $target_planet = $nme_planets[0];
# my $target_planet = first {1} @nme_planets;
# die auskommentierte Zeile macht das selbe wie die andere

# return $target_planet; entweder so oder halt
$self->set_mem("current_target_id", $target_planet->id);
}

sub decide_global_fleet_movements {
my $self = shift;
given ($self->state) {
when ($self->STATES->{ATTACK}) {
my %events = $self->own_events;
# my $nme_nation = ;
my @possible_target_planets = $self->control->active_nme_nations->planets;
# das gibt euch alle feindlichen Planeten
my $target_planet = $possible_target_planets[rand @possible_target_planets];
# das ist eine Art ein Ziel zu wählen *hust*
foreach my $planet ($self->control->own_nation->planets) {
my $fleet = $planet->stationed_fleet;
$fleet->move_ships($target_planet, int($planet->stationed_cruises / 2), $planet->stationed_transports);
# so bewegt ihr Flotten
$self->set_mem('attack_start', 1);
}
}
}
}

sub decide_techlist {
my $self = shift;
# nicht sehr durchdachte Art der Forschung ^^
return qw (mines assaultcruiser starbase armouredcruiser security fabrication biomodelling army fusiondrive medicine);

}

sub decide_planet_items {
my ($self, $planet) = @_;

my @stuff_to_build = ($self->ITEMS->{CR})x17;
push @stuff_to_build, $self->ITEMS->{TR};
if ($self->control->own_nation->has_tech('mines')) {push @stuff_to_build, ($self->ITEMS->{SM})x7;}
return @stuff_to_build;
# offensichtlich was das macht, oder?
}


#################
# Hilfsmethoden #
#################

sub STATES {
my $self = shift;
return {
ATTACK => 'ATTACK',
PREPARATION => 'PREPARATION',
};
}

sub ITEMS {
my $self = shift;
return {
CR => "cruiser",
FR => "freighter",
TR => "transport",
CS => "colonyship",
MC => "medicenter",
BA => "barracks",
FA => "factory",
SB => "starbase",
BS => "biosphere",
SM => "mines",
};
}

sub TECHS {

sub TECHS {
my $self = shift;
return {
ARC => "armouredcruiser",
ASC => "assaultcruiser",
AF => "fabrication",
BM => "biomodelling",
CA => "army",
FD => "fusiondrive",
MM => "medicine",
OE => "starbase",
SN => "security",
SM => "mines",
};
}

1;
ZonkYo
07.12.11 - 09:20
Like I told you in the last meeting , this bot is just for showing how you might start implementing your bot. This bot is not perfect and as I recall mentioned in the meeting, does not work at all. This is probably due to some missing curly braces, for example in line 77 it is written
$newstate = $self->STATES->ATTACK;

That will fail! This is due to the fact, that this is a method call for a method that does not exist. As you all should have figured out right now, $self means your bot.
So this is your bot, looking for a method called STATES, the first helper method. After that it is looking for another method, called ATTACK that it of course won't find. Instead it should have been like two lines above, where is written

$self->STATES->{PREPARE}

Now an explaination for this:
The method STATES gives you an anonymous hash as a result. If your hash has a name, you address it usually as $hashname{$key} or $hashname{'key'}. But since we have an anonymous hash here, we have to access it with ->{ATTACK}.
Then here are two possibilities. Either you do it like I did it an access it directly since you now what is given to you by the method you called or you make two lines out of my one liner. That would be something like:
my $hashref = $self->STATES;
$newstate = $hashref->{ATTACK};

There is no big difference between the two ways to handle this but you will have to figure out for yourselves which one you prefer.

As I reread the code I saw the comments were in German. That is due to last years students, they were all Germans. If you want to have the code running and with english comments you can write either here or send me a mail.

Cheerio,

Wolfgang
Back to Topic Overview

Back to Main Page