File Coverage

lib/Settlers/Event/Robber.pm
Criterion Covered Total %
statement 69 80 86.2
branch 15 34 44.1
condition 3 9 33.3
subroutine 16 17 94.1
pod 0 11 0.0
total 103 151 68.2


line stmt bran cond sub pod time code
1             package Settlers::Event::Robber;
2             $Settlers::Event::Robber::VERSION = '0.07';
3 2     2   9 use strict;
  2     1   3  
  2         45  
  1         898  
  1         2  
  1         31  
4 2     2   10 use warnings;
  2     1   4  
  2         51  
  1         5  
  1         1  
  1         26  
5 2     2   1436 use POSIX 'ceil';
  2     1   14752  
  2         11  
  1         4  
  1         2  
  1         10  
6              
7             sub new
8             {
9 1     1 0 4 my ($class, $args) = @_;
10              
11             bless {
12             players_to_steal => [],
13             players_to_concede=> [],
14             active => 0,
15 1         6 location => set_initial_location($args->{map}),
16             moved => 0,
17             }, $class;
18             }
19              
20 145     145 0 516 sub active { $_[0]->{active} }
21 88     88 0 313 sub location { $_[0]->{location} }
22              
23             sub activate
24             {
25 8     8 0 16 my ($self, $players_to_concede) = @_;
26 8 50       24 die "robber is already active\n" if $self->active;
27 8         15 $self->{active} = 1;
28              
29             # check which players have more than 7 cards and need to concede
30 8         21 for (@$players_to_concede)
31             {
32 20 50       55 next unless $_->resource_total > 7;
33 0         0 push @{$self->{players_to_concede}}, {player => $_, target_total => ceil($_->resource_total / 2)};
  0         0  
34             }
35 8         33 return $self->{players_to_concede};
36             }
37              
38             sub check_players_to_concede
39             {
40 14     14 0 24 my ($self) = @_;
41 14         27 my @remaining_players = ();
42 14         16 for my $pair (@{$self->{players_to_concede}})
  14         43  
43             {
44 0 0       0 next if $pair->{player}->resource_total <= $pair->{target_total};
45 0         0 push @remaining_players, $pair;
46             }
47 14         25 $self->{players_to_concede} = \@remaining_players;
48 14         37 return $self->{players_to_concede};
49             }
50              
51             sub deactivate
52             {
53 7     7 0 17 my $self = shift;
54 7 50       19 die "robber is already inactive\n" unless $self->active;
55 7         16 $self->check_players_to_concede;
56 7 50       11 die "Not all players have conceded their resources yet!\n" if @{$self->{players_to_concede}};
  7         22  
57 7 50       20 die "robber hasn\'t moved yet!\n" unless $self->moved;
58 7         12 $self->{active} = 0;
59 7         16 $self->{moved} = 0;
60             }
61              
62             # deploy to a random desert tile
63             sub set_initial_location
64             {
65 1     1 0 6 my $tiles = shift->tiles_by_type_code('D');
66 1         6 my $tile = $tiles->[ int rand(@$tiles) ];
67 1 50       4 die "There are no desert tiles!\n" unless $tile;
68 1         14 return $tile;
69             }
70              
71             sub move
72             {
73 7     7 0 16 my ($self, $tile,$active_player, $players) = @_;
74 7         22 $self->check_players_to_concede;
75              
76 7 50 33     19 die "move requires tile & players arguments\n"
      33        
      33        
77             unless $tile && $tile->isa('Settlers::Map::Tile') && $players && ref $players eq 'ARRAY';
78              
79 7 50       14 die "Not all players have conceded their resources yet!\n" if @{$self->{players_to_concede}};
  7         26  
80              
81 7 50       20 die "the robber can only be moved when active\n" unless $self->{active};
82              
83 7 50       22 die "the robber has already moved\n" if $self->{moved};
84              
85             die "the robber cannot be moved to the same tile\n"
86 7 50       30 if $self->{location}->uuid eq $tile->uuid;
87              
88 7         17 $self->{location} = $tile;
89 7         15 $self->{moved} = 1;
90              
91 7         13 my @players_to_steal = ();
92              
93             PLAYER:
94 7         16 for my $player (@$players)
95             {
96 28 100       75 next if $player eq $active_player;
97 21         41 for my $property (@{$player->properties})
  21         53  
98             {
99 50 100       143 if ($property->location->is_adjacent($tile))
100             {
101 5         14 push @players_to_steal, $player;
102 5         17 next PLAYER;
103             }
104             }
105             }
106 7         20 $self->{players_to_steal} = \@players_to_steal;
107 7         21 return $tile;
108             }
109              
110             # check player has an adjacent property to the robber
111             # return a random resource if they are
112             sub steal
113             {
114 0     0 0 0 my ($self, $player) = @_;
115 0 0       0 die "the robber can only steal when active\n" unless $self->{active};
116 0 0       0 die "the robber hasn\'t moved yet!\n" unless $self->{moved};
117              
118 0 0       0 if (grep($_->number == $player->number, @{$self->{players_to_steal}}))
  0         0  
119             {
120 0         0 return $player->resource_lose_random;
121             }
122             else
123             {
124 0         0 die "$player->{number} has no adjacent properties\n";
125             }
126             }
127 7     7 0 24 sub moved { $_[0]->{moved} }
128              
129 7     7 0 10 sub can_steal { scalar @{$_[0]->{players_to_steal}} }
  7         31  
130             1;
131              
132             __END__