File Coverage

blib/lib/Game/Battleship.pm
Criterion Covered Total %
statement 41 66 62.1
branch 10 22 45.4
condition 6 15 40.0
subroutine 7 9 77.7
pod 3 3 100.0
total 67 115 58.2


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