aboutsummaryrefslogtreecommitdiff
path: root/challenge-060
diff options
context:
space:
mode:
authorPerlMonk Athanasius <PerlMonk.Athanasius@gmail.com>2020-05-16 23:44:50 -0700
committerPerlMonk Athanasius <PerlMonk.Athanasius@gmail.com>2020-05-16 23:44:50 -0700
commitea71158dff34e84024f8bc9333010104e4503e7a (patch)
tree5369354c430d22669d3d6b7be38287aa8aaa91a9 /challenge-060
parent36f57247358bdfce5419157c0fd9b984759c9680 (diff)
downloadperlweeklychallenge-club-ea71158dff34e84024f8bc9333010104e4503e7a.tar.gz
perlweeklychallenge-club-ea71158dff34e84024f8bc9333010104e4503e7a.tar.bz2
perlweeklychallenge-club-ea71158dff34e84024f8bc9333010104e4503e7a.zip
Perl and Raku solutions to Task 1 of the Perl Weekly Challenge #060
On branch branch-for-challenge-060 Changes to be committed: new file: challenge-060/athanasius/perl/ch-1.pl new file: challenge-060/athanasius/raku/ch-1.raku
Diffstat (limited to 'challenge-060')
-rw-r--r--challenge-060/athanasius/perl/ch-1.pl132
-rw-r--r--challenge-060/athanasius/raku/ch-1.raku124
2 files changed, 256 insertions, 0 deletions
diff --git a/challenge-060/athanasius/perl/ch-1.pl b/challenge-060/athanasius/perl/ch-1.pl
new file mode 100644
index 0000000000..96daf3ce58
--- /dev/null
+++ b/challenge-060/athanasius/perl/ch-1.pl
@@ -0,0 +1,132 @@
+#!perl
+
+################################################################################
+=comment
+
+Perl Weekly Challenge 060
+=========================
+
+Task #1
+-------
+*Excel Column*
+
+*Reviewed by: Ryan Thompson*
+
+Write a script that accepts a number and returns the *Excel Column Name* it
+represents and vice-versa.
+
+Excel columns start at *A* and increase lexicographically using the 26 letters
+of the English alphabet, *A*..*Z*. After *Z*, the columns pick up an extra
+"digit", going from *AA*, *AB*, etc., which could (in theory) continue to an
+arbitrary number of digits. In practice, Excel sheets are limited to 16,384
+columns.
+
+*Example*
+
+Input Number: 28 Output: AB
+
+Input Column Name: AD Output: 30
+
+=cut
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2020 PerlMonk Athanasius #
+#--------------------------------------#
+
+use strict;
+use warnings;
+use Const::Fast;
+use Scalar::Util qw( looks_like_number );
+use constant WARN_ON_RANGE => 1;
+
+const my $MAX_COLUMN => 16_384; # = XFD: 24*26² + 6*26¹ + 4*26⁰
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\n";
+}
+
+#===============================================================================
+MAIN:
+#===============================================================================
+{
+ print "Challenge 060, Task #1: Excel Column (Perl)\n\n";
+
+ my $args = scalar @ARGV;
+ $args == 1
+ or die "ERROR: Expected 1 command-line argument but found $args\n";
+
+ my $arg = $ARGV[0];
+
+ if (looks_like_number($arg))
+ {
+ int($arg) == $arg && $arg > 0
+ or die "ERROR: Invalid numeric argument \"$arg\"\n";
+
+ warn "WARNING: Column $arg is out of range\n"
+ if WARN_ON_RANGE && $arg > $MAX_COLUMN;
+
+ my $name = number_to_name($arg);
+
+ print "The Excel column number $arg is named \"$name\"\n";
+ }
+ else
+ {
+ my $name = uc $arg;
+ $name =~ / ^ [A-Z]+ $ /x
+ or die "ERROR: Argument \"$arg\" is not a valid column name\n";
+
+ my $number = name_to_number($name);
+
+ warn "WARNING: Column \"$name\" is out of range\n"
+ if WARN_ON_RANGE && $number > $MAX_COLUMN;
+
+ print "The Excel column named \"$name\" is number $number\n";
+ }
+}
+
+#-------------------------------------------------------------------------------
+sub number_to_name
+#-------------------------------------------------------------------------------
+{
+ my ($num) = @_;
+ my $name = '';
+ my $exp = 2;
+ my $max = 26; # Cf. OEIS A218729:
+ $max += 26 ** $exp++ while $max < $num; # 1, 27, 703, 18279, ...
+
+ for my $power (reverse 0 .. $exp - 2)
+ {
+ my $div = 26 ** $power;
+ my $quo = int($num / $div);
+ $quo = 26 if $quo > 26;
+ $name .= ('A' .. 'Z')[$quo - 1];
+ $num -= $quo * $div;
+
+ last if $num == 0;
+ }
+
+ return $name;
+}
+
+#-------------------------------------------------------------------------------
+sub name_to_number
+#-------------------------------------------------------------------------------
+{
+ my ($name) = @_;
+ my $number = 0;
+
+ for (my $multiplier = 1; $name; $multiplier *= 26)
+ {
+ my $char = substr $name, -1, 1, '';
+ $number += $multiplier * (ord($char) - ord('A') + 1);
+ }
+
+ return $number;
+}
+
+################################################################################
diff --git a/challenge-060/athanasius/raku/ch-1.raku b/challenge-060/athanasius/raku/ch-1.raku
new file mode 100644
index 0000000000..63e70d612b
--- /dev/null
+++ b/challenge-060/athanasius/raku/ch-1.raku
@@ -0,0 +1,124 @@
+use v6d;
+
+################################################################################
+=begin comment
+
+Perl Weekly Challenge 060
+=========================
+
+Task #1
+-------
+*Excel Column*
+
+*Reviewed by: Ryan Thompson*
+
+Write a script that accepts a number and returns the *Excel Column Name* it
+represents and vice-versa.
+
+Excel columns start at *A* and increase lexicographically using the 26 letters
+of the English alphabet, *A*..*Z*. After *Z*, the columns pick up an extra
+"digit", going from *AA*, *AB*, etc., which could (in theory) continue to an
+arbitrary number of digits. In practice, Excel sheets are limited to 16,384
+columns.
+
+*Example*
+
+Input Number: 28 Output: AB
+
+Input Column Name: AD Output: 30
+
+=end comment
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2020 PerlMonk Athanasius #
+#--------------------------------------#
+
+my Bool constant WARN-ON-RANGE = True;
+my UInt constant MAX-COLUMN = 16_384; # = XFD: 24*26² + 6*26¹ + 4*26⁰
+
+#-------------------------------------------------------------------------------
+BEGIN ''.put;
+#-------------------------------------------------------------------------------
+
+#===============================================================================
+multi sub MAIN
+(
+ UInt:D $number where $number > 0 #= Excel column number: an integer >= 1
+)
+#===============================================================================
+{
+ "Challenge 060, Task #1: Excel Column (Raku)\n".put;
+
+ "WARNING: Column $number is out of range".note
+ if WARN-ON-RANGE && $number > MAX-COLUMN;
+
+ my Str $name = number-to-name($number);
+
+ "The Excel column number $number is named \"$name\"".put;
+}
+
+#-------------------------------------------------------------------------------
+sub number-to-name( UInt:D $num is copy --> Str:D )
+#-------------------------------------------------------------------------------
+{
+ my Str $name = '';
+ my UInt $exp = 2;
+ my UInt $max = 26; # Cf. OEIS A218729:
+ $max += 26 ** $exp++ while $max < $num; # 1, 27, 703, 18279, ...
+
+ for reverse 0 .. $exp - 2 -> UInt $power
+ {
+ my UInt $div = 26 ** $power;
+ my UInt $quo = ($num / $div).truncate;
+ $quo = 26 if $quo > 26;
+ $name ~= ('A' .. 'Z')[$quo - 1];
+ $num -= $quo * $div;
+
+ last if $num == 0;
+ }
+
+ return $name;
+}
+
+#===============================================================================
+multi sub MAIN
+(
+ Str:D $str #= Excel column name: one or more letters only
+)
+#===============================================================================
+{
+ "Challenge 060, Task #1: Excel Column (Raku)\n".put;
+
+ my Str $name = $str.uc;
+
+ $name ~~ rx/ ^ <[ A .. Z ]>+ $ /
+ or die "ERROR: Argument \"$str\" is not a valid column name\n$*USAGE";
+
+ my UInt $number = name-to-number($name);
+
+ "WARNING: Column \"$name\" is out of range".note
+ if WARN-ON-RANGE && $number > MAX-COLUMN;
+
+ "The Excel column named \"$name\" is number $number".put;
+}
+
+#-------------------------------------------------------------------------------
+sub name-to-number( Str:D $name --> UInt:D )
+#-------------------------------------------------------------------------------
+{
+ my UInt $number = 0;
+ my UInt $multiplier = 1;
+ my Str @chars = $name.split: '', :skip-empty;
+
+ while @chars
+ {
+ my Str $char = @chars.pop;
+ $number += $multiplier * ($char.ord - 'A'.ord + 1);
+ $multiplier *= 26;
+ }
+
+ return $number;
+}
+
+###############################################################################