# HG changeset patch # User "Rex Tsai " # Date 1224500873 -28800 # Node ID d2ac1e198ce4673fec3394170dac16ff54d7510e # Parent bc31729f29f46930dde479387bf54fcf7b950325 implement a new agent based on Decision Tree (Decision::ParseTree) diff -r bc31729f29f4 -r d2ac1e198ce4 Ikariam.pm --- a/Ikariam.pm Sat Oct 18 22:24:03 2008 +0800 +++ b/Ikariam.pm Mon Oct 20 19:07:53 2008 +0800 @@ -241,6 +241,97 @@ 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; @@ -286,7 +377,7 @@ foreach my $i (0..14) { my ($elem) = $html->getElementsByAttribute("id", "position" . $i); my $building = $elem->getAttribute('class'); - if ($building ne "buildingGround land") { + if (!($building =~ /buildingGround/)) { $self->{'cities'}->{$cityId}->{locations}[$i] = $building; my $span = getElementsByAttribute($elem, "class", "textLabel"); my (undef, undef, $level) = split(/ /, $span->innerText()); @@ -303,7 +394,7 @@ # if($content =~ /更新戰鬥報告: (\d+)/); # if($content =~ /新的戰鬥報告: (\d+)/); - # check townHall + # 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"; @@ -351,7 +442,7 @@ $self->{'cities'}->{$cityId}->{corruption} =~ s/%//g; } - # count + # countCiizens my @citizens_type = qw/citizens woodworkers specialworkers scientists/; @elems = $html->getElementsByAttribute('class', 'count'); $self->{'cities'}->{$cityId}->{'citizens'} = {}; @@ -363,14 +454,11 @@ $self->{'cities'}->{$cityId}->{'citizens'}->{total} += $elems[$i]->innerText();; } - # production - # skin/resources/icon_gold.gif - # skin/resources/icon_wood.gif - # skin/resources/icon_sulfur.gif (?) - # skin/resources/icon_research.gif + # } + + $self->{'cities'}->{$cityId}->{'research'} = $self->checkResearch($cityId); - - # check armies + # 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/ ]; @@ -432,14 +520,16 @@ } sub getElementsByTagName { - my $element = shift; + my $element = shift; my $tagname = lc(shift); my ( $flat, $cur ) = @$element; my $out = []; for( ; $cur <= $#$flat ; $cur++ ) { - next if ( $flat->[$cur]->[001] ne $tagname ); - next if $flat->[$cur]->[000]; # close + 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 ); diff -r bc31729f29f4 -r d2ac1e198ce4 agent.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent.pl Mon Oct 20 19:07:53 2008 +0800 @@ -0,0 +1,145 @@ +#!/usr/bin/perl + +use strict; +use Ikariam; +use Data::Dumper; +use Decision::ParseTree q{ParseTree}; +use YAML qw/LoadFile Dump/; + +package Ikariam::Cities::Rules; +use strict; +use Data::Dumper; + +sub new { + my ( $class ) = @_; + my $self = {}; + return bless $self, $class; +} + +sub is_Attacked { + my ($self, $city) = @_; + return ($city->{force}->{attacks} > 0 ) ? 1 : 0; +} + +sub is_constructing { + my ($self, $city) = @_; + return ($city->{construction} > 0 ) ? 1 : 0; +} + +sub is_wall_enough { + my ($self, $city) = @_; + # TODO 應該以防禦力計算 + return ($city->{buildings}->{wall} >= $city->{buildings}->{townHall} ? 1 : 0); +} + +sub is_space_enough { + my ($self, $city) = @_; + # TODO 應該以消耗率/時間計算 + return ($city->{space}->{total} <= ($city->{space}->{occupied}+6) ? 1 : 0) +} + +sub is_corruption { + my ($self, $city) = @_; + return 0; +} + +sub is_happiness +{ + my ($self, $city) = @_; + # TODO 以 fuzzy 取出合理 happiness 值 + return ($city->{happiness} >= 2 ? 1 : 0) +} + +sub is_warehouse_enough +{ + my ($self, $city) = @_; + # TODO 以速率計算容納率 + # XXX: not implemented yet. + return 1; +} + +sub is_risk +{ + my ($self, $city) = @_; + # TODO 計算可搶劫比例, 城牆防護, 軍事分數 + return 0; +} + +sub is_shipyard +{ + return 1; +} + +sub is_drydock_researched { + my ($self, $city) = @_; + return (defined($city->{research}->{4010}) ? 1 : 0); +} + +sub is_winepress_researched { + my ($self, $city) = @_; + return (defined($city->{research}->{2040}) ? 1 : 0); +} + +sub rule_engagement +{ + my ($self, $city) = @_; + # XXX + # 計算距離, 可搶劫比例, 是否有聯盟, 軍事分數 (win rate) +} + +sub rule_resource +{ + # XXX +} +1; + + +package main; +our $i = new Ikariam($::server, $::user, $::pass); +$i->login; +my $cities = $i->check; + +my $rules = Ikariam::Cities::Rules->new; +my $tree = LoadFile('building.yaml'); +# print Dumper($tree); +# show cities. +foreach my $cityId (keys(%$cities)) { + printf("%s http://%s/index.php?view=city&id=%d\n", + $cities->{$cityId}->{name}, $::server, $cityId); + printf("construction: %s\n", $cities->{$cityId}->{construction}); + + foreach my $thing (qw/resources space force buildings citizens army fleet/) { + printf("<%s>\n", uc($thing)); + foreach my $i (keys(%{$cities->{$cityId}->{$thing}})) { + printf("%s %s, ", $i, $cities->{$cityId}->{$thing}->{$i}); + } + print("\n"); + } + print("\n"); + # print(Dumper($cities)); + + # make decisions + + # for the Decision Tree + $cities->{$cityId}->{parse_path} = []; + $cities->{$cityId}->{parse_answer} = undef; + while (my $action = ParseTree($tree, $rules, $cities->{$cityId})) + { + # TODO: remove the last rule, if the result is fallback + triggerAction($action, $cityId); + last; + } + # Debug + print(Dumper($cities->{$cityId}->{parse_path})); +} + +$i->logout; + +sub triggerAction { + my ($action, $cityId) = @_; + + my ($func, $param) = split(/_/,$action); + # printf('$i->%s("%s", %s);\n\n', $func, $param, $cityId); + eval(sprintf('$i->%s("%s", %s);', $func, $param, $cityId)); + warn $@ if $@; +} diff -r bc31729f29f4 -r d2ac1e198ce4 building.yaml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/building.yaml Mon Oct 20 19:07:53 2008 +0800 @@ -0,0 +1,39 @@ +--- +# 基本建設規則 +# 檢查是否被攻擊 +- is_Attacked: + # we are in Peace :D + 0: + - is_constructing: + # already building something. + 1: + # let's find something to build up + 0: + # 確認是否為主城 + # 確認是否有學院 + - is_wall_enough: + 0: build_wall + - is_space_enough: + 0: build_cityhall + - is_corruption: + 1: build_governorsresidence + # 倉庫庫存量 + - is_warehouse_enough: + 0: build_warehouse + - is_risk: + 1: + - is_shipyard: + 0: + - is_drydock_researched: + 0: resaerch_drydock + 1: build_shipyard + - is_happiness: + 0: + - is_winepress_researched: + 0: research_economy + 1: build_tavern + # reduce_trvern + # 是主城, 可隨意建任一尚未搭建之建築 + # 副城, 不建 ... + # 採取防禦措施 + 1: run_defense diff -r bc31729f29f4 -r d2ac1e198ce4 inference.pl --- a/inference.pl Sat Oct 18 22:24:03 2008 +0800 +++ b/inference.pl Mon Oct 20 19:07:53 2008 +0800 @@ -13,11 +13,6 @@ $::server, $city, $cities->{$city}->{name}, $msg); } -our $i = new Ikariam($::server, $::user, $::pass); -$i->login; -$cities = $i->check; -$i->logout; - sub rule_happiness { my $id = shift; @@ -111,6 +106,11 @@ print("\n"); } +our $i = new Ikariam($::server, $::user, $::pass); +$i->login; +$cities = $i->check; +$i->logout; + # space # Checking rules foreach my $procedure (qw/rule_war rule_happiness rule_corruption rule_building rule_space rule_resource/) { diff -r bc31729f29f4 -r d2ac1e198ce4 sheep.pl --- a/sheep.pl Sat Oct 18 22:24:03 2008 +0800 +++ b/sheep.pl Mon Oct 20 19:07:53 2008 +0800 @@ -37,7 +37,7 @@ SELECT user.id FROM user, cities WHERE user.id == cities.user - AND user.trader_score_secondary >= 50000 + AND user.trader_score_secondary >= 20 AND user.army_score_main <= 100 AND cities.island IN (SELECT island.id FROM island WHERE island.x <= ? AND island.x >= ? AND island.y <= ? AND island.y >= ? ) }