# HG changeset patch # User "Rex Tsai " # Date 1225253136 -28800 # Node ID 592d3b3b78982fe043e7feed6445e142eae6d60a # Parent ed616063032933b4c0ed2303c121be379fbb5fb4 implemented the WAR robot diff -r ed6160630329 -r 592d3b3b7898 Ikariam.pm --- a/Ikariam.pm Wed Oct 29 03:20:53 2008 +0800 +++ b/Ikariam.pm Wed Oct 29 12:05:36 2008 +0800 @@ -8,7 +8,7 @@ use Class::DBI::AutoLoader ( dsn => 'dbi:SQLite:dbname=ikariam.sqlite', options => { RaiseError => 1 }, - tables => ['cities', 'island', 'user', 'ally'], + tables => ['cities', 'island', 'user', 'ally', 'report'], use_base => 'Class::DBI::SQLite', namespace => 'Ikariam', ); @@ -97,6 +97,8 @@ use HTML::TagParser; use XML::LibXML qw(:encoding); use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ; +# use Time::ParseDate; +use POSIX; use utf8; sub new @@ -177,15 +179,16 @@ ]); my $extractor = new Ikariam::Extractor(content => $res->content); my $result = $extractor->{doc}->find('//table[@class="table01"][2]//tr'); + foreach my $tr ( @$result ) { my %user; + my $extractor = new Ikariam::Extractor(content => $tr->toString(1)); - $extractor->{doc} = $tr; my $href = $extractor->find('//td[@class="action"]/a/@href'); if($href =~ /index\.php\?view=sendMessage&with=(\d+)&oldView=highscore/) { $user{'id'} = $1; - # $user{'name'} = $extractor->find('//td[@class="name"]'); $user{'name'} = $user; + $user{'name'} = $extractor->find('//td[@class="name"]'); $user{'ally'} = $extractor->find('//td[@class="allytag"]/a/text()'); my $allyHref = $extractor->find('//td[@class="allytag"]/a/@href'); @@ -197,6 +200,7 @@ $users{$user{'id'}} = \%user; } } + # print(Dumper(\%users)); return \%users; } @@ -412,11 +416,22 @@ return $out; } -sub checkCity { +sub plunderCity { + my $self = shift; + my $cityId = shift; + $self->{mech}->get(sprintf("http://%s/index.php?view=plunder&destinationCityId=%d", $self->{server}, $cityId)); + $self->{mech}->submit_form( + form_number => 1, + fields => { + cargo_army_302 => '2', + } + ); +} + +sub changeCity { my $self = shift; my $cityId = shift; - # search for goods $self->{mech}->get(sprintf("http://%s/index.php", $self->{server})); $self->{mech}->submit_form( form_number => 2, @@ -424,6 +439,14 @@ cityId => $cityId, } ); +} + +sub checkCity { + my $self = shift; + my $cityId = shift; + + $self->changeCity($cityId); + my $res = $self->{mech}->get(sprintf("http://%s/index.php?view=city&id=%d", $self->{server}, $cityId)); my $extractor = new Ikariam::Extractor(content => $res->content); @@ -478,102 +501,119 @@ sub checkMilitaryAdvisorMilitaryMovements { my $self = shift; # TODO - # http://%s/index.php?view=militaryAdvisorMilitaryMovements my $res = $self->{mech}->get(sprintf('http://%s/index.php?view=militaryAdvisorMilitaryMovements', $self->{server})); my $extractor = new Ikariam::Extractor(content => $res->content); - my @homeland = $extractor->find('//div[@id="homeland"]'); - my @elsewhere = $extractor->find('//div[@id="elsewhere"]'); - $self->{'military'}->{attacks} = $#elsewhere+1; - $self->{'military'}->{wars} = $#homeland+1; + $self->{'military'}->{wars} = 0; + $self->{'military'}->{attack} = 0; + + foreach (qw/homeland elsewhere/) { + $self->{'military'}->{$_} = (); + my $result = $extractor->{doc}->find(sprintf('//div[@id="%s"]//ul[@id="battleReports"]/li[@class="enroute"]', $_)); + foreach my $div ( @$result ) { + my $extractor = new Ikariam::Extractor(content => $div->toString(1)); + my $f = $extractor->find('//div[@class="report"]/a[1]/@href'); + my $t = $extractor->find('//div[@class="report"]/a[2]/@href'), + $f = $1 if($f =~ /\?view=island&cityId=(\d+)/); + $t = $1 if($t =~ /\?view=island&cityId=(\d+)/); + + push @{$self->{'military'}->{$_}}, { from => $f, to => $t}; + if($_ eq 'homeland') { + $self->{'military'}->{wars}++; + } else { + $self->{'military'}->{attack}++; + } + } + } + # print(Dumper($self->{'military'})); +} + +sub checkMilitaryAdvisorReportView { + my $self = shift; + my $combatId = shift; + my $res = $self->{mech}->get(sprintf('http://%s/index.php?view=militaryAdvisorReportView&detailedCombatId=%s', $self->{server}, $combatId)); + my $extractor = new Ikariam::Extractor(content => $res->content); + + my %report; - # there are some details. -#
-# -#
+ $report{id} = $combatId; + my $c = $extractor->{doc}->toString(1); + + # FIXME 城鎮 6 級)的城牆( 2 級)為防禦部隊增加了 7% 的防禦力。 + while($c =~ /城鎮\s+(\d+)/gs) { + $report{cityLevel} = $1; + $report{wallLevel} = $2; + } + + $report{attacker} = $extractor->find('//div[@id="troopsReport"]//table[@id="result"]//th[@class="attackers"]'); + $report{defender} = $extractor->find('//div[@id="troopsReport"]//table[@id="result"]//th[@class="defenders"]'); + $report{winner} = $extractor->find('//div[@id="troopsReport"]//table[@id="result"]//td[@class="winner"]'); + $report{targetCity} = $extractor->find('//div[@id="troopsReport"]/div/h3/a/text()'); + my $href = $extractor->find('//div[@id="troopsReport"]/div/h3/a/@href'); + if($href =~ /index\.php\?view=island&id=(\d+)&selectCity=(\d+)/) { + $report{island} = $1; + $report{city} = $2; + } + $report{gold} = $extractor->find('//div[@id="troopsReport"]//ul[@class="resources"]/li[@class="gold"]'); + $report{wood} = $extractor->find('//div[@id="troopsReport"]//ul[@class="resources"]/li[@class="wood"]'); + $report{crystal} = $extractor->find('//div[@id="troopsReport"]//ul[@class="resources"]/li[@class="glass"]'); + $report{wine} = $extractor->find('//div[@id="troopsReport"]//ul[@class="resources"]/li[@class="wine"]'); + $report{sulfur} = $extractor->find('//div[@id="troopsReport"]//ul[@class="resources"]/li[@class="sulfur"]'); -#
-# -#
+ foreach(qw/gold wood crystal wine sulfur attacker defender winner/) { + $report{$_} =~ s/^.*?:\s+//; + $report{$_} =~ s/\s+$//; + $report{$_} =~ s/,//g; + } + return \%report; } sub checkMilitaryAdvisorCombatReports { my $self = shift; - my $content; - my $res = $self->{mech}->get(sprintf('http://%s/index.php?view=militaryAdvisorCombatReports', $self->{server})); - gunzip \$res->content => \$content - or die "gunzip failed: $GunzipError\n"; + my $page = shift || 0; + + my $res = $self->{mech}->get(sprintf('http://%s/index.php?view=militaryAdvisorCombatReports&start=%s', $self->{server}, $page)); + my $extractor = new Ikariam::Extractor(content => $res->content); + + my $result = $extractor->{doc}->find('//div[@id="troopsOverview"]//table/tr[position()<=10]'); + foreach my $tr ( @$result ) { + my $trExtractor = new Ikariam::Extractor(content => $tr->toString(1)); + my $date = $trExtractor->find('//td[@class="date"]'); + $date =~ s/^\s+//g; $date =~ s/\s+$//g; + + + my $href = $trExtractor->find('//td/a/@href'); + if($href =~ /index.php\?view=militaryAdvisorReportView&combatId=(\d+)/) { + my $report = Ikariam::Report->retrieve($1); + if(!$report) { + my $report_hash = $self->checkMilitaryAdvisorReportView($1); + $report = Ikariam::Report->insert($report_hash); - # TODO + if($date =~ /(\d+)\.(\d+)\. (\d+):(\d+)/) { + my $unixtime = mktime (0, $4, $3, $1, ($2-1), '108'); + $report->set('date', $unixtime); + } + $report->set('time', time); - # list down reports. - # /index.php?view=militaryAdvisorReportView&combatId=1887662 - # //form[@id='finishedReports']//a + $report->update(); + } else { + return; + } + } else { + return; + } + } + + my @moreCombats = $extractor->find('//div[@id="troopsOverview"]//table/tr[position()>10]//a/@href'); + foreach (@moreCombats){ + last if(/^javascript/); + if(/\?view=militaryAdvisorCombatReports&start=(\d+)/) { + next if($1 le $page); + $self->checkMilitaryAdvisorCombatReports($1); + last; + } + } } sub checkTownHall { diff -r ed6160630329 -r 592d3b3b7898 warfare.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/warfare.pl Wed Oct 29 12:05:36 2008 +0800 @@ -0,0 +1,136 @@ +#!/usr/bin/perl +use strict; +use Ikariam; +use Data::Dumper; +use Decision::ParseTree q{ParseTree}; +use YAML qw/LoadFile Dump DumpFile/; + +package Ikariam::Warfare::Rules; +use strict; +use Data::Dumper; + +Ikariam::User->has_many(cities => 'Ikariam::Cities'); +Ikariam::User->has_a(ally => 'Ikariam::Ally'); +Ikariam::Cities->has_a(user => 'Ikariam::User'); +Ikariam::Cities->has_a(island => 'Ikariam::Island'); +Ikariam::Cities->set_sql(sheeps => qq { + SELECT cities.cityId + FROM user, cities + WHERE user.id == cities.user + AND user.army_score_main == 0 + AND cities.island IN (SELECT island.id FROM island WHERE island.x <= ? AND island.x >= ? AND island.y <= ? AND island.y >= ? ) + ORDER BY cities.citylevel * (cities.citylevel - 1) * user.trader_score_secondary / 10000 DESC LIMIT 10 + } +); +Ikariam::Report->set_sql(attack => qq { + SELECT report.id + FROM report + WHERE report.city = ? + AND report.date >= ? + } +); + +sub new { + my ( $class, $i ) = @_; + my $self = { + ikariam => $i, + }; + return bless $self, $class; +} + +sub is_attacked { + my ($self, $city) = @_; + return ($self->{'ikariam'}->{'military'}->{attacks} > 0 ) ? 1 : 0; +} + +sub is_actionPoint_enough { + my ($self, $city) = @_; + return ($city->{actionPoints} > ($city->{maxActionPoints}/2) ) ? 1 : 0; +} + +sub is_army_available { + my ($self, $city) = @_; + return ($city->{army}->{Swordsman} > 2 ) ? 1 : 0; +} + + +sub locateVictim { + my ($self, $city, $x, $y) = @_; + my @cities = Ikariam::Cities->search_sheeps(($x + 6), ($x - 6), ($y + 6), ($y - 6)); + + foreach my $city (@cities) { + my $sheep = $city->user; + my $island = $city->island; + + # Ignore 假期模式 + next if($city->status eq 'v'); + unless ($city->status eq 'i') { + unless ($sheep->allyId == '0') { + my $ally = $sheep->ally; + # Ignore 聯盟人數大於10 + next if(defined($ally) && $ally->members > 10); + } + } + + # check if we over-attacked + my $c = Ikariam::Report->search_attack($city->cityId, time - 24*60*60 - 7*60*60)->count(); + # check the current plunders + foreach ($self->{ikariam}->{'military'}->{'homeland'}) { + $c++ if($_{to} eq $city->cityId); + } + next if($c >= 4); + + # { + # if(1) { + my $capture = $city->citylevel * ($city->citylevel - 1) * $sheep->trader_score_secondary / 10000; + my $line = sprintf("%d %s [%d,%d] %s %s/%s", + $capture, $city->status, + $island->x, $island->y, + $city->cityname, + $sheep->name, $sheep->ally); + printf("%s\n", $line); + # } + return $city->cityId; + } + return undef; +} + +sub engagement { + my ($self, $cityId, $x, $y) = @_; + my $victim = $self->locateVictim($cityId, $x, $y); + if(defined($victim)) { + $self->{ikariam}->changeCity($cityId); + $self->{ikariam}->plunderCity($victim); + } +} + +1; + +package main; + +if($#ARGV != 1) { die("Usage: $0 x y\n"); } +my ($x, $y) = @ARGV; + +our $i = new Ikariam($::server, $::user, $::pass); +our $rules = Ikariam::Warfare::Rules->new($i); + +$i->login; +my $cities = $i->check; +$i->checkMilitaryAdvisorCombatReports(); +print Dump($i->{'military'}); + +foreach my $cityId (keys(%$cities)) { + # build and upgrade for cities + my $tree = LoadFile('warfare.yaml'); + $cities->{$cityId}->{parse_path} = []; + $cities->{$cityId}->{parse_answer} = undef; + if(ParseTree($tree, $rules, $cities->{$cityId}) eq 'engagement') { + $rules->engagement($cityId, $x, $y); + sleep(30); + $i->checkMilitaryAdvisorMilitaryMovements(); + } + print Dump($cities->{$cityId}->{parse_path}); +} +DumpFile("warfare-dump.yaml", $cities); + +$i->logout; diff -r ed6160630329 -r 592d3b3b7898 warfare.yaml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/warfare.yaml Wed Oct 29 12:05:36 2008 +0800 @@ -0,0 +1,7 @@ +--- +- is_attacked: + 0: + - is_actionPoint_enough: + 1: + - is_army_available: + 1: engagement