Games::Battleship::Player - A Battleship player class


Games-Battleship documentation Contained in the Games-Battleship distribution.

Index


Code Index:

NAME

Top

Games::Battleship::Player - A Battleship player class

SYNOPSIS

Top

  use Games::Battleship::Player;

  $aeryk = Games::Battleship::Player->new(name => 'Aeryk');
  $gene  = Games::Battleship::Player->new(name => 'Gene');

  print 'Player 1: ', $aeryk->name, "\n",
        'Player 2: ', $gene->name,  "\n";

  $aeryk->strike($gene, 0, 0);

  # Repeat and get a duplicate strike warning.
  $strike = $aeryk->strike($gene, 0, 0);

  print $aeryk->grid($gene), "\nThat was a " .
    ( $strike == 1 ? 'hit!'
    : $strike == 0 ? 'miss.'
                   : 'duplicate?' ), "\n";

  $craft_obj = $aeryk->craft($id);

DESCRIPTION

Top

A Games::Battleship::Player object represents a Battleship player complete with fleet and game surface.

PUBLIC METHODS

Top

new %ARGUMENTS
  $player => Games::Battleship::Player->new(
      name  => 'Aeryk',
      fleet => \@fleet,
      dimensions => [$x, $y],
  );

* name => $STRING

An optional attribute provided to give the player a name.

If not provided, the string "player_1" or "player_2" is used.

* fleet => [$CRAFT_1, $CRAFT_2, ... $CRAFT_N]

Array reference of Games::Battleship::Craft objects.

If not explicitely provided, the standard fleet (with 5 ships) is created by default.

* dimensions => [$WIDTH, $HEIGHT]

Array reference with the player's grid height and width values.

If the grid dimensions are not explicitly specified, the standard ten by ten grid is used.

grid
  $grid = $player->grid();
  $grid = $player->grid($enemy);

Return the playing grid as a "flush-left" text matrix like this:

  . . . . . . . . . .
  . . . . . . . . . .
  . . . . . . . . . .
  . . . S S S . . . .
  . . . . . . C . . .
  . . . . . A C . . .
  . D . . . A C . . B
  . D . . . A . . . B
  . . . . . A . . . B
  . . . . . A . . . B

Eventually, this method will respect the game type and return an apppropriate representation, such as a PNG file or XML, etc.

strike $PLAYER, @COORDINATE
  $strike = $player->strike($enemy, $x, $y);

Strike the enemy at the given coordinate and return a numeric value to indicate success or failure.

The player to strike must be given as a Games::Battleship::Player object and the coordinate must be given as a numeric pair.

On success, an "x" is placed on the striking player's "opponent map grid" (a Games::Battleship::Grid object attribute named for the opponent) at the given coordinate, the opponent's "craft grid" is updated by lowercasing the Games::Battleship::Craft object id at the given coordinate, the opponent Games::Battleship::Craft object hits attribute is incremented, the striking player's score attribute is incremented, and a one (i.e. true) is returned.

If an enemy craft is completely destroyed, a happy warning is emitted.

On failure, an "o" is placed on the striking player's "opponent map grid" at the given coordinate and a zero (i.e. false) is returned.

If a player calls for a strike at a coordinate that was already struck, a warning is emitted and a negative one (-1) is returned.

craft $KEY [$VALUE]
  $craft = $player->craft($id);
  $craft = $player->craft(id => $id);
  $craft = $player->craft(name => $name);

Return the player's Games::Battleship::Craft object that matches the given argument(s).

If the last argument is not provided the first argument is assumed to be the id attribute.

PRIVATE METHODS

Top

_is_a_hit @COORDINATE

Return true or false if another player's strike is successful. That is, return a one if there is a craft at the given coordinate and zero otherwise.

TO DO

Top

Include a weapon argument in the strike method.

Make the grid method honor the game type and return something appropriate.

SEE ALSO

Top

Games::Battleship

Games::Battleship::Craft

Games::Battleship::Grid

AUTHOR

Top

Gene Boggs <gene@cpan.org>

COPYRIGHT AND LICENSE

Top


Games-Battleship documentation Contained in the Games-Battleship distribution.

# $Id: Player.pm,v 1.25 2004/08/25 08:36:50 gene Exp $

