The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.
package Games::Othello;

use warnings;
use strict;

=head1 NAME

Games::Othello - Perl extension for modelling a game of Othello.

=head1 VERSION

Version 0.01

=cut

our $VERSION = '0.01';

=head1 SYNOPSIS

    use Games::Othello;

    my $game = Games::Othello->new();

    while( !game->over ) {
        printf "It is presently %s's move",
            ($game->whos_move eq 'b') ? 'black', 'white';
        my @possible_moves = values $game->possible_moves();

        if ( ! @possible_moves ) {
            print "You have no moves available, you must pass.
            $game->pass_to_opponent;
        } else {
            foreach ( my $move ) @possible_moves ) {
                printf
                  "You will take %d of your opponents chips if you place your chip on %d,%d",
                  scalar @{ $move->{chips} }, $move->{x}, $move->{y};
            }
            my ($locx, $locy) = get_move();
            my $flipped = $game->place_chip( $locx, $locy );
        }
        
        my $layout = $game->chip_layout();
        foreach my $row ( @$layout ) {
            foreach my $pos ( @$row ) {
                printf '%3s',
                      ($pos eq 'b') ? 'B'  # Black occupied square.
                    : ($pos eq 'w') ? 'W'  # White occupied square.
                    :                 ' '  # Un-occupied square.
            }
            print "\n\n";
        }
    }
    my ($black_score, $white_score) = $game->score;

=head1 STATUS

This module is B<PRE-ALPHA>.  Do not expect it to do anything at this point.
Do not expect the API to remain as documented.  If this module interests you
and you have feedback on its design please DO forward that to me.  Contact
information is contained at the bottom of this documentation.

=head1 DESCRIPTION

This module is used to model the common board game, Othello.   Othello has been
around for a very long time, and has been re-produced in several different
formats.  The goal of the game is to eventually fill the board with all of your
chips.

The board itself is an 8x8 grid represented as a matrix of x,y coordinates.
The location of which way each axis is numbered is irrelevant.  But for the
examples in this documentation, the the 0,0 cordinate is located on the
top-left of the board, and 7,7 is located on the bottom-right of the board.
Initially there are two white chips and two black chips each organized
diagonally in the center of the board:  

      0   1   2   3   4   5   6   7

   0

   1

   2

   3              W   B

   4              B   W

   5

   6

   7

Black always has the first move.  Each player must place their color chip on
the board in a square that is horizontally, vertically, or diagonally adjacent
to at least one opponent's chip on the board.  Beyond the opponents chip must
be a straight row of contiguous chips terminated another one of the player's
own chips.

In each instance where a row of opponent chips is terminated by the player's
recently placed chip and another one of that player's chips, the opponents
chips are said to be "flipped".  When this happens, the opponents chips change
color and become owned by the player that just played a chip.

For example: At the beginning of the game, Black always moves first and always
has the following moves available:  (3,2), (2,3), (5,4), (4,5).   Suppose that
black were to place its first chip on (2,3), resulting in the following layout:

       2   3   4   

   3   B   W   B

   4       B   W

Since the new chip at (3,2) now causes the white chip at (3,3) to be in between
two black chips, that chip would be flipped:

       2   3   4   

   3   B   B   B

   4       B   W

White must now play a chip at (2,2) for a diagonal, (4,2) for a vertical, or
(2,4) for a horizontal row.

If a player is un-able to place a chip on the board in a way that causes at
least one flip, they must pass their turn. The game is over under the following
conditions:

=over

=item 1. All squares are occupied.

=item 2. Neither player has any moves available.

=item 3. One player has had all chips eliminated.

=back

At the end of the game, the winner is the player with the most chips on the
board.

=head1 METHODS

=head2 new

This object constructor returns a new Games::Othello object.  

=cut

sub new {
    die 'un-implemented.';
}

=head2 game_over

This method returns a boolean to indicate if the game is over.  See the above
game description for more information.

=cut

sub game_over {
    die 'un-implemented';
}

=head2 whos_move

This method will return the character 'b', or 'w' to indicate if it is
presently black or white's turn.

=cut

sub whos_move {
    die 'un-implemented';
}

=head2 possible_moves

This method returns a hash of hashrefs. 

The outer hash keys are strings representing the comma-separated x and y
coordinates of a particular chip placement that is available in the present
turn (i.e. "3,4").   The values are hashrefs containing information about that
chip placement for the present turn.   

An empty outer hash indicates there are no chip placements possible.

Each inner hashref contains the following key/values:

=over

=item * x

This is the x-axis value of the placement.

=item * y

This is the y-axis value of the placement.

=item * chips

This is a list of opponent's chips that will be flipped over if the move is
executed.  Each chip is represented as an array-ref containing the [x,y] pair
of coordinates for the chip to be flipped.   Because the rules of the game
state that you must always flip at least one opponent's chip or pass your turn,
it is assumed that this list will always contain at least one element.

=cut

sub possible_moves {
    die 'un-implemented';
}

=head2 pass_to_opponent

This method passes game play to the opponent.  This may only be when there are
no possible moves available for the current player.

If the turn is passed to the opponent while there are moves available, then a
Games::Othello::InvalidMove exception will be thrown.  (see EXCEPTIONS, below)

=cut

sub pass_to_opponent {
    die 'un-implemented';
}

=head2 place_chip

This method accepts two parameters: x and y coordinates where the player has
elected to place their chip.

When called, this method will update the state of the board to reflect that the
chipped has been place.  Any opponent chips that need flipped will be flipped
and the game will be updated so that it is the other player's turn.

A list of chips that were flipped will be returned by this method in the form
of [x,y] pairs in array-refs.

If place_chip is called with an invalid set of coordinates, then a
Games::Othello::InvalidMove exception will be thrown.

=cut

sub place_chip {
    die 'un-implemented';
}

=head2 chip_layout

This method returns information about the position of all chips on the board.
It returns an array of arrays.  Each outer array represents one row on the
board (starting from 0), and each inner array represents the horizontal grid
squares in that row (starting from 0).

Each square is represented with the single character 'b' for a black occupied
square, 'w' for a white occupied square, or ' ' (single space) for an
un-occupied square.

=cut

sub chip_layout {
    die 'un-implemented';
}

=head2 score

This method returns the black score and white score in a list.  The score for each player is simply a count of how many chips they have on the board.

=cut

sub score {
    die 'un-implemented';
}

=head1 EXECPTIONS

Games::Othello uses the L<Exception::Class> model for errors.

=head1 AUTHOR

Daniel J. Wright, C<< <DWRIGHT at CPAN.ORG> >>

=head1 BUGS

Please report any bugs or feature requests to
C<bug-games-othello at rt.cpan.org>, or through the web interface at
L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Games-Othello>.
I will be notified, and then you'll automatically be notified of progress on
your bug as I make changes.

=head1 SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Games::Othello

You can also look for information at:

=over 4

=item * AnnoCPAN: Annotated CPAN documentation

L<http://annocpan.org/dist/Games-Othello>

=item * CPAN Ratings

L<http://cpanratings.perl.org/d/Games-Othello>

=item * RT: CPAN's request tracker

L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Games-Othello>

=item * Search CPAN

L<http://search.cpan.org/dist/Games-Othello>

=back

=head1 ACKNOWLEDGEMENTS

Thanks to L<Games::Backgammon> for giving me some thoughts on how to organize
this.

=head1 COPYRIGHT & LICENSE

Copyright 2006 Daniel J. Wright, all rights reserved.

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

=cut

1; # End of Games::Othello