/
City.pm
206 lines (143 loc) · 4.52 KB
/
City.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
use 5.010;
use strict;
use warnings;
package Games::Pandemic::City;
# ABSTRACT: pandemic city object
use Moose 0.92;
use MooseX::Has::Sugar;
use MooseX::SemiAffordanceAccessor;
use Games::Pandemic::Utils;
# -- accessors
# WARNING: do not use y as an attribute name, since it confuses the
# hell out of xgettext when one tries to access $foo->y. indeed, it
# will skip random portions of your file, without any warning.
# therefore, i'm using coordx / coordy.
has id => ( ro, required, isa => 'Int' );
has name => ( ro, required, isa => 'Str' );
has coordx => ( ro, required, isa => 'Num' );
has coordy => ( ro, required, isa => 'Num' );
has xreal => ( ro, required, isa => 'Num' );
has yreal => ( ro, required, isa => 'Num' );
has disease => ( ro, required, weak_ref, isa => 'Games::Pandemic::Disease' );
has _map => ( ro, required, weak_ref, isa => 'Games::Pandemic::Map' );
=method $city->build_station;
Create a research station in the city.
=method $city->quash_station;
Remove the research station that was in the city.
=method my $bool = $city->has_station;
Return true if the city has a research station.
=cut
has has_station => (
rw,
traits => ['Bool'],
isa => 'Bool',
default => 0,
handles => {
build_station => 'set',
quash_station => 'unset',
}
);
#
# _infections is an array of integer. the indexes are the disease ids,
# and the values are the number of disease items on the city.
#
# private methods provided:
# . my $nb = $city->_get_infection($id);
# return the number of item for disease $id in the $city.
# see public method get_infection()
#
# . $city->_set_infection($id, $nb);
# set the new number $nb of items for disease $id in the $city.
# see public method infect()
#
has _infections => (
ro,
traits => ['Array'],
isa => 'ArrayRef[Int]',
default => sub { [] },
handles => {
_get_infection => 'get',
_set_infection => 'set',
},
);
has neighbour_ids => (
ro, required,
traits => ['Array'],
isa => 'ArrayRef',
handles => { _neighbour_ids => 'elements' },
);
# -- default builders / finishers
sub DEMOLISH {
my $self = shift;
#debug( "~city: " . $self->name . "\n" );
}
# -- public methods
=method my @cities = $city->neighbours;
Return a list of C<Games::Pandemic::City>, which are the direct
neighbours of C<$city>.
=cut
sub neighbours {
my $self = shift;
my $map = $self->_map;
return map { $map->city($_) } $self->_neighbour_ids;
}
=method my ($outbreak, $nbreal) = $city->infect( [ $nb [, $disease] ] )
Infect C<$city> with C<$nb> items of C<$disease>. Return true if an
outbreak happened following this infection, false otherwise. If an
outbreak happened, return also the real number of items used (since a
city can only hold up to a maximum number of disease items).
C<$nb> defaults to 1, and C<$disease> to the city disease.
=cut
sub infect {
my ($self, $nb, $disease) = @_;
$nb //= 1;
$disease //= $self->disease;
# FIXME: check for eradication
# perform the infection
my $id = $disease->id;
my $old = $self->_get_infection($id) // 0; # FIXME//padre
my $new = $old + $nb;
my $max = $self->_map->max_infections;
# check for outbreak
my $outbreak = 0;
if ( $new > $max ) {
$new = $max;
$outbreak = 1;
}
# store new infection state & return outbreak status
$self->_set_infection( $id, $new );
return $outbreak, $new-$old;
}
=method my $nb = $city->get_infection( $disease );
Return the number of C<$disease> items for the C<$city>.
=cut
sub get_infection {
my ($self, $disease) = @_;
return $self->_get_infection( $disease->id ) // 0; # FIXME//padre
}
=method $city->treat( $disease, $nb );
Remove C<$nb> items from C<$disease> in C<$city>.
=cut
sub treat {
my ($self, $disease, $nb) = @_;
my $before = $self->get_infection($disease);
$self->_set_infection( $disease->id, $before-$nb );
}
no Moose;
__PACKAGE__->meta->make_immutable;
1;
__END__
=for Pod::Coverage
DEMOLISH
=head1 DESCRIPTION
This module implements a class for city objects, used in Pandemic. They
have different attributes:
=over 4
=item * name: the city name
=item * xreal: the x coord of the city
=item * yreal: the y coord of the city
=item * coordx: the x coord where city information will be put
=item * coordy: the y coord where city information will be put
=item * disease: a ref to a C<Games::Pandemic::Disease> object, which is
the disease which will infect the city by default
=back