File Coverage

blib/lib/Game/Battleship.pm
Criterion Covered Total %
statement 35 60 58.3
branch 10 22 45.4
condition 6 15 40.0
subroutine 5 7 71.4
pod 3 3 100.0
total 59 107 55.1


line stmt bran cond sub pod time code
1             package Game::Battleship;
2             our $AUTHORITY = 'cpan:GENE';
3             # ABSTRACT: "You sunk my battleship!"
4              
5             our $VERSION = '0.0601';
6              
7 2     2   41568 use Carp;
  2         6  
  2         154  
8 2     2   1108 use Game::Battleship::Player;
  2         6  
  2         63  
9 2     2   14 use Moo;
  2         3  
  2         9  
10              
11              
12             has players => (
13             is => 'rw',
14             isa => sub { croak 'Invalid players list' unless ref($_[0]) eq 'HASH' },
15             );
16              
17              
18             sub add_player {
19 3     3 1 2497 my ($self, $player, $i) = @_;
20              
21             # If we are not given a number to use...
22 3 50       10 unless ($i) {
23             # ..find the least whole number that is not already used.
24 1         5 my @nums = sort { $a <=> $b }
25 3         25 grep { s/^player_(\d+)$/$1/ }
26 3         6 keys %{ $self->{players} };
  3         14  
27 3         7 my $n = 1;
28 3         7 for (@nums) {
29 3 50       10 last if $n > $_;
30 3         5 $n++;
31             }
32 3         6 $i = $n;
33             }
34              
35             # Make the name to use for our object.
36 3         8 my $who = "player_$i";
37              
38             # Return undef if we are trying to add an existing player.
39 3 50       9 if ( exists $self->{players}{$who} ) {
40 0         0 warn "A player number $i already exists\n";
41 0         0 return;
42             }
43              
44             # Set the player name unless we already have a player.
45 3 50       9 $player = $who unless $player;
46              
47             # We are given a player object.
48 3 50       12 if (ref ($player) eq 'Game::Battleship::Player') {
    50          
49 0         0 $self->{players}{$who} = $player;
50             }
51             # We are given the guts of a player.
52             elsif (ref ($player) eq 'HASH') {
53             $self->{players}{$who} = Game::Battleship::Player->new(
54             id => $player->{id} || $i,
55             name => $player->{name} || $who,
56             fleet => $player->{fleet},
57             dimensions => $player->{dimensions},
58 0   0     0 );
      0        
59             }
60             # We are just given a name.
61             else {
62 3         56 $self->{players}{$who} = Game::Battleship::Player->new(
63             id => $i,
64             name => $player,
65             );
66             }
67              
68             # Hand the player object back.
69 3         25 return $self->{players}{$who};
70             }
71              
72              
73             sub player {
74 10     10 1 2107 my ($self, $name) = @_;
75 10         12 my $player;
76              
77             # Step through each player...
78 10         12 for (keys %{ $self->{players} }) {
  10         34  
79             # Are we looking at the same player by name, key or id?
80 27 100 100     212 if( $_ eq $name ||
      100        
81             $self->{players}{$_}->name eq $name ||
82             $self->{players}{$_}->id eq $name
83             ) {
84             # Set the player object to return.
85 9         16 $player = $self->{players}{$_};
86 9         13 last;
87             }
88             }
89              
90 10 100       109 warn "No such player '$name'\n" unless $player;
91 10         39 return $player;
92             }
93              
94              
95             sub play {
96 0     0 1   my ($self, %args) = @_;
97 0           my $winner = 0;
98              
99 0           while (not $winner) {
100             # Take a turn per live player.
101 0           for my $player (values %{ $self->{players} }) {
  0            
102 0 0         next unless $player->life;
103              
104             # Strike each opponent.
105 0           for my $opponent (values %{ $self->{players} }) {
  0            
106 0 0 0       next if $opponent->name eq $player->name ||
107             !$opponent->life;
108              
109 0           my $res = -1; # "duplicate strike" flag.
110 0           while ($res == -1) {
111 0           $res = $player->strike(
112             $opponent,
113             $self->_get_coordinate($opponent)
114             );
115             }
116             }
117             }
118              
119             # Do we have a winner?
120 0           my @alive = grep { $self->{players}{$_}->life } keys %{ $self->{players} };
  0            
  0            
121 0 0         $winner = @alive == 1 ? shift @alive : undef;
122             }
123              
124             #warn $winner->name ." is the winner!\n";
125 0           return $winner;
126             }
127              
128             # Return a coordinate from a player's grid.
129             sub _get_coordinate {
130 0     0     my ($self, $player) = @_;
131              
132 0           my ($x, $y);
133              
134             # Return random coordinates...
135             ($x, $y) = (
136             int 1 + rand $player->{grid}->{dimension}[0],
137 0           int 1 + rand $player->{grid}->{dimension}[1]
138             );
139              
140             # warn "$x, $y\n";
141 0           return $x, $y;
142             }
143              
144             1;
145              
146             __END__