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