Mercurial > eagle-eye
view Ikariam.pm @ 52:d2ac1e198ce4
implement a new agent based on Decision Tree (Decision::ParseTree)
author | "Rex Tsai <chihchun@kalug.linux.org.tw>" |
---|---|
date | Mon, 20 Oct 2008 19:07:53 +0800 |
parents | 96ee35378696 |
children | 2d3c394b7940 |
line wrap: on
line source
#!/usr/bin/env perl BEGIN { foreach (((getpwuid($<))[7], $ENV{HOME}, $ENV{LOGDIR}, ".")) { require "$_/.eagleeye.pm" if (-f "$_/.eagleeye.pm"); } } use Class::DBI::AutoLoader ( dsn => 'dbi:SQLite:dbname=ikariam.sqlite', options => { RaiseError => 1 }, tables => ['cities', 'island', 'user'], use_base => 'Class::DBI::SQLite', namespace => 'Ikariam', ); package Ikariam; use strict; use Data::Dumper; use LWP; # use LWP::Debug qw(+ -conns -trace -debug); use LWP::Debug qw(+trace); use HTTP::Cookies; use WWW::Mechanize; use HTML::TagParser; use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ; sub new { my ($class, $server, $user, $pass) = @_; my $self = { mech => WWW::Mechanize->new( agent => "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008092816 Iceweasel/3.0.1 (Debian-3.0.1-1)", timeout => 10, ), server => $server, user => $user, pass => $pass, }; $self->{mech}->cookie_jar(HTTP::Cookies->new(file => "/tmp/ikariam-cookies.txt", autosave => 1)); $self->{mech}->default_headers->push_header('Accept-Encoding', 'deflate'); return bless $self, $class; } sub viewScore { my $self = shift; my $type = shift || 'score'; my $user = shift || ''; my $offset = shift || 0; my $res = $self->{mech}->post(sprintf("http://%s/index.php", $self->{server}), [ highscoreType => $type, offset => $offset, searchUser => $user, view => 'highscore' ]); my $c; my $status = gunzip \$res->content => \$c or die "gunzip failed: $GunzipError\n"; my %users; my $html = HTML::TagParser->new($c); my ($table) = $html->getElementsByAttribute("class", "table01"); return %users if(!defined($table)); my @elems = getElementsByTagName($table, "tr"); foreach my $elem (@elems) { my $e; my %user; $e = getElementsByAttribute($elem, "class", "action"); $e = getElementsByTagName($e, "a"); if(defined ($e) && $e->getAttribute('href') =~ /index\.php\?view=sendMessage&with=(\d+)&oldView=highscore/) { $user{'id'} = $1; $e = getElementsByAttribute($elem, "class", "name"); $user{'name'} = $e->innerText(); $e = getElementsByAttribute($elem, "class", "allytag"); $user{'ally'} = $e->innerText(); $e = getElementsByTagName($e, "a"); if($e->getAttribute('href') =~ /\?view=allyPage&allyId=(\d+)/) { $user{'allyId'} = $1; } $e = getElementsByAttribute($elem, "class", "score"); $user{$type} = $e->innerText(); $user{$type} =~ s/,//g; $users{$user{'id'}} = \%user; } else { next; } } return \%users; } sub viewWorldMap { my $self = shift; my $x = shift; my $y = shift; if(!defined($x) && !defined($y)) { die('location required'); } my $res = $self->{mech}->post(sprintf("http://%s/index.php?view=worldmap_iso", $self->{server}), [ xajax => 'getMapData', 'xajaxargs[]' => $x, 'xajaxargs[]' => $y, xajaxr => time, ]); my $c; my $status = gunzip \$res->content => \$c or die "gunzip failed: $GunzipError\n"; my @islands; # parsing xjxobj while($c =~ /<cmd n="jc" t="addToMap"><xjxobj><e><k>0<\/k><v><!\[CDATA\[(\d+)\]\]><\/v><\/e><e><k>1<\/k><v><!\[CDATA\[(\d+)\]\]><\/v><\/e><e><k>2<\/k><v><!\[CDATA\[(\d+)\]\]><\/v><\/e><e><k>3<\/k><v><!\[CDATA\[(\d+)\]\]><\/v><\/e><e><k>4<\/k><v><!\[CDATA\[(\d+)\]\]><\/v><\/e><e><k>5<\/k><v><!\[CDATA\[(\w+)\]\]><\/v><\/e><e><k>6<\/k><v><!\[CDATA\[(\d+)\]\]><\/v><\/e><e><k>7<\/k><v><!\[CDATA\[(\d+)\]\]><\/v><\/e><\/xjxobj><\/cmd>/g) { my %island; $island{id} = $3; $island{x} = $1; $island{y} = $2; $island{name} = $6; $island{tradegood} = $4; $island{wonder} = $5; # $7 ? $island{people} = $8; push @islands, \%island; } return @islands; } sub viewHomeMap { my $self = shift; my $res = $self->{mech}->get(sprintf("http://%s/index.php?view=worldmap_iso", $self->{server})); my $c; my $status = gunzip \$res->content => \$c or die "gunzip failed: $GunzipError\n"; # m[50][36]=new Array(564,1,5,'Risietia', '5', 13); # x = 43-57 = 6 # y = 27-41 = 6 my @islands; while($c =~ /m\[(\d+)\]\[(\d+)\]=new Array\((\d+),(\d+),(\d+),'(\w+)', '(\d+)', (\d+)\);/g) { my %island; $island{id} = $3; $island{x} = $1; $island{y} = $2; $island{name} = $6; $island{tradegood} = $4; $island{wonder} = $5; # $7 ? $island{people} = $8; #foreach my $i (sort(keys(%island))) #{ # printf ("%s %s\n", $i, $island{$i}); #} #print("\n"); push @islands, \%island; } return @islands; } sub viewIsland { my $self = shift; my $island = shift; my $res = $self->{mech}->get(sprintf("http://%s/index.php?view=island&id=%s", $self->{server}, $island)); my $c; my $status = gunzip \$res->content => \$c or die "gunzip failed: $GunzipError\n"; my $html = HTML::TagParser->new($c); # find inactivity and vacation my %status; foreach my $class (qw/inactivity vacation/) { my @elems = $html->getElementsByAttribute("class", $class); foreach my $elem (@elems) { if($elem->innerText() =~ /^(.*?) \((\w)\)/) { $status{$1} = $2; # printf("%s\n", $elem->innerText()); } } } # find content my @elems = $html->getElementsByClassName( "cityinfo" ); my @cities; foreach my $elem (@elems) { my %info; my @e = getElementsByTagName($elem, "li"); $info{'cityname'} = substr($e[0]->innerText(), 8); $info{'citylevel'} = substr($e[1]->innerText(), 14); $info{'owner'} = substr($e[2]->innerText(), 8); $info{'ally'} = substr($e[3]->innerText(), 8); delete($info{'ally'}) if($info{'ally'} eq '-'); @e = getElementsByAttribute($elem, "class", "messageSend"); if ( $e[0]->getAttribute("href") =~ /with=(\d+)&destinationCityId=(\d+)/) { $info{'user'} = $1; $info{'cityId'} = $2; } # update status; if(defined($status{$info{'cityname'}})) { $info{'status'} = $status{$info{'cityname'}}; } else { $info{'status'} = undef; } # print(Dumper(\%info)); push @cities, \%info; } return @cities; } sub build { my $self = shift; my $type = shift; my $cityId = shift; die ("only wall are implmeneted") unless ($type eq "wall"); die ("we don't know about this city") unless(defined($self->{'cities'}->{$cityId})); my $position = -1; my @locations = @{$self->{'cities'}->{$cityId}->{locations}}; foreach (0..$#locations) { $position = $_ if($locations[$_] == $type); } if($position == -1) { warn("we don't have the building yet."); } else { my $res = $self->{mech}->post(sprintf('http://%s/index.php', $self->{server}), [ action => 'CityScreen', 'function' => 'upgradeBuilding', id => $cityId, position => $position, level => $self->{'cities'}->{$cityId}->{buildings}->{$type}, oldView => $type, ]); } } sub run { my $self = shift; # defense. die("Not implemented"); } sub research { my $self = shift; my $type = shift; my $cityId = shift; # check if we are researching the same stuff my $res = $self->{mech}->get(sprintf('http://%s/index.php?action=CityScreen&function=changeResearch&id=%s&researchType=%s', $self->{server}, $cityId, $type)); # my $content; # gunzip \$res->content => \$content # or die "gunzip failed: $GunzipError\n"; # # print ($content); } sub checkResearch { my $self = shift; my $cityId = shift; my $res = $self->{mech}->get(sprintf('http://%s/index.php?view=researchOverview&id=%s', $self->{server}, $cityId)); my $content; gunzip \$res->content => \$content or die "gunzip failed: $GunzipError\n"; my $html = HTML::TagParser->new($content); my @elems = $html->getElementsByAttribute('class', 'explored'); my $out = {}; foreach my $elem (@elems) { my @items = getElementsByTagName($elem, "a"); foreach my $item (@items) { if($item->getAttribute('href') =~ /view=researchDetail&id=\d+&position=\d+&researchId=(\d+)$/) { @$out{$1} = $item->innerText(); } } } return $out; } sub checkCity { my $self = shift; my $cityId = shift; my $res = $self->{mech}->post(sprintf('http://%s/index.php', $self->{server}), [ action => 'header', cityId => $cityId, function => 'changeCurrentCity', id => $cityId, oldView => 'city', ]); # XXX } sub check { my $self = shift; # looking for cities foreach my $cityId (keys(%{$self->{'cities'}})) { # search for goods my $res = $self->{mech}->post(sprintf('http://%s/index.php', $self->{server}), [ action => 'header', cityId => $cityId, function => 'changeCurrentCity', id => $cityId, oldView => 'city', ]); my $content; gunzip \$res->content => \$content or die "gunzip failed: $GunzipError\n"; my $html = HTML::TagParser->new($content); my @elems; my ($elem) = $html->getElementsByAttribute("id", "value_gold"); $self->{'cities'}->{$cityId}->{resources}->{gold} = $elem->innerText(); $self->{'cities'}->{$cityId}->{resources}->{gold} =~ s/,//g; my ($elem) = $html->getElementsByAttribute("class", "city"); $self->{'cities'}->{$cityId}->{name} = $elem->innerText(); my ($elem) = $html->getElementsByAttribute("class", 'constructionSite'); $self->{'cities'}->{$cityId}->{construction} = 0; $self->{'cities'}->{$cityId}->{construction} = 1 if(defined($elem)); # check goods foreach my $good (qw/wood wine marble crystal sulfur/) { my ($elem) = $html->getElementsByAttribute("id", "value_" . $good); $self->{'cities'}->{$cityId}->{resources}->{$good} = $elem->innerText(); $self->{'cities'}->{$cityId}->{resources}->{$good} =~ s/,//g; } # search locations foreach my $i (0..14) { my ($elem) = $html->getElementsByAttribute("id", "position" . $i); my $building = $elem->getAttribute('class'); if (!($building =~ /buildingGround/)) { $self->{'cities'}->{$cityId}->{locations}[$i] = $building; my $span = getElementsByAttribute($elem, "class", "textLabel"); my (undef, undef, $level) = split(/ /, $span->innerText()); $self->{'cities'}->{$cityId}->{buildings}->{$building} = $level; } } $res = $self->{mech}->get(sprintf('http://%s/index.php?view=militaryAdvisorMilitaryMovements', $self->{server}, $cityId)); gunzip \$res->content => \$content or die "gunzip failed: $GunzipError\n"; $self->{'cities'}->{$cityId}->{force}->{attacks} = $1 if($content =~ /敵人攻擊: (\d+)/); $self->{'cities'}->{$cityId}->{force}->{wars} = $1 if($content =~ /我方軍隊行程: (\d+)/); # if($content =~ /更新戰鬥報告: (\d+)/); # if($content =~ /新的戰鬥報告: (\d+)/); # sub checkTownHall { $res = $self->{mech}->get(sprintf('http://%s/index.php?view=townHall&id=%d', $self->{server}, $cityId)); gunzip \$res->content => \$content or die "gunzip failed: $GunzipError\n"; # check happiness # Happiness = Basic bonuses (196 + Capital Bonus + Holiday Bonus(25)) + # Wine (Tavern Base(12*level) + # Tavern Bonus(80*step)) + # Culture (Museum Base(20*level) + # Cultural Goods Bonus(50*Cultural Goods)) - # Population (population) - # Corruption (Corruption rate * population) # # Growth Rate = Happiness * 0.02 $html = HTML::TagParser->new($content); my @happiness = ("ecstatic", "happy", "neutral", "sad", "outraged"); foreach my $j (0..$#happiness) { my ($elem) = $html->getElementsByAttribute("class", sprintf("happiness happiness_%s", $happiness[$j])); if(defined($elem)) { $self->{'cities'}->{$cityId}->{happiness} = $j; $self->{'cities'}->{$cityId}->{happiness_text} = $happiness[$j]; } } # Space, 房屋數 $self->{'cities'}->{$cityId}->{"space"} = {}; foreach my $j (qw/occupied total/) { my ($elem) = $html->getElementsByAttribute("class", sprintf("value %s", $j)); if(defined($elem)) { $self->{'cities'}->{$cityId}->{"space"}->{$j} = $elem->innerText(); } } # Actions # <span id="value_maxActionPoints">1</span> # <li class="incomegold incomegold_negative"> # <li class="incomegold incomegold_positive"> # <span class="value">-178</span> my ($elem) = $html->getElementsByAttribute("title", "目前腐敗程度"); if(defined($elem)) { $self->{'cities'}->{$cityId}->{corruption} = $elem->innerText(); $self->{'cities'}->{$cityId}->{corruption} =~ s/%//g; } # countCiizens my @citizens_type = qw/citizens woodworkers specialworkers scientists/; @elems = $html->getElementsByAttribute('class', 'count'); $self->{'cities'}->{$cityId}->{'citizens'} = {}; $self->{'cities'}->{$cityId}->{'citizens'}->{total} = 0; foreach my $i (0..$#citizens_type) { $self->{'cities'}->{$cityId}->{'citizens'}->{$citizens_type[$i]} = $elems[$i]->innerText(); $self->{'cities'}->{$cityId}->{'citizens'}->{total} += $elems[$i]->innerText();; } # } $self->{'cities'}->{$cityId}->{'research'} = $self->checkResearch($cityId); # sub checkArmies { my %force_types; $force_types{'army'} = [ qw/undef undef Slinger Swordsman Phalanx Ram Archer Catapult Gunsman Mortar SteamGiant Gyrocopter Bombardier Doctor Cook/ ]; $force_types{'fleet'} = [ qw/undef undef Ram-Ship BallistaShip Flamethrower CatapultShip MortarShip PaddleWheelRam DivingBoat/ ]; foreach my $x (qw/army fleet/) { $self->{'cities'}->{$cityId}->{$x} = {}; # search army $res = $self->{mech}->get(sprintf('http://%s/index.php?view=cityMilitary-%s&id=%d', $self->{server}, $x, $cityId)); gunzip \$res->content => \$content or die "gunzip failed: $GunzipError\n"; $html = HTML::TagParser->new($content); @elems = $html->getElementsByTagName('td'); foreach my $j (0..$#{$force_types{$x}}) { next if($force_types{$x}[$j] eq 'undef'); if($elems[$j]->innerText() == '-') { $self->{'cities'}->{$cityId}->{$x}->{$force_types{$x}[$j]} = 0; } else { $self->{'cities'}->{$cityId}->{$x}->{$force_types{$x}[$j]} = $elems[$j]->innerText(); } } } } # print Dumper($self->{'cities'}); return $self->{'cities'}; } sub logout { my $self = shift; $self->{mech}->get(sprintf('http://%s/index.php?action=loginAvatar&function=logout', $self->{server})); } sub login { my $self = shift; my $res = $self->{mech}->post(sprintf("http://%s/index.php?action=loginAvatar&function=login", $self->{server}), [ name => $self->{user}, password => $self->{pass}, ]); my $c; my $status = gunzip \$res->content => \$c or die "gunzip failed: $GunzipError\n"; if($c =~ /錯誤!/) { die ("password error\n"); } else { my $html = HTML::TagParser->new($c); my @elems; @elems = $html->getElementsByAttribute("class", "avatarCities coords"); foreach my $elem (@elems) { # my cities $self->{'cities'}->{$elem->getAttribute('value')} = {}; } } } sub getElementsByTagName { my $element = shift; my $tagname = lc(shift); my ( $flat, $cur ) = @$element; my $out = []; for( ; $cur <= $#$flat ; $cur++ ) { last if ($flat->[ $cur + 1 ]->[001] eq $element->tagName() ); next if ($flat->[$cur]->[001] ne $tagname ); next if $flat->[$cur]->[000]; # close my $elem = HTML::TagParser::Element->new( $flat, $cur ); return $elem unless wantarray; push( @$out, $elem ); } return unless wantarray; @$out; } sub getElementsByAttribute { my $element = shift; my $key = lc(shift); my $val = shift; my ( $flat, $cur ) = @$element; my $out = []; for ( ; $cur <= $#$flat ; $cur++ ) { next if $flat->[$cur]->[000]; # close my $elem = HTML::TagParser::Element->new( $flat, $cur ); my $attr = $elem->attributes(); next unless exists $attr->{$key}; next if ( $attr->{$key} ne $val ); return $elem unless wantarray; push( @$out, $elem ); } return unless wantarray; @$out; } 1;