File Coverage

lib/Settlers/Game/Trade.pm
Criterion Covered Total %
statement 82 86 95.3
branch 18 24 75.0
condition 10 26 38.4
subroutine 13 14 92.8
pod 0 8 0.0
total 123 158 77.8


line stmt bran cond sub pod time code
1             package Settlers::Game::Trade;
2             $Settlers::Game::Trade::VERSION = '0.07';
3 3     3   558 use warnings;
  3     1   5  
  3         81  
  1         961  
  1         2  
  1         26  
4 3     3   15 use strict;
  3     1   12  
  3         68  
  1         5  
  1         2  
  1         23  
5 3     3   13 use List::Util 'sum';
  3     1   6  
  3         2990  
  1         5  
  1         2  
  1         1571  
6              
7              
8             sub new
9             {
10 148     148 0 8144 my ($class, $bank, $players, $details, $resource_production) = @_;
11              
12 148 50 33     2925 die __PACKAGE__ . ' new requires players and trade detail arguments'
      33        
      33        
      33        
      33        
      33        
      50        
13             unless $bank && $bank->isa('Settlers::Game::Bank')
14             && $details && ref $details eq 'HASH' && keys %$details
15             && $players && ref $players eq 'ARRAY' && scalar @$players;
16              
17 148         325 my $self = bless { }, $class;
18              
19             # validate trade details
20 148         445 for my $player_number (keys %$details)
21             {
22 172         511 my @players = grep($player_number == $_->number, @$players);
23              
24 172 50       408 die __PACKAGE__ . ' is for an invalid player number'
25             unless scalar @players == 1;
26              
27 172         549 my $resources = $bank->resource_from_notation($details->{$player_number});
28 172         617 $self->{$player_number} = { player => $players[0], resources => $resources };
29              
30 172         230 push @{$self->{players}}, $players[0];
  172         556  
31             }
32              
33 148         219 my @players = @{$self->players};
  148         342  
34              
35 148 100       338 if (@players == 1)
36             {
37 125         192 my $player = shift @players;
38 125         346 my $ratios = $player->ratios;
39 125         204 push @{$self->{players}}, $bank;
  125         236  
40              
41             # check trade ratios if its a bank trade
42 125         222 my ($allowed, $requested) = (0,0);
43              
44 125         215 for my $r (@{$self->resources($player->number)})
  125         309  
45             {
46 203 100       514 if ($r->amount < 0)
    50          
47             {
48 98         223 $allowed += (-$r->amount) / $ratios->{$r->code};
49             }
50             elsif ($r->amount > 0)
51             {
52 105         232 $requested += $r->amount;
53             }
54 203         354 push @{$self->{bank}{resources}}, $r->invert;
  203         875  
55             }
56 125 50 66     477 die "$player requested $requested resources, but provided too few resources trade with the bank\n"
57             unless $resource_production || $allowed == $requested;
58             }
59             # check that the trade contains only 2 players and the amounts balance
60             else
61             {
62 23 100       78 die "a trade must be between 2 players only!\n" unless @players == 2;
63 22         62 my $resources1 = $self->resources($players[0]->number);
64 22         72 my $resources2 = $self->resources($players[1]->number);
65              
66 22         53 for my $r (@$resources1)
67             {
68 40 100       63 my $total2 = sum map { $_->isa(ref $r) ? $_->amount : 0 } @$resources2;
  88         544  
69 40 100       100 die "a trade between 2 players must balance!\n"
70             unless $r->amount + $total2 == 0;
71             }
72             }
73 146         434 return $self;
74             }
75              
76 3     3 0 14 sub is_with_bank { exists $_[0]->{bank} }
77 443     443 0 1053 sub players { $_[0]->{players} }
78              
79             sub as_hashref
80             {
81 9     9 0 23 my $self = shift;
82 9         17 my $rv = {};
83 9         15 for my $player (@{$self->players})
  9         22  
84             {
85 18         23 for my $r (@{$self->resources($player->number)})
  18         48  
86             {
87 30         73 $rv->{$player->number}{$r->code} = $r->amount;
88             }
89             }
90 9         52 return $rv;
91             }
92              
93 0     0 0 0 sub resources_all { [ map { @{$_[0]->resources($_->number)} } @{$_[0]->players} ]}
  0         0  
  0         0  
  0         0  
94              
95             sub resources
96             {
97 484     484 0 736 my ($self, $player_number) = @_;
98              
99             die 'resources requires a valid player number argument'
100 484 50 33     1766 unless $player_number && exists $self->{$player_number};
101              
102 484         1259 return $self->{$player_number}{resources};
103             }
104              
105             sub execute
106             {
107 142     142 0 234 my $self = shift;
108 142 50       294 if ($self->can_afford)
109             {
110 140         210 my %results;
111              
112 140         180 for my $player (@{$self->players})
  140         285  
113             {
114 280         361 for my $r (@{$self->resources($player->number)})
  280         626  
115             {
116 456         1055 $player->resources->{$r->code} += $r->amount;
117 456         1083 $results{$player->number}{$r->code} = $r->amount;
118             }
119             }
120 140         653 return \%results;
121             }
122             }
123              
124             sub can_afford
125             {
126 142     142 0 199 my ($self) = @_;
127              
128 142         160 for my $player (@{$self->players})
  142         292  
129             {
130 283         390 for (@{$self->{$player->number}{resources}})
  283         747  
131             {
132             return die "$player does not have enough resources for that\n"
133 460 100       1066 unless $player->resources->{$_->code} + $_->quantity >= 0;
134             }
135             }
136 140         529 return 1;
137             }
138              
139             1;
140              
141             __END__