15giftsTask/number_generator.pl

122 lines
4.0 KiB
Perl

#!/usr/bin/env perl
use v5.36.0;
use strict;
use warnings;
use feature 'signatures';
my @numbers_one_to_nine = qw/one two three four five six seven eight nine/;
my @numbers_one_to_nineteen = (@numbers_one_to_nine, qw/ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen/);
# This is contains an undef in the decenes index just to hopefully catch some warning if gets wrongfully used.)
my @decenes = (undef, qw/twenty thirty forty fifty sixty seventy eighty ninety/);
main();
sub main {
my $start_of_range = $ARGV[0];
my $end_of_range = $ARGV[1];
if (!defined $end_of_range) {
$end_of_range = 1_000_000;
}
if (!defined $start_of_range) {
$start_of_range = 1;
}
for (my $i = $start_of_range; $i <= $end_of_range; $i++) {
say convert_number_to_words($i)
}
}
sub convert_number_to_words($number) {
my $return = generate_number_without_uppercase_and_end_marks($number);
$return =~ s/(\w)/\U$1/;
$return .= '.';
return $return;
}
sub generate_number_without_uppercase_and_end_marks($number) {
my $return = '';
if ($number < 1) {
$return .= 'zero';
return $return;
}
# This is done in this way attempting to split the big problem
# in many smaller problems.
append_millions_to_return(\$number, \$return);
my $there_is_hundred_thousands = append_thousand_hundreds_to_return(\$number, \$return);
append_decene_thousands_to_return(\$number, \$return, $there_is_hundred_thousands);
append_hundred_to_return(\$number, \$return);
append_decene_to_return(\$number, \$return);
return $return;
}
sub append_decene_to_return($number_ref, $return_ref) {
my $number = ${$number_ref};
my $decene = int ($number / 1);
return if ($decene < 1);
${$return_ref} .= ' and ' if length ${$return_ref};
${$return_ref} .= convert_two_chars_number_to_words($decene);
${$number_ref} = 0;
}
sub append_decene_thousands_to_return($number_ref, $return_ref, $there_is_hundred_thousands) {
my $number = ${$number_ref};
my $thousand_decene_unit = int ($number / 1_000);
# This is needed for numbers such as 1_100_001 that do not have thousand decenes
# but have thousand hundreds.
if ($there_is_hundred_thousands && $thousand_decene_unit < 1) {
${$return_ref} .= ' thousand';
};
return if ($thousand_decene_unit < 1);
${$return_ref} .= ' and ' if length ${$return_ref};
${$return_ref} .= convert_two_chars_number_to_words($thousand_decene_unit) . ' thousand';
${$number_ref} = $number % 1_000;
}
sub append_hundred_to_return($number_ref, $return_ref) {
my $number = ${$number_ref};
my $hundred = int ($number / 100);
return if ($hundred < 1);
${$return_ref} .= ', ' if length ${$return_ref};
${$return_ref} .= $numbers_one_to_nine[$hundred-1] . ' ' . 'hundred';
${$number_ref} = $number % 100;
}
sub convert_two_chars_number_to_words($number) {
my $return = '';
{
if ($number < 20) {
$return .= $numbers_one_to_nineteen[$number-1];
return $return;
}
my $decene = int($number / 10);
$return .= $decenes[$decene-1];
my $unit = $number % 10;
if ($unit < 1) {
return $return;
}
$return .= '-';
$return .= $numbers_one_to_nine[$unit-1];
}
return $return;
}
sub append_thousand_hundreds_to_return($number_ref, $return_ref) {
my $number = ${$number_ref};
my $thousand_hundreds_unit = int ($number / 100_000);
return if ($thousand_hundreds_unit < 1);
${$return_ref} .= ', ' if length ${$return_ref};
${$return_ref} .= $numbers_one_to_nine[$thousand_hundreds_unit-1] . ' ' . 'hundred';
${$number_ref} = $number % 100_000;
return 1;
}
sub append_millions_to_return($number_ref, $return_ref) {
my $number = ${$number_ref};
my $millions_unit = int ($number / 1_000_000);
return if ($millions_unit < 1);
${$return_ref} .= $numbers_one_to_nine[$millions_unit-1] . ' ' . 'million';
${$number_ref} = $number % 1_000_000;
}