aboutsummaryrefslogtreecommitdiff
path: root/challenge-063/colin-crain/perl
diff options
context:
space:
mode:
authorMohammad S Anwar <mohammad.anwar@yahoo.com>2020-06-07 09:45:01 +0100
committerMohammad S Anwar <mohammad.anwar@yahoo.com>2020-06-07 09:45:01 +0100
commit1c2ecf8f2312c3d67b660d5269bb7e1ef29ca4fd (patch)
treef2f387c634c878ca3757c1a8aa5cc75745692eae /challenge-063/colin-crain/perl
parent1995178f759ed17fa887a4a6b5897a10770d23f8 (diff)
downloadperlweeklychallenge-club-1c2ecf8f2312c3d67b660d5269bb7e1ef29ca4fd.tar.gz
perlweeklychallenge-club-1c2ecf8f2312c3d67b660d5269bb7e1ef29ca4fd.tar.bz2
perlweeklychallenge-club-1c2ecf8f2312c3d67b660d5269bb7e1ef29ca4fd.zip
- Added solutions by Colin Crain.
Diffstat (limited to 'challenge-063/colin-crain/perl')
-rw-r--r--challenge-063/colin-crain/perl/ch-1.pl88
-rw-r--r--challenge-063/colin-crain/perl/ch-2.pl160
2 files changed, 248 insertions, 0 deletions
diff --git a/challenge-063/colin-crain/perl/ch-1.pl b/challenge-063/colin-crain/perl/ch-1.pl
new file mode 100644
index 0000000000..460e99a7fb
--- /dev/null
+++ b/challenge-063/colin-crain/perl/ch-1.pl
@@ -0,0 +1,88 @@
+#! /opt/local/bin/perl
+#
+# drop_the_mic.pl
+#
+# TASK #1 › Last Word
+# Submitted by: Mohammad S Anwar
+# Lovingly Crafted by: Ryan Thompson
+#
+# Define sub last_word($string, $regexp) that returns the
+# last word matching $regexp found in the given string, or
+# undef if the string does not contain a word matching
+# $regexp.
+#
+# For this challenge, a “word” is defined as any character
+# sequence consisting of non-whitespace characters (\S)
+# only. That means punctuation and other symbols are part of
+# the word.
+#
+# The $regexp is a regular expression. Take care that the
+# regexp can only match individual words! See the Examples
+# for one way this can break if you are not careful.
+#
+# Examples
+#
+# last_word(' hello world', qr/[ea]l/); # 'hello'
+# last_word("Don't match too much, Chet!", qr/ch.t/i); # 'Chet!'
+# last_word("spaces in regexp won't match", qr/in re/); # undef
+# last_word( join(' ', 1..1e6), qr/^(3.*?){3}/); # '399933'
+#
+# METHOD
+#
+# It seems the main idea behind this challenge is in the
+# mechanics of passing a regular expression into a subroutine,
+# and in handling a variety of edge-cases that can arise whilst
+# still conforming to the required behavior.
+#
+# In general, looking for the last occurrence of a thing
+# requires a sense of state to be updated, but finding one
+# solution and moving on is much simpler. So with that in mind,
+# we will tokenize our string and look for a match starting from
+# the end rather than the beginning. Returning after our first
+# match will find that last match in the original string. Easy
+# peasy.
+#
+# Another detail is that the challenge explicitly asks for a
+# subroutine, so that is what we will create, along with a
+# wrapper to call it.
+#
+#
+#
+# 2020 colin crain
+## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
+
+
+
+use warnings;
+use strict;
+use feature ":5.26";
+
+## ## ## ## ## MAIN:
+
+my @pairs = ( [' hello world', qr/[ea]l/],
+ ["Don't match too much, Chet!", qr/ch.t/i],
+ ["spaces in regexp won't match", qr/in re/],
+ [ join(' ', 1..1e6), qr/^(3.*?){3}/] );
+
+for my $parameters ( @pairs ) {
+ my $word = last_word($parameters->@*);
+ if (defined $word) {
+ say $word
+ }
+ else {
+ say "\t«no match found»";
+ }
+}
+
+## ## ## ## ## SUBS:
+
+sub last_word {
+ my ($string, $regex) = @_;
+ my @words = split /\s/, $string;
+ my $word;
+ while (@words > 0) {
+ $word = pop @words;
+ return $word if ($word =~ m/$regex/);
+ }
+ return undef;
+}
diff --git a/challenge-063/colin-crain/perl/ch-2.pl b/challenge-063/colin-crain/perl/ch-2.pl
new file mode 100644
index 0000000000..b759e1dd1d
--- /dev/null
+++ b/challenge-063/colin-crain/perl/ch-2.pl
@@ -0,0 +1,160 @@
+#! /opt/local/bin/perl
+#
+# chopped_and_screwed.pl
+#
+# TASK #2 › Rotate String
+# Submitted by: Mohammad S Anwar
+# Lovingly Crafted by: Ryan Thompson
+#
+# Given a word made up of an arbitrary number of x and y
+# characters, that word can be rotated as follows: For the
+# ith rotation (starting at i = 1), i % length(word)
+# characters are moved from the front of the string to the
+# end. Thus, for the string xyxx, the initial (i = 1) % 4 =
+# 1 character (x) is moved to the end, forming yxxx. On the
+# second rotation, (i = 2) % 4 = 2 characters (yx) are moved
+# to the end, forming xxyx, and so on. See below for a
+# complete example.
+#
+# Your task is to write a function that takes a string of xs
+# and ys and returns the maximum non-zero number of
+# rotations required to obtain the original string. You may
+# show the individual rotations if you wish, but that is not
+# required.
+#
+# Example Input: $word = 'xyxx';
+#
+# Rotation 1: you get yxxx by moving x to the end.
+# Rotation 2: you get xxyx by moving yx to the end.
+# Rotation 3: you get xxxy by moving xxy to the end.
+# Rotation 4: you get xxxy by moving nothing as 4 % length(xyxx) == 0.
+# Rotation 5: you get xxyx by moving x to the end.
+# Rotation 6: you get yxxx by moving xx to the end.
+# Rotation 7: you get xyxx by moving yxxx to the end which is same as the given word.
+# Output: 7
+#
+# ANALYSIS AND METHOD
+#
+# One obvious way to proceed is to build a loop, do the
+# transform, and jump out if the transformed string is the
+# same as the initial. This is all well and good, but does
+# follow through to the next question, which is whether it
+# will always eventually find a solution, or whether we
+# might perchance get stuck in an infinite stable
+# oscillation of some sort.
+#
+# This got me thinking more about what we’re actually doing
+# here. And the big reveal is that looked at the right way,
+# the sequence of characters never changes. When we move the
+# first character of the string to the end, the last
+# character is now followed by the first. No matter how many
+# characters are moved over at a time, this relationship
+# will always remain true, and each character within the
+# string will at all times be followed (and proceeded by)
+# the same characters as in the original untransformed
+# string. All we have done is create a new rule, that the
+# end of the string is immediately followed by the
+# beginning. In topology this is known as a loop, a function
+# over an interval where the state at the end of the
+# interval is exactly the same as the beginning. Think of a
+# donut, being a circle rotated in space to form a torus. We
+# have made something quite like that, but with a string.
+#
+# We have no natural data type for a loop of string, but
+# using modular arithmetic we can pretend we do, leaving the
+# string alone and just changing the index of the start
+# point, or, in topology what is known as the base point. As
+# long as when moving forward we treat the current position
+# as mod the length of the string, we will remain on the
+# loop. This is akin to pointing to a point on a circle and
+# declaring that the circle starts here: no matter where you
+# start, one can always trace a complete circle from that
+# point. As a matter of fact, once we have the logic to move
+# the starting point in our loop according to the rules of
+# the given progression, we can then determine that we have
+# worked our way through a complete cycle by observing when
+# our start point returns to 0. At this level of
+# abstraction, we have completely abandoned our actual text;
+# we don’t even need the string anymore to do our math, and
+# can just count the iterations. Neat!
+#
+# It is worth noting before we get too excited that what
+# we’ve solved here this isn’t exactly our problem. It does
+# however give a lot of insight into what we were tasked
+# with. In our thought experiment, it doesn’t matter what
+# the characters of the string are, because given enough
+# rotations the start point will work its way back to 0. But
+# for our challenge we do care: in a random assemblage of xs
+# and ys, an objectively differently ordered but identical
+# pattern might arise by happenstance, so we will need to
+# construct and examine the intermediate steps to check for
+# this. But before that, to follow through in our analysis,
+# what we can do is construct a little program:
+#
+# for my $len (1..500) {
+# my $idx = 0;
+# my $i;
+#
+# while (++$i) {
+# $idx = ($idx + ($i % $len)) % $len;
+# last if $idx == 0;
+# }
+# say "$len $i"; ## string length and number of rotations to cycle
+# }
+#
+# which, for any arbitrary length of string, will provide an
+# upper bound of the maximum number of steps required to
+# come full circle.
+#
+# Just for kicks, we do the transformation here using
+# substr, lifting out the desired prefix and modifying the
+# original string at the same time, which we then graft on
+# to the end of the remaining tail. It’s a succinct solution
+# I dare say, doing a lot with very few words. Another way
+# to do this would be to use a substitution match:
+#
+# $shifted =~ s/^(.{$moves})(.*)/$2$1/;
+#
+# Versus the simplicity of the substitution version I can’t
+# decide which I like best.
+#
+# 2020 colin crain
+## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
+
+
+
+use warnings;
+use strict;
+use feature ":5.26";
+
+## ## ## ## ## MAIN:
+
+my $string = make_xys();
+my $rotations = churn($string);
+say "\nrotations required: $rotations";
+
+## ## ## ## ## SUBS:
+
+sub churn {
+ my $base = shift;
+ my $shifted = $base;
+ my $i;
+
+ say "starting string: ", $base, "\n";
+ while (++$i) {
+ my $moves = $i % length($base);
+ $shifted .= substr( $shifted, 0, $moves, '');
+ printf "move %-2d shifting %2d chars: %s\n", $i, $moves, $shifted;
+ return $i if $shifted eq $base;
+ }
+}
+
+sub make_xys {
+ my $len = shift // int( rand(12) ) + 4;
+ my @xy = ('x','y');
+ my $out;
+ for ( 1..$len) {
+ $out .= $xy[int(rand 2)] ;
+ }
+ return $out;
+}