I like that you disregard the -
in the input and interpret the framing yourself — that enhances robustness. Common notation for a spare is a /
on the second throw. (削除) It would be nice if you supported that. (削除ここまで) As @rolfl points out @rolfl points out, you need to support that because each throw has to be represented in one character, and you have no other way to indicate a frame of 0, 10. Also, in accordance with the principle that you should be lenient in what you accept, it would be better to accept both uppercase and lowercase x
as a strike.
I like that you disregard the -
in the input and interpret the framing yourself — that enhances robustness. Common notation for a spare is a /
on the second throw. (削除) It would be nice if you supported that. (削除ここまで) As @rolfl points out, you need to support that because each throw has to be represented in one character, and you have no other way to indicate a frame of 0, 10. Also, in accordance with the principle that you should be lenient in what you accept, it would be better to accept both uppercase and lowercase x
as a strike.
I like that you disregard the -
in the input and interpret the framing yourself — that enhances robustness. Common notation for a spare is a /
on the second throw. (削除) It would be nice if you supported that. (削除ここまで) As @rolfl points out, you need to support that because each throw has to be represented in one character, and you have no other way to indicate a frame of 0, 10. Also, in accordance with the principle that you should be lenient in what you accept, it would be better to accept both uppercase and lowercase x
as a strike.
# Split the game history into an array of throws,
# replacing X with 10.
... = map { s/X/10/i; $_} split(/-|?/, $game);
use feature qw(say);
use strict;
use warnings;
use List::Util qw(sum);
# Is this frame a strike?
sub is_strike {
shift == 10;
}
# Is this frame a spare? (Call this subroutine only if it's not a strike.)
sub is_spare {
my ($first_throw, $second_throw) = @_;
$second_throw eq '/' || $first_throw + $second_throw == 10;
}
sub score_frame {
my ($first_throw, $second_throw, @bonus) = @_;
$second_throw = 10 - $first_throw if $second_throw eq '/';
sum($first_throw, $second_throw, @bonus);
}
sub score_game {
my ($game) = @_;
# Split the game history into an array of throws,
# replacing X with 10.
@_ = map { s/X/10/i; $_} split(/-|?/, $game);
my $score = 0;
for my $frame (1..10) {
if (is_strike(@_)) {
# OneConsume one throw in this frame.
# Include the next two throws as a bonus for this frame.
$score += score_frame(shift, $_[0], $_[1]);
} elsif (is_spare(@_)) {
# TwoConsume two throws in this frame.
# Include the next throw as a bonus for this frame.
$score += score_frame(shift, shift, $_[0]);
} else {
# TwoConsume two throws in this frame. No bonus.
$score += score_frame(shift, shift);
}
}
$score;
}
say score_game("X-X-X-X-X-X-X-X-X-X-XX"); #300
say score_game("55-55-55-55-55-55-55-55-55-55-5"); #150
say score_game("00-00-00-00-00-00-00-00-X-X-XX"); #60
say score_game("01-10-20-03-04-35-55-6/-X-24"); #77
# Split the game history into an array of throws,
# replacing X with 10.
... = map { s/X/10/i; $_} split(/-|/, $game);
use feature qw(say);
use strict;
use warnings;
use List::Util qw(sum);
# Is this frame a strike?
sub is_strike {
shift == 10;
}
# Is this frame a spare? (Call this subroutine only if it's not a strike.)
sub is_spare {
my ($first_throw, $second_throw) = @_;
$second_throw eq '/' || $first_throw + $second_throw == 10;
}
sub score_frame {
my ($first_throw, $second_throw, @bonus) = @_;
$second_throw = 10 - $first_throw if $second_throw eq '/';
sum($first_throw, $second_throw, @bonus);
}
sub score_game {
my ($game) = @_;
# Split the game history into an array of throws,
# replacing X with 10.
@_ = map { s/X/10/i; $_} split(/-|/, $game);
my $score = 0;
for my $frame (1..10) {
if (is_strike(@_)) {
# One throw in this frame.
# Include the next two throws as a bonus for this frame.
$score += score_frame(shift, $_[0], $_[1]);
} elsif (is_spare(@_)) {
# Two throws in this frame.
# Include the next throw as a bonus for this frame.
$score += score_frame(shift, shift, $_[0]);
} else {
# Two throws in this frame. No bonus.
$score += score_frame(shift, shift);
}
}
$score;
}
say score_game("X-X-X-X-X-X-X-X-X-X-XX"); #300
say score_game("55-55-55-55-55-55-55-55-55-55-5"); #150
say score_game("00-00-00-00-00-00-00-00-X-X-XX"); #60
say score_game("01-10-20-03-04-35-55-6/-X-24"); #77
# Split the game history into an array of throws,
# replacing X with 10.
... = map { s/X/10/i; $_} split(/-?/, $game);
use feature qw(say);
use strict;
use warnings;
use List::Util qw(sum);
# Is this frame a strike?
sub is_strike {
shift == 10;
}
# Is this frame a spare? (Call this subroutine only if it's not a strike.)
sub is_spare {
my ($first_throw, $second_throw) = @_;
$second_throw eq '/' || $first_throw + $second_throw == 10;
}
sub score_frame {
my ($first_throw, $second_throw, @bonus) = @_;
$second_throw = 10 - $first_throw if $second_throw eq '/';
sum($first_throw, $second_throw, @bonus);
}
sub score_game {
my ($game) = @_;
# Split the game history into an array of throws,
# replacing X with 10.
@_ = map { s/X/10/i; $_} split(/-?/, $game);
my $score = 0;
for my $frame (1..10) {
if (is_strike(@_)) {
# Consume one throw in this frame.
# Include the next two throws as a bonus for this frame.
$score += score_frame(shift, $_[0], $_[1]);
} elsif (is_spare(@_)) {
# Consume two throws in this frame.
# Include the next throw as a bonus for this frame.
$score += score_frame(shift, shift, $_[0]);
} else {
# Consume two throws in this frame. No bonus.
$score += score_frame(shift, shift);
}
}
$score;
}
say score_game("X-X-X-X-X-X-X-X-X-X-XX"); #300
say score_game("55-55-55-55-55-55-55-55-55-55-5"); #150
say score_game("00-00-00-00-00-00-00-00-X-X-XX"); #60
say score_game("01-10-20-03-04-35-55-6/-X-24"); #77
I like that you disregard the -
in the input and interpret the framing yourself — that enhances robustness. Common notation for a spare is a /
on the second throw. (削除) It would be nice if you supported that. (削除ここまで) As @rolfl points out, you need to support that because each throw has to be represented in one character, and you have no other way to indicate a frame of 0, 10. Also, in accordance with the principle that you should be lenient in what you accept, it would be better to accept both uppercase and lowercase x
as a strike.
Second, Perl is a punctuation-heavy language, and you managed to get hit hard, both by dereferencing and by array access, whenever you use @{$_[0]}[$foo..$bar]
— which is quite frequentfrequently. My previous suggestion to give names to all parameters helps a bit. An object-oriented interface for frames couldwould help — you could write $game->throws($foo..$bar)
instead.
You currently call score_frame(\@throws, $current)
.
I prefer to writeinterpret the input using this one-liner in score_game()
. It gets the assignment right the first time, requiring no subsequent mutation.
I like that you disregard the -
in the input and interpret the framing yourself — that enhances robustness. Common notation for a spare is a /
on the second throw. (削除) It would be nice if you supported that. (削除ここまで) As @rolfl points out, you need to support that because each throw has to be represented in one character, and you have no other way to indicate a frame of 0, 10. Also, in accordance with the principle that you should be lenient in what you accept, it would be better to accept lowercase x
as a strike.
Second, Perl is a punctuation-heavy language, and you managed to get hit hard, both by dereferencing and by array access, whenever you use @{$_[0]}[$foo..$bar]
— which is quite frequent. My previous suggestion to give names to all parameters helps a bit. An object-oriented interface for frames could help — you could write $game->throws($foo..$bar)
instead.
You currently call score_frame(\@throws, $current)
I prefer to write this one-liner. It gets the assignment right the first time, requiring no subsequent mutation.
I like that you disregard the -
in the input and interpret the framing yourself — that enhances robustness. Common notation for a spare is a /
on the second throw. (削除) It would be nice if you supported that. (削除ここまで) As @rolfl points out, you need to support that because each throw has to be represented in one character, and you have no other way to indicate a frame of 0, 10. Also, in accordance with the principle that you should be lenient in what you accept, it would be better to accept both uppercase and lowercase x
as a strike.
Second, Perl is a punctuation-heavy language, and you managed to get hit hard, both by dereferencing and by array access, whenever you use @{$_[0]}[$foo..$bar]
— which is quite frequently. My previous suggestion to give names to all parameters helps a bit. An object-oriented interface for frames would help — you could write $game->throws($foo..$bar)
instead.
You currently call score_frame(\@throws, $current)
.
I prefer to interpret the input using this one-liner in score_game()
. It gets the assignment right the first time, requiring no subsequent mutation.