The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use strict;
use warnings;
package Games::Bowling::Scorecard::AsText;
{
  $Games::Bowling::Scorecard::AsText::VERSION = '0.105';
}
# ABSTRACT: format a bowling scorecard as text


use Carp ();

sub card_as_text {
  my ($self, $card) = @_;

  my $hdr = '+-----+-----+-----+-----+-----+-----+-----+-----+-----+-------+';
  my $balls  = '';
  my $scores = '';

  my @frames = $card->frames;
  INDEX: for my $i (0 .. 8) {
    my $frame = $frames[ $i ];
    unless ($frame) {
      $_  .= '|     ' for $balls, $scores;
      next INDEX;
    }

    $balls .= sprintf '| %s ', $self->_two_balls($frame->balls);

    my $score = $card->score_through($i + 1);
    $scores .= defined $score
             ? sprintf '| %3u ', $score
             : '|     ';
  }

  TENTH: for (1) {
    my $frame = $frames[ 9 ];

    unless ($frame) {
      $_ .= '|       |' for $balls, $scores;
      last TENTH;
    }

    $balls .= sprintf '| %s |', $self->_three_balls($frame->balls);

    my $score = $card->score_through(10);

    $scores .= defined $score
             ? sprintf '|   %3u |', $score
             : '|       |';
  }

  return "$hdr\n"
       . "$balls\n"
       . "$scores\n";
}

sub _two_balls {
  my ($self, $b1, $b2) = @_;

  return '   ' unless defined $b1;

  sprintf '%s %s',
    $b1 == 10 ? 'X' : $b1 || '-',
    $b1 == 10 ? ' ' : defined $b2 ? $b1 + $b2 == 10 ? '/' : $b2 || '-' : ' ';
}

sub _three_balls {
  my ($self, $b1, $b2, $b3) = @_;

  return '     ' unless defined $b1;

  if ($b1 == 10) {
    return 'X    ' unless defined $b2;

    return sprintf 'X X %s', defined $b3 ? $b3 == 10 ? 'X' : $b3 || '-' : ' '
      if $b2 == 10;

    return sprintf 'X %s', $self->_two_balls($b2, $b3);
  } elsif (not defined $b2) {
    return sprintf '%s    ', $b1 || '-';
  } elsif ($b1 + $b2 == 10) {
    return sprintf '%s %s',
      $self->_two_balls($b1, $b2),
      defined $b3 ? $b3 == 10 ? 'X' : $b3 || '-' : ' ';
  } else {
    return sprintf '%s  ', $self->_two_balls($b1, $b2);
  }
}

300;

__END__

=pod

=head1 NAME

Games::Bowling::Scorecard::AsText - format a bowling scorecard as text

=head1 VERSION

version 0.105

=head1 SYNOPSIS

  use Games::Bowling::Scorecard;

  my $card = Games::Bowling::Scorecard->new;

  $card->record(6,1);  # slow start
  $card->record(7,2);  # getting better
  $card->record(10);   # strike!
  $card->record(9,1);  # picked up a spare
  $card->record(10) for 1 .. 3; # turkey!
  $card->record(0,0);  # clearly distracted by something
  $card->record(8,2);  # amazingly picked up 7-10 split
  $card->record(10, 9, 1); # pick up a bonus spare

  print Games::Bowling::Scorecard::AsText->card_as_text($card);

The above outputs:

  +-----+-----+-----+-----+-----+-----+-----+-----+-----+-------+
  | 6 1 | 7 2 | X   | 9 / | X   | X   | X   | - - | 8 / | X 9 / |
  |   7 |  16 |  36 |  56 |  86 | 106 | 116 | 116 | 136 |   156 |

=head1 DESCRIPTION

So, you've written a bowling record-keeper and now you want to print out
scorecards to your dynamic Gopher site.  Games::Bowling::Scorecard has taken
care of the scoring, but now you need to worry about all those slashes and
dashes and X's

=head1 METHODS

=head2 card_as_text

  my $text = Games::Bowling::Scorecard::AsText->card_as_text($card);

Given a scorecard, this method returns a three-line text version of the card,
using standard notation.  A total is kept only through the last non-pending
frame.

=head1 WARNING

This module's interface is almost certain to change, whenever the author gets
around to it.

=head1 AUTHOR

Ricardo SIGNES <rjbs@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2013 by Ricardo SIGNES.

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

=cut