package Games::Battleship::Player;
$VERSION = 0.05;
use strict;
use warnings;
use Carp;
use Games::Battleship::Craft;
use Games::Battleship::Grid;

sub new {
    my ($proto, %args) = @_;
    my $class = ref ($proto) || $proto;

    my $self = {
        id    => $args{id}    || undef,
        name  => $args{name}  || undef,
        score => $args{score} || 0,
        life  => $args{life}  || 0,
        fleet => $args{fleet} || [
            Games::Battleship::Craft->new(
                name   => 'aircraft carrier',
                points => 5,
            ),
            Games::Battleship::Craft->new(
                name   => 'battleship',
                points => 4,
            ),
            Games::Battleship::Craft->new(
                name   => 'cruiser',
                points => 3,
            ),
            Games::Battleship::Craft->new(
                name   => 'submarine',
                points => 3,
            ),
            Games::Battleship::Craft->new(
                name   => 'destroyer',
                points => 2,
            ),
        ],
    };

    bless $self, $class;
    $self->_init(\%args);
    return $self;
}

sub _init {
    my ($self, $args) = @_;

    # Initialize a grid and place the player's fleet, if one is
    # provided.
    $self->{grid} = Games::Battleship::Grid->new(
        fleet => $self->{fleet},
        dimensions => $args->{dimensions},
    );

    # Compute the life points for this player.
    $self->{life} += $_->{points} for @{ $self->{fleet} };
}

sub name { return shift->{name} }

# The enemy must be a G::B::Player object.
sub grid {
    my ($self, $enemy) = @_;
    return $enemy
        ? join "\n",
            map { "@$_" } @{ $self->{$enemy->{name}}{matrix} }
        : join "\n",
            map { "@$_" } @{ $self->{grid}{matrix} };
}

# The enemy must be a G::B::Player object.
sub strike {
    my ($self, $enemy, $x, $y) = @_;

    croak "No opponent to strike.\n" unless $enemy;
    croak "No coordinate at which to strike.\n"
        unless defined $x && defined $y;

    if ($enemy->{life} > 0) {
        # Initialize the enemy grid map if we need to.
        $self->{$enemy->{name}} = Games::Battleship::Grid->new
            unless exists $self->{$enemy->{name}};

        my $enemy_pos = \$enemy->{grid}{matrix}[$x][$y];
        my $map_pos   = \$self->{$enemy->{name}}{matrix}[$x][$y];

        if ($$map_pos ne '.') {
            warn "Duplicate strike on $enemy->{name} by $self->{name} at $x, $y.\n";
            return -1;
        }
        elsif ($enemy->_is_a_hit($x, $y)) { # Set the enemy grid map coordinate char to 'hit'.
            $$map_pos = 'x';

            # What craft was hit?
            my $craft = $self->craft(id => $$enemy_pos);

            warn "$self->{name} hit $enemy->{name}'s $craft->{name}!\n";

            # How much is left on this craft?
            my $remainder = $craft->hit;

            # Tally the hit in the craft object, itself and emit a happy
            # warning if it was totally destroyed.
            warn "$self->{name} sunk $enemy->{name}'s $craft->{name}!\n"
                unless $remainder;

            # Indicate the hit on the enemy grid by lowercasing the craft
            # id.
            $$enemy_pos = lc $$enemy_pos;

            # Increment the player's score.
            $self->{score}++;

            # Decrement the opponent's life.
            warn "$enemy->{name} is out of the game.\n"
                if --$enemy->{life} <= 0;

            return 1;
        }
        else {
            # Set the enemy grid map coordinate char to 'miss'.
            warn "$self->{name} missed $enemy->{name} at $x, $y.\n";
            $$map_pos = 'o';
            return 0;
        }
    }
    else {
        warn "$enemy->{name} is already out of the game. Strike another opponent.\n";
        return -1;
    }
}

sub _is_a_hit {
    my ($self, $x, $y) = @_;
    return $self->{grid}{matrix}[$x][$y] ne '.'
        ? 1 : 0;
}

sub craft {
    my ($self, $key, $val) = @_;

    # If the key is not defined, assume it's supposed to be the id.
    unless (defined $val) {
        $val = $key;
        $key = 'id';
    }

    my $craft;

    for (@{ $self->{fleet} }) {
        if ($val eq $_->{$key}) {
            $craft = $_;
            last;
        }
    }

    return $craft;
}

1;

__END__