aboutsummaryrefslogtreecommitdiff
path: root/challenge-179
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2022-08-28 17:39:49 +0100
committerGitHub <noreply@github.com>2022-08-28 17:39:49 +0100
commit1f8d258caa89189d2eb88da68f3adbb00f9c48c3 (patch)
tree7ac33cb7c11a030a74b619f3180302126e8c2c76 /challenge-179
parentfca06608d83631f1d8828a3010ebbc1e1c08f67d (diff)
parent6ab83568d89a13607944908754fb31172aa300f9 (diff)
downloadperlweeklychallenge-club-1f8d258caa89189d2eb88da68f3adbb00f9c48c3.tar.gz
perlweeklychallenge-club-1f8d258caa89189d2eb88da68f3adbb00f9c48c3.tar.bz2
perlweeklychallenge-club-1f8d258caa89189d2eb88da68f3adbb00f9c48c3.zip
Merge pull request #6658 from PerlMonk-Athanasius/branch-for-challenge-179
Perl & Raku solutions to Tasks 1 & 2 for Week 179
Diffstat (limited to 'challenge-179')
-rw-r--r--challenge-179/athanasius/perl/ch-1.pl315
-rw-r--r--challenge-179/athanasius/perl/ch-2.pl152
-rw-r--r--challenge-179/athanasius/raku/ch-1.raku285
-rw-r--r--challenge-179/athanasius/raku/ch-2.raku152
4 files changed, 904 insertions, 0 deletions
diff --git a/challenge-179/athanasius/perl/ch-1.pl b/challenge-179/athanasius/perl/ch-1.pl
new file mode 100644
index 0000000000..bf97bafc48
--- /dev/null
+++ b/challenge-179/athanasius/perl/ch-1.pl
@@ -0,0 +1,315 @@
+#!perl
+
+###############################################################################
+=comment
+
+Perl Weekly Challenge 179
+=========================
+
+TASK #1
+-------
+*Ordinal Number Spelling*
+
+Submitted by: Mohammad S Anwar
+
+You are given a positive number, $n.
+
+Write a script to spell the ordinal number.
+
+For example,
+
+ 11 => eleventh
+ 62 => sixty-second
+ 99 => ninety-ninth
+
+=cut
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2022 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=comment
+
+Assumptions
+-----------
+1. Ordinal names use the short scale. [1]
+2. Valid input is any integer $n in the range 0 < $n <= (2^64 - 2^10).
+
+Interface
+---------
+If $n is not supplied on the command line, the in-file test suite is run
+instead.
+
+Note
+----
+Script output tested under Windows 8.1 using Perl v5.32.1.
+
+Reference
+---------
+[1] "Long and short scales", Wikipedia,
+ https://en.wikipedia.org/wiki/Long_and_short_scales
+
+=cut
+#==============================================================================
+
+use strict;
+use warnings;
+use Const::Fast;
+use Regexp::Common qw( number );
+use Test::More;
+
+const my $MAX => 18_446_744_073_709_550_592; # 2^64 - 2^10
+
+const my %UNITS =>
+(
+ CARDINAL =>
+ [ '', qw( one two three four five six seven eight nine ) ],
+ ORDINAL =>
+ [ '', qw( first second third fourth fifth sixth seventh eighth ninth ) ],
+);
+
+const my @TEENS => qw( ten eleven twelve thirteen fourteen
+ fifteen sixteen seventeen eighteen nineteen );
+
+const my @TENS => '', '', qw( twenty thirty forty fifty
+ sixty seventy eighty ninety );
+
+const my @LARGE => qw( thousand million billion
+ trillion quadrillion quintillion );
+
+const my $USAGE =>
+"Usage:
+ perl $0 <n>
+ perl $0
+
+ <n> A natural number below 2^64 - 2^10\n";
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\nChallenge 179, Task #1: Ordinal Number Spelling (Perl)\n\n";
+}
+
+#==============================================================================
+MAIN:
+#==============================================================================
+{
+ my $n = parse_command_line();
+
+ if (defined $n)
+ {
+ printf "Input: %s\n", add_commas( $n );
+ printf "Output: %s\n", ordinal ( $n );
+ }
+ else
+ {
+ run_tests();
+ }
+}
+
+#------------------------------------------------------------------------------
+sub ordinal
+#------------------------------------------------------------------------------
+{
+ my ($n) = @_;
+
+ $n = '0' x ((3 - (length( $n ) % 3)) % 3) . $n; # Prepend zeroes
+
+ my @triples = $n =~ / (\d{3}) /gx; # Group digits
+ my $ls_digs = $triples[ -1 ]; # Least significant digits
+ my $hundreds = hundreds( pop @triples, 1 );
+
+ my @ordinal;
+ push @ordinal, $hundreds if $hundreds;
+
+ for (my $index = 0; @triples; ++$index)
+ {
+ if ((my $n = pop @triples) > 0)
+ {
+ push @ordinal, hundreds( $n, 0 ) . ' ' . $LARGE[ $index ];
+ }
+ }
+
+ return format_ordinal( \@ordinal, $ls_digs );
+}
+
+#------------------------------------------------------------------------------
+sub hundreds
+#------------------------------------------------------------------------------
+{
+ my ($n, $ordinal) = @_;
+ my ($hundreds, $tens) = $n =~ / ^ (\d) (\d{2}) $ /x;
+ my $name = tens( $tens, $ordinal );
+
+ if ($hundreds > 0)
+ {
+ $name = $UNITS{ CARDINAL }[ $hundreds ] . ' hundred' .
+ (($tens == 0) ? '' : ($name ? " and $name" : 'th'));
+ }
+
+ return $name;
+}
+
+#------------------------------------------------------------------------------
+sub tens
+#------------------------------------------------------------------------------
+{
+ my ($n, $ordinal) = @_;
+
+ return '' if $n == 0;
+
+ my ($tens, $units) = $n =~ / ^ (\d) (\d) $ /x;
+
+ my $key = $ordinal ? 'ORDINAL' : 'CARDINAL';
+ my $name = ($tens == 1) ? $TEENS[ $units ] . ($ordinal ? 'th' : '')
+ : $UNITS{ $key }[ $units ];
+
+ if ($tens > 1)
+ {
+ my $tens_name = $TENS[ $tens ];
+
+ if ($units > 0)
+ {
+ $name = $tens_name . '-' . $name;
+ }
+ elsif ($ordinal)
+ {
+ $name = substr( $tens_name, 0, -1 ) . 'ieth';
+ }
+ else
+ {
+ $name = $tens_name;
+ }
+ }
+
+ return $name;
+}
+
+#-------------------------------------------------------------------------------
+sub format_ordinal
+#-------------------------------------------------------------------------------
+{
+ my ($ord_array, $ls_digs) = @_;
+ my $ordinal;
+
+ if (scalar @$ord_array == 1)
+ {
+ $ordinal = $ord_array->[ 0 ] . (($ls_digs % 100 == 0) ? 'th' : '');
+ }
+ elsif ($ls_digs % 100 == 0)
+ {
+ $ordinal = join( ' ', reverse @$ord_array ) . 'th';
+ }
+ elsif ($ls_digs =~ / ^ 0 /x)
+ {
+ $ordinal = join( ' ', reverse @$ord_array[ 1 .. $#$ord_array ] ) .
+ ' and ' . $ord_array->[ 0 ];
+ }
+ else
+ {
+ $ordinal = join ' ', reverse @$ord_array;
+ }
+
+ return $ordinal;
+}
+
+#-------------------------------------------------------------------------------
+sub add_commas
+#-------------------------------------------------------------------------------
+{
+ my ($number) = @_;
+
+ # Regex from perlfaq5: "How can I output my numbers with commas added?"
+
+ return $number =~ s/(^\d+?(?=(?>(?:\d{3})+)(?!\d))|\G\d{3}(?=\d))/$1,/gr;
+}
+
+#------------------------------------------------------------------------------
+sub parse_command_line
+#------------------------------------------------------------------------------
+{
+ my $args = scalar @ARGV;
+ $args == 0 and return; # Run tests
+ $args == 1 or error( "Expected 1 command line argument, found $args" );
+
+ my $n = $ARGV[ 0 ];
+
+ $n =~ / ^ $RE{num}{int} $ /x
+ or error( qq["$n" is not a valid integer] );
+
+ $n > 0 or error( "$n is not a natural number" );
+
+ $n <= $MAX or error( "$n is too large" );
+
+ return $n + 0; # Normalise (remove any initial zeroes)
+}
+
+#------------------------------------------------------------------------------
+sub error
+#------------------------------------------------------------------------------
+{
+ my ($message) = @_;
+
+ die "ERROR: $message\n$USAGE";
+}
+
+#------------------------------------------------------------------------------
+sub run_tests
+#------------------------------------------------------------------------------
+{
+ while (my $line = <DATA>)
+ {
+ chomp $line;
+
+ $line =~ s/ ^ (\s+) //x; # Remove initial whitespace
+
+ my ($n, $expected) = split /\s+/, $line, 2;
+ my $test_name = sprintf '(%s)', add_commas( $n );
+
+ is ordinal( $n ), $expected, $test_name;
+ }
+
+ done_testing;
+}
+
+###############################################################################
+
+__DATA__
+ 1 first
+ 2 second
+ 3 third
+ 4 fourth
+ 10 tenth
+ 11 eleventh
+ 19 nineteenth
+ 20 twentieth
+ 21 twenty-first
+ 37 thirty-seventh
+ 62 sixty-second
+ 99 ninety-ninth
+ 100 one hundredth
+ 201 two hundred and first
+ 310 three hundred and tenth
+ 425 four hundred and twenty-fifth
+ 590 five hundred and ninetieth
+ 2345 two thousand three hundred and forty-fifth
+ 5000 five thousandth
+ 6100 six thousand one hundredth
+ 100000 one hundred thousandth
+ 101001 one hundred and one thousand and first
+ 101110 one hundred and one thousand one hundred and tenth
+ 1000069 one million and sixty-ninth
+ 9000999 nine million nine hundred and ninety-ninth
+ 9001000 nine million one thousandth
+ 6000000000 six billionth
+ 6000000050 six billion and fiftieth
+ 6000007000 six billion seven thousandth
+ 7000000003 seven billion and third
+ 1034000890 one billion thirty-four million eight hundred and ninetieth
+ 1000000000000000000 one quintillionth
+ 1000000000000001343 one quintillion one thousand three hundred and forty-third
+18446744073709550592 eighteen quintillion four hundred and forty-six quadrillion seven hundred and forty-four trillion seventy-three billion seven hundred and nine million five hundred and fifty thousand five hundred and ninety-second
diff --git a/challenge-179/athanasius/perl/ch-2.pl b/challenge-179/athanasius/perl/ch-2.pl
new file mode 100644
index 0000000000..6c841c9cd1
--- /dev/null
+++ b/challenge-179/athanasius/perl/ch-2.pl
@@ -0,0 +1,152 @@
+#!perl
+
+###############################################################################
+=comment
+
+Perl Weekly Challenge 179
+=========================
+
+TASK #2
+-------
+*Unicode Sparkline*
+
+Submitted by: Mohammad S Anwar
+
+You are given a list of positive numbers, @n.
+
+Write a script to print sparkline in Unicode for the given list of numbers.
+
+=cut
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2022 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=comment
+
+Assumptions
+-----------
+1. Strictly speaking, sparklines are line charts [2]. However, the Rosetta Code
+ task "Sparkline in unicode" [3] specifies output in the form of bar charts
+ drawn using the 8 Unicode characters U+2581 through U+2588. Given that the
+ Task description calls for a "sparkline in Unicode", the Rosetta Code speci-
+ fication is adopted here.
+
+2. In a normal bar chart, the y axis should start at zero; otherwise, it is a
+ truncated (or torn) graph, which "can create the impression of important
+ change where there is relatively little change" [1]. A sparkline, on the
+ other hand, "presents the general shape of the variation...in some measure-
+ ment" and so should normally not start at zero. The elements in a sparkline
+ range in value between the minimum and maximum data points only.
+
+Note
+----
+Script output tested under Windows 8.1 using Perl v5.22.4 running under Cygwin
+2.8.2-1.
+
+References
+----------
+[1] "Misleading graph", Wikipedia,
+ https://en.wikipedia.org/wiki/Misleading_graph
+[2] "Sparkline", Wikipedia, https://en.wikipedia.org/wiki/Sparkline
+[3] "Sparkline in unicode", Rosetta Code,
+ https://rosettacode.org/wiki/Sparkline_in_unicode
+
+=cut
+#==============================================================================
+
+use strict;
+use warnings;
+use utf8;
+use Const::Fast;
+use List::Util qw( max min );
+use Regexp::Common qw( number );
+
+const my @CHARS => qw( ▁ ▂ ▃ ▄ ▅ ▆ ▇ █ );
+const my $USAGE =>
+"Usage:
+ perl $0 [<n> ...]
+
+ [<n> ...] One or more positive numbers\n";
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ $| = 1;
+ binmode(STDOUT, ':utf8');
+ print "\nChallenge 179, Task #2: Unicode Sparkline (Perl)\n\n";
+}
+
+#==============================================================================
+MAIN:
+#==============================================================================
+{
+ my @n = parse_command_line();
+
+ printf "Input: %s\n\n", join ', ', @n;
+
+ my @sparkline;
+ my $min = min @n;
+ my $max = max @n;
+ my $range = $max - $min;
+
+ if ($range == 0)
+ {
+ @sparkline = ($CHARS[ 0 ]) x scalar( @n );
+ }
+ else
+ {
+ for my $n (@n)
+ {
+ my $idx = 7;
+
+ for my $i (1 .. 7)
+ {
+ if (($n - $min) < ($i * $range / 8))
+ {
+ $idx = $i - 1;
+ last;
+ }
+ }
+
+ push @sparkline, $CHARS[ $idx ];
+ }
+ }
+
+ printf "Output: %s\n", join '', @sparkline;
+}
+
+#------------------------------------------------------------------------------
+sub parse_command_line
+#------------------------------------------------------------------------------
+{
+ my $args = scalar @ARGV;
+ $args == 0 and error( 'No command line arguments found' );
+
+ my @n = @ARGV;
+
+ for my $n (@n)
+ {
+ $n =~ s/ (,) $ //x; # Remove trailing comma separator (if any)
+
+ $n =~ / ^ $RE{num}{real} $ /x
+ or error( qq["$n" is not a valid real number] );
+ $n >= 0 or error( qq["$n" is not a positive number] );
+ }
+
+ return @n;
+}
+
+#------------------------------------------------------------------------------
+sub error
+#------------------------------------------------------------------------------
+{
+ my ($message) = @_;
+
+ die "ERROR: $message\n$USAGE";
+}
+
+###############################################################################
diff --git a/challenge-179/athanasius/raku/ch-1.raku b/challenge-179/athanasius/raku/ch-1.raku
new file mode 100644
index 0000000000..c492a335c1
--- /dev/null
+++ b/challenge-179/athanasius/raku/ch-1.raku
@@ -0,0 +1,285 @@
+use v6d;
+
+###############################################################################
+=begin comment
+
+Perl Weekly Challenge 179
+=========================
+
+TASK #1
+-------
+*Ordinal Number Spelling*
+
+Submitted by: Mohammad S Anwar
+
+You are given a positive number, $n.
+
+Write a script to spell the ordinal number.
+
+For example,
+
+ 11 => eleventh
+ 62 => sixty-second
+ 99 => ninety-ninth
+
+=end comment
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2022 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=begin comment
+
+Assumptions
+-----------
+1. Ordinal names use the short scale. [1]
+2. Valid input is any integer $n in the range 0 < $n < 10^21.
+
+Interface
+---------
+If $n is not supplied on the command line, the in-file test suite is run
+instead.
+
+Note
+----
+Script output tested under Windows 8.1 using Rakudo v2022.04 (implementing Raku
+v6.d).
+
+Reference
+---------
+[1] "Long and short scales", Wikipedia,
+ https://en.wikipedia.org/wiki/Long_and_short_scales
+
+=end comment
+#==============================================================================
+
+use Test;
+
+my constant $MAX = 10 ** 21 - 1; # One sextillion less one
+
+my constant %UNITS =
+
+ CARDINAL =>
+ [ '', |< one two three four five six seven eight nine > ],
+ ORDINAL =>
+ [ '', |< first second third fourth fifth sixth seventh eighth ninth > ];
+
+my constant @TEENS = < ten eleven twelve thirteen fourteen
+ fifteen sixteen seventeen eighteen nineteen >;
+
+my constant @TENS = '', '', |< twenty thirty forty fifty
+ sixty seventy eighty ninety >;
+
+my constant @LARGE = < thousand million billion
+ trillion quadrillion quintillion >;
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ "\nChallenge 179, Task #1: Ordinal Number Spelling (Raku)\n".put;
+}
+
+#==============================================================================
+multi sub MAIN
+(
+ UInt:D $n where { 0 < $n <= $MAX } #= A natural number below 1 sextillion
+)
+#==============================================================================
+{
+ my UInt $num = $n + 0; # Normalise (remove any initial zeroes)
+
+ "Input: %s\n".printf: add-commas( $num );
+ "Output: %s\n".printf: ordinal\ ( $num );
+}
+
+#==============================================================================
+multi sub MAIN()
+#==============================================================================
+{
+ run-tests;
+}
+
+#-------------------------------------------------------------------------------
+sub ordinal( UInt:D $n where * > 0 --> Str:D )
+#-------------------------------------------------------------------------------
+{
+ my Str $num = '0' x ((3 - $n.chars % 3) % 3) ~ $n; # Prepend zeroes
+ my Str @triples = ($num ~~ m:g/ (\d ** 3) /).map: { .Str }; # Group digits
+ my Str $ls-digs = @triples[ *-1 ]; # Least significant digits
+ my Str $hundreds = hundreds( @triples.pop, True );
+ my Str @ordinal;
+ @ordinal.push: $hundreds if $hundreds;
+
+ loop (my UInt $index = 0; @triples.elems > 0; ++$index)
+ {
+ if (my Str $n = @triples.pop) > 0
+ {
+ @ordinal.push: hundreds( $n, False ) ~ ' ' ~ @LARGE[ $index ];
+ }
+ }
+
+ return format-ordinal( @ordinal, $ls-digs );
+}
+
+#------------------------------------------------------------------------------
+sub hundreds( Str:D $n, Bool:D $ordinal --> Str:D )
+#------------------------------------------------------------------------------
+{
+ my Str ($hundreds, $tens) = ($n ~~ / ^ (\d) (\d ** 2) $ /).map: { .Str };
+ my Str $name = tens( $tens, $ordinal );
+
+ if $hundreds > 0
+ {
+ $name = %UNITS< CARDINAL >[ $hundreds ] ~ ' hundred' ~
+ (($tens == 0) ?? '' !! ($name ?? " and $name" !! 'th'));
+ }
+
+ return $name;
+}
+
+#------------------------------------------------------------------------------
+sub tens( Str:D $n, Bool:D $ordinal --> Str:D )
+#------------------------------------------------------------------------------
+{
+ return '' if $n.Int == 0;
+
+ my Str ($tens, $units) = ($n ~~ / ^ (\d) (\d) $ /).map: { .Str };
+
+ my Str $key = $ordinal ?? 'ORDINAL' !! 'CARDINAL';
+ my Str $name = ($tens == 1) ?? @TEENS[ $units ] ~ ($ordinal ?? 'th' !! '')
+ !! %UNITS{ $key }[ $units ];
+
+ if $tens > 1
+ {
+ my Str $tens-name = @TENS[ $tens ];
+
+ if $units > 0
+ {
+ $name = $tens-name ~ '-' ~ $name;
+ }
+ elsif $ordinal
+ {
+ $name = $tens-name.substr( 0, $tens-name.chars - 1 ) ~ 'ieth';
+ }
+ else
+ {
+ $name = $tens-name;
+ }
+ }
+
+ return $name;
+}
+
+#-------------------------------------------------------------------------------
+sub format-ordinal( Array:D[Str:D] $ord-array, Str:D $ls-digs --> Str:D )
+#-------------------------------------------------------------------------------
+{
+ my Str $ordinal;
+
+ if @$ord-array.elems == 1
+ {
+ $ordinal = $ord-array[ 0 ] ~ ($ls-digs %% 100 ?? 'th' !! '');
+ }
+ elsif $ls-digs %% 100
+ {
+ $ordinal = $ord-array.reverse.join( ' ' ) ~ 'th';
+ }
+ elsif $ls-digs ~~ / ^ 0 /
+ {
+ $ordinal = $ord-array[ 1 .. $ord-array.end ].reverse.join( ' ' ) ~
+ ' and ' ~ $ord-array[ 0 ];
+ }
+ else
+ {
+ $ordinal = $ord-array.reverse.join: ' ';
+ }
+
+ return $ordinal;
+}
+
+#-------------------------------------------------------------------------------
+# From https://rosettacode.org/wiki/Commatizing_numbers#Raku
+#
+sub add-commas( $s, :$at = 0, :$ins = ',', :$by = 3 )
+#-------------------------------------------------------------------------------
+{
+ $s.subst: :continue( $at ), :1st, / <[1..9]> <[0..9]>* /,
+ *.flip.comb( / <{ ". ** 1..$by" }> / ).join( $ins ).flip;
+}
+
+#------------------------------------------------------------------------------
+sub run-tests()
+#------------------------------------------------------------------------------
+{
+ for test-data.lines -> Str $line
+ {
+ my Str $test = $line.chomp;
+
+ $test ~~ s/ ^ (\s+) //; # Remove initial whitespace
+
+ my Str ($n, $expected) = $test.split: /\s+/, 2, :skip-empty;
+ my Str $test-name = '(%s)'.sprintf: add-commas( $n );
+
+ is ordinal( $n.Int ), $expected, $test-name;
+ }
+
+ done-testing;
+}
+
+#------------------------------------------------------------------------------
+sub test-data()
+#------------------------------------------------------------------------------
+{
+ return q:to/END/;
+ 1 first
+ 2 second
+ 3 third
+ 4 fourth
+ 10 tenth
+ 11 eleventh
+ 19 nineteenth
+ 20 twentieth
+ 21 twenty-first
+ 37 thirty-seventh
+ 62 sixty-second
+ 99 ninety-ninth
+ 100 one hundredth
+ 201 two hundred and first
+ 310 three hundred and tenth
+ 425 four hundred and twenty-fifth
+ 590 five hundred and ninetieth
+ 2345 two thousand three hundred and forty-fifth
+ 5000 five thousandth
+ 6100 six thousand one hundredth
+ 100000 one hundred thousandth
+ 101001 one hundred and one thousand and first
+ 101110 one hundred and one thousand one hundred and tenth
+ 1000069 one million and sixty-ninth
+ 9000999 nine million nine hundred and ninety-ninth
+ 9001000 nine million one thousandth
+ 6000000000 six billionth
+ 6000000050 six billion and fiftieth
+ 6000007000 six billion seven thousandth
+ 7000000003 seven billion and third
+ 1034000890 one billion thirty-four million eight hundred and ninetieth
+ 1000000000000000000 one quintillionth
+ 1000000000000001343 one quintillion one thousand three hundred and forty-third
+999999999999999999999 nine hundred and ninety-nine quintillion nine hundred and ninety-nine quadrillion nine hundred and ninety-nine trillion nine hundred and ninety-nine billion nine hundred and ninety-nine million nine hundred and ninety-nine thousand nine hundred and ninety-ninth
+END
+}
+
+#------------------------------------------------------------------------------
+sub USAGE()
+#------------------------------------------------------------------------------
+{
+ my Str $usage = $*USAGE;
+
+ $usage ~~ s:g/ ($*PROGRAM-NAME) /raku $0/;
+
+ $usage.put;
+}
+
+###############################################################################
diff --git a/challenge-179/athanasius/raku/ch-2.raku b/challenge-179/athanasius/raku/ch-2.raku
new file mode 100644
index 0000000000..fd67f4222d
--- /dev/null
+++ b/challenge-179/athanasius/raku/ch-2.raku
@@ -0,0 +1,152 @@
+use v6d;
+
+###############################################################################
+=begin comment
+
+Perl Weekly Challenge 179
+=========================
+
+TASK #2
+-------
+*Unicode Sparkline*
+
+Submitted by: Mohammad S Anwar
+
+You are given a list of positive numbers, @n.
+
+Write a script to print sparkline in Unicode for the given list of numbers.
+
+=end comment
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2022 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=begin comment
+
+Assumptions
+-----------
+1. Strictly speaking, sparklines are line charts [2]. However, the Rosetta Code
+ task "Sparkline in unicode" [3] specifies output in the form of bar charts
+ drawn using the 8 Unicode characters U+2581 through U+2588. Given that the
+ Task description calls for a "sparkline in Unicode", the Rosetta Code speci-
+ fication is adopted here.
+
+2. In a normal bar chart, the y axis should start at zero; otherwise, it is a
+ truncated (or torn) graph, which "can create the impression of important
+ change where there is relatively little change" [1]. A sparkline, on the
+ other hand, "presents the general shape of the variation...in some measure-
+ ment" and so should normally not start at zero. The elements in a sparkline
+ range in value between the minimum and maximum data points only.
+
+Note
+----
+Script output tested under Windows 8.1 using Rakudo v2022.04 (implementing Raku
+v6.d) running under Cygwin 2.8.2-1.
+
+References
+----------
+[1] "Misleading graph", Wikipedia,
+ https://en.wikipedia.org/wiki/Misleading_graph
+[2] "Sparkline", Wikipedia, https://en.wikipedia.org/wiki/Sparkline
+[3] "Sparkline in unicode", Rosetta Code,
+ https://rosettacode.org/wiki/Sparkline_in_unicode
+
+=end comment
+#==============================================================================
+
+my constant @CHARS = < ▁ ▂ ▃ ▄ ▅ ▆ ▇ █ >;
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ "\nChallenge 179, Task #2: Unicode Sparkline (Raku)\n".put;
+}
+
+#==============================================================================
+sub MAIN
+(
+ *@n where { .elems > 0 } #= One or more positive numbers
+)
+#==============================================================================
+{
+ my Real @nums = parse-command-line( @n );
+
+ "Input: %s\n\n".printf: @nums.join: ', ';
+
+ my Str @sparkline;
+ my Real $min = @nums.min;
+ my Real $max = @nums.max;
+ my Real $range = $max - $min;
+
+ if $range
+ {
+ for @nums -> Real $n
+ {
+ my UInt $idx = 7;
+
+ for 1 .. 7 -> UInt $i
+ {
+ if ($n - $min) < ($i * $range / 8)
+ {
+ $idx = $i - 1;
+ last;
+ }
+ }
+
+ @sparkline.push: @CHARS[ $idx ];
+ }
+ }
+ else
+ {
+ @sparkline = @CHARS[ 0 ] xx @nums.elems;
+ }
+
+ "Output: %s\n".printf: @sparkline.join;
+}
+
+#------------------------------------------------------------------------------
+sub parse-command-line( *@n --> Array:D[Real:D] )
+#------------------------------------------------------------------------------
+{
+ my Real @nums;
+
+ for @n
+ {
+ my Str $n = S/ (\,) $ //; # Remove trailing comma separator (if any)
+
+ $n.Real ~~ Failure and error( qq["$n" is not a valid real number] );
+ $n.Real >= 0 or error( qq["$n" is not a positive number] );
+
+ @nums.push: $n.Real;
+ }
+
+ return @nums;
+}
+
+#------------------------------------------------------------------------------
+sub error( Str:D $message )
+#------------------------------------------------------------------------------
+{
+ "ERROR: $message".put;
+
+ USAGE();
+
+ exit 0;
+}
+
+#------------------------------------------------------------------------------
+sub USAGE()
+#------------------------------------------------------------------------------
+{
+ my Str $usage = $*USAGE;
+
+ $usage ~~ s:g/ ($*PROGRAM-NAME) /raku $0/;
+
+ $usage.put;
+}
+
+###############################################################################