aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xchallenge-132/mattneleigh/perl/ch-1.pl163
-rwxr-xr-xchallenge-132/mattneleigh/perl/ch-2.pl134
2 files changed, 297 insertions, 0 deletions
diff --git a/challenge-132/mattneleigh/perl/ch-1.pl b/challenge-132/mattneleigh/perl/ch-1.pl
new file mode 100755
index 0000000000..647916d4d2
--- /dev/null
+++ b/challenge-132/mattneleigh/perl/ch-1.pl
@@ -0,0 +1,163 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Time::Local;
+
+################################################################################
+# Begin main execution
+################################################################################
+
+my @birthday_dates = (
+ "2021/09/18",
+ "1975/10/10",
+ "1967/02/14"
+);
+my $birthday_date;
+my $reference_date = "2021/09/22";
+
+foreach $birthday_date (@birthday_dates){
+ print("Input: $birthday_date\n");
+ print(" With reference date $reference_date:\n");
+ printf(
+ " Output: %s\n",
+ join(
+ ", ",
+ birthday_mirror($birthday_date, $reference_date)
+ )
+ );
+ print(" With current date:\n");
+ printf(
+ " Output: %s\n\n",
+ join(
+ ", ",
+ birthday_mirror($birthday_date)
+ )
+ );
+}
+
+exit(0);
+################################################################################
+# End main execution; subroutines follow
+################################################################################
+
+
+
+################################################################################
+# Given a birthdate and an optional reference date, calculate the mirror dates
+# for same- the date before the birthdate and after the reference date that
+# correspond to the length of the time interval between the two dates. If no
+# reference date is specified, the current date will be used.
+# Takes two arguments:
+# * A string defining a birthdate, consisting solely of the date itself in the
+# format YYYY/MM/DD
+# * An optional string defining a reference date, subject to the same format
+# requirements as the birthdate; if this argument is omitted, the current
+# date, according to the local system clock, will be used
+# Returns:
+# * A list with the following members:
+# - A string containing the date BEFORE the birth date corresponding to the
+# length of time elapsed between the birth date and the reference date
+# - A string containing the date AFTER the reference date corresponding to
+# the length of time elapsed between the birth date and the reference date;
+# as noted above, if no reference date is specified, the current date will
+# be used
+# NOTE: This function requires that the system correctly handle negative time
+# values with respect to the start of the UNIX epoch; this is not mandated by
+# the POSIX standard, but in practice most modern systems support this
+################################################################################
+sub birthday_mirror{
+ my $birthday = shift();
+ my $reference_date = shift();
+
+ my @time_values;
+ my $delta;
+
+ # Calculate the epoch time at 12:00:00 on
+ # the specified birthdate; noon is used
+ # instead of midnight so leap seconds
+ # won't push the time into the wrong day-
+ # for reasonable human lifespans,
+ # anyway...
+ $birthday = noon_on_date($birthday);
+
+ # Calculate the epoch time at 12:00:00
+ # on the reference date
+ if(defined($reference_date)){
+ $reference_date = noon_on_date($reference_date);
+ } else{
+ # No reference date defined; use the
+ # current date, making sure to pull the
+ # time from the system clock only once
+ $reference_date = time();
+ @time_values = localtime($reference_date);
+ $reference_date -= (
+ ($time_values[2] - 12) * 3600
+ +
+ $time_values[1] * 60
+ +
+ $time_values[0]
+ );
+ }
+
+ # Difference (delta) between the
+ # reference date and the birth date
+ $delta = $reference_date - $birthday;
+
+ # Subtract the delta from the birth date
+ @time_values = localtime($birthday - $delta);
+ $birthday = sprintf(
+ "%4d/%02d/%02d",
+ $time_values[5] + 1900,
+ $time_values[4] + 1,
+ $time_values[3]
+ );
+
+ # Add the delta to the reference date
+ @time_values = localtime($reference_date + $delta);
+ $reference_date = sprintf(
+ "%4d/%02d/%02d",
+ $time_values[5] + 1900,
+ $time_values[4] + 1,
+ $time_values[3]
+ );
+
+ return($birthday, $reference_date);
+
+}
+
+
+
+################################################################################
+# Calculate the UNIX epoch time in seconds at noon (12:00:00 local system time)
+# on a specified date
+# Takes one argument:
+# * A string defining a date, consisting solely of the date itself in the
+# format YYYY/MM/DD
+# Returns:
+# * The number of seconds from the start of the UNIX epoch to noon on the
+# specified date, in local system time; if this time is before the start of
+# the epoch, the value returned will be negative
+# NOTE: This function requires that the system correctly handle negative time
+# values with respect to the start of the UNIX epoch; this is not mandated by
+# the POSIX standard, but in practice most modern systems support this
+################################################################################
+sub noon_on_date{
+ my $date = shift();
+
+ my @time_values;
+
+ @time_values = ($date =~ m/^(\d{4})\/(\d{2})\/(\d{2})$/);
+
+ # timelocal() is from Time::Local
+ return(
+ timelocal(
+ 0, 0, 12, $time_values[2], $time_values[1] - 1, $time_values[0]
+ )
+ );
+
+}
+
+
+
diff --git a/challenge-132/mattneleigh/perl/ch-2.pl b/challenge-132/mattneleigh/perl/ch-2.pl
new file mode 100755
index 0000000000..b3764565c7
--- /dev/null
+++ b/challenge-132/mattneleigh/perl/ch-2.pl
@@ -0,0 +1,134 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use English;
+
+################################################################################
+# Begin main execution
+################################################################################
+
+my @player_ages = (
+ [20, "Alex" ],
+ [28, "Joe" ],
+ [38, "Mike" ],
+ [18, "Alex" ],
+ [25, "David" ],
+ [18, "Simon" ]
+);
+my @player_names = (
+ ["Alex", "Stewart"],
+ ["Joe", "Root" ],
+ ["Mike", "Gatting"],
+ ["Joe", "Blog" ],
+ ["Alex", "Jones" ],
+ ["Simon","Duane" ]
+);
+my $row;
+
+print("\nMerged rows:\n");
+foreach $row (@{hash_join(\@player_ages, 1, \@player_names, 0)}){
+ print_table_row($row);
+}
+print("\n");
+
+exit(0);
+################################################################################
+# End main execution; subroutines follow
+################################################################################
+
+
+
+################################################################################
+# Perform a hash join of two lists of table rows, based on the specified key
+# fields. The original arrays will NOT be modified. The order of rows in the
+# merged list will depend on the order of rows with matching keys in the Build
+# and Probe lists.
+# Takes four arguments:
+# * A ref to a list of table rows; this will be treated as the Build List
+# * The index of the field to use as the key from the Build List
+# * A ref to a list of table rows; this will be treated as the Probe List
+# * The index of the field to use as the key from the Probe List
+# Returns:
+# * A ref to a list of merged table rows
+# Adapted from the algorithm described at:
+# http://www.dcs.ed.ac.uk/home/tz/phd/thesis/node21.htm
+################################################################################
+sub hash_join{
+ my $build = shift();
+ my $build_index = shift();
+ my $probe = shift();
+ my $probe_index = shift();
+
+ my $row;
+ my $key;
+ my %table = ();
+ my $joined = [];
+
+ # Build phase- build a table of things
+ # from the build rows, using the specified
+ # field as the key; make each entry in the
+ # table a list of rows, in case more than
+ # one thing matches the key
+ foreach $row (@{$build}){
+ # Copy the row from the build list, then
+ # remove the key from the row before
+ # adding to that key's list in the table
+ $row = [ @{$row} ];
+ $key = splice(@{$row}, $build_index, 1);
+ push(@{$table{$key}}, $row);
+ }
+
+ # Probe phase- loop over the probe list,
+ # examining the table for occurances of the
+ # specified key...
+ foreach $row (@{$probe}){
+ $key = $row->[$probe_index];
+
+ if($table{$key}){
+ # The key from this row appears in the build
+ # table- copy the row and delete the key
+ $row = [ @{$row} ];
+ splice(@{$row}, $probe_index, 1);
+
+ # Loop over everything in the table for this
+ # key and merge the built row with the probe
+ # row, storing the combination in the joined
+ # list
+ foreach my $built_row (@{$table{$key}}){
+ push(@{$joined}, [ @{$built_row}, $key, @{$row} ]);
+ }
+ }
+ }
+
+ return($joined);
+
+}
+
+
+
+################################################################################
+# Print the contents of a table row to STDOUT
+# Takes one argument:
+# * A ref to the row to print out, which must be an array of values that will
+# be interpreted as strings
+# Returns no meaningful value
+################################################################################
+sub print_table_row{
+
+ printf(
+ "%s\n",
+ join(
+ " ",
+ map(
+ { sprintf("%8s", $_); }
+ @{$ARG[0]}
+ )
+ )
+ );
+
+}
+
+
+