File Coverage

blib/lib/Games/Lacuna/Task/Action/EvaluateColony.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package Games::Lacuna::Task::Action::EvaluateColony;
2              
3 1     1   1843 use 5.010;
  1         3  
  1         62  
4             our $VERSION = $Games::Lacuna::Task::VERSION;
5              
6 1     1   584 use Moose -traits => 'NoAutomatic';
  0            
  0            
7             extends qw(Games::Lacuna::Task::Action);
8             with qw(Games::Lacuna::Task::Role::Stars);
9              
10             use Games::Lacuna::Task::Utils qw(distance);
11             use Games::Lacuna::Task::Table;
12              
13             sub description {
14             return q[Evaluate colonizeable worlds];
15             }
16              
17             has 'max_distance' => (
18             is => 'rw',
19             isa => 'Int',
20             default => 75,
21             required => 1,
22             documentation => 'Maximum distance from home planet [Default: 75]',
23             );
24              
25             has 'min_orbit' => (
26             is => 'rw',
27             isa => 'Int',
28             lazy_build => 1,
29             documentation => 'Min orbit. Defaults to your species min orbit',
30             );
31              
32             has 'max_orbit' => (
33             is => 'rw',
34             isa => 'Int',
35             lazy_build => 1,
36             documentation => 'Max orbit. Defaults to your species max orbit',
37             );
38              
39             has 'min_size' => (
40             is => 'rw',
41             isa => 'Int',
42             default => 55,
43             documentation => 'Min habitable planet size [Default: 55]',
44             );
45              
46             has 'min_gas_giant_size' => (
47             is => 'rw',
48             isa => 'Int',
49             default => 105,
50             documentation => 'Min gas giant size [Default: 105]',
51             );
52              
53             has 'gas_giant' => (
54             is => 'rw',
55             isa => 'Bool',
56             default => 0,
57             documentation => 'Consider gas giants [Flag, Default: false]',
58             );
59              
60             sub _build_min_orbit {
61             my ($self) = @_;
62             return $self->_get_orbit->{min};
63             }
64              
65             sub _build_max_orbit {
66             my ($self) = @_;
67             return $self->_get_orbit->{max};
68             }
69              
70             sub _get_orbit {
71             my ($self) = @_;
72            
73             my $species_stats = $self->request(
74             object => $self->build_object('Empire'),
75             method => 'view_species_stats',
76             )->{species};
77            
78            
79             $self->min_orbit($species_stats->{min_orbit})
80             unless $self->meta->get_attribute('min_orbit')->has_value($self);
81             $self->max_orbit($species_stats->{max_orbit})
82             unless $self->meta->get_attribute('max_orbit')->has_value($self);
83            
84             return {
85             min => $species_stats->{min_orbit},
86             max => $species_stats->{max_orbit},
87             }
88             }
89              
90             sub run {
91             my ($self) = @_;
92            
93             my $planet_stats = $self->my_body_status($self->home_planet_id);
94            
95             my @bodies;
96            
97             $self->search_stars_callback(
98             sub {
99             my ($star_data) = @_;
100            
101             return 1
102             unless scalar @{$star_data->{bodies}};
103            
104             my $boost = 1;
105            
106             # Distance boost
107             $boost += (0.3) * (1-($star_data->{distance} / $self->max_distance));
108            
109             # Evaluate neighbourhood
110             foreach my $body (@{$star_data->{bodies}}) {
111             if (defined $body->{empire}) {
112             # No inhabited systems - SAWs might kill our colony ship
113             return 1
114             if (($body->{type} eq 'habitable planet' || $body->{type} eq 'gas giant')
115             && $body->{empire}{alignment} =~ /^hostile/);
116            
117             # Neighbour boost
118             if ($body->{empire}{alignment} eq 'self') {
119             $boost += 0.1;
120             } elsif ($body->{empire}{alignment} eq 'ally') {
121             $boost += 0.05;
122             }
123             }
124             }
125            
126             # Evaluate bodies
127             foreach my $body (@{$star_data->{bodies}}) {
128             next
129             if defined $body->{empire};
130             next
131             unless $body->{type} eq 'habitable planet' || ($body->{type} eq 'gas giant' && $self->gas_giant);
132             next
133             if $body->{orbit} < $self->min_orbit;
134             next
135             if $body->{orbit} > $self->max_orbit;
136            
137             if ($body->{type} eq 'habitable planet') {
138             next
139             if $body->{size} < $self->min_size;
140             } elsif ($body->{type} eq 'gas giant') {
141             next
142             if $body->{size} < $self->min_gas_giant_size;
143             }
144            
145             my $score = $self->calculate_score($body,$boost);
146            
147             push(@bodies,[$body,$score]);
148            
149             $self->log('debug','Found candidate %s in %s (score %i)',$body->{name},$body->{star_name},$score);
150             }
151            
152             return 1;
153             },
154             x => $planet_stats->{x},
155             y => $planet_stats->{y},
156             max_distance=> $self->max_distance,
157             is_probed => 1,
158             distance => 1,
159             );
160            
161             $self->log('info','Found %i candidates',scalar(@bodies));
162            
163             my $table = Games::Lacuna::Task::Table->new({
164             columns => ['Name','X','Y','Orbit','Score','Size','Water','Distance'],
165             });
166            
167             foreach my $element (sort { $b->[1] <=> $a->[1] } @bodies) {
168             my $body = $element->[0];
169             my $score = $element->[1];
170             $table->add_row({
171             (map { ($_ => $body->{$_}) } qw(name x y orbit size water)),
172             score => $score,
173             distance => int(distance($planet_stats->{x},$planet_stats->{y},$body->{x},$body->{y})),
174             });
175             }
176            
177             say $table->render_text;
178             }
179              
180             sub calculate_score {
181             my ($self,$body,$boost) = @_;
182            
183             $boost //= 1;
184             my $score = 0;
185            
186             # See examples/colony_worlds.pl in Game-Lacuna-Client
187             if ($body->{type} eq 'habitable planet') {
188             $score += ($body->{water} - 5000) / 70;
189             $score += (($body->{size} > 50 ? 50 : $body->{size} ) - 30) * 6;
190             } else {
191             $score += (($body->{size} > 100 ? 100 : $body->{size} ) - 70) * 6;
192             }
193             $score += (scalar grep { $body->{ore}->{$_} > 1 } keys %{$body->{ore}}) * 5;
194            
195             $score *= $boost
196             if $boost;
197            
198             return int($score);
199             }
200              
201             __PACKAGE__->meta->make_immutable;
202             no Moose;
203             1;