aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAbigail <abigail@abigail.be>2021-09-28 14:21:01 +0200
committerAbigail <abigail@abigail.be>2021-10-02 20:56:06 +0200
commitd6547d06f1cb3102611a7a7df3d5a720fa645194 (patch)
treeff30cb8f5162e20eb2538e453f201e8f1f002f23
parent4654113af779173d91d68a66b245b899325a3b05 (diff)
downloadperlweeklychallenge-club-d6547d06f1cb3102611a7a7df3d5a720fa645194.tar.gz
perlweeklychallenge-club-d6547d06f1cb3102611a7a7df3d5a720fa645194.tar.bz2
perlweeklychallenge-club-d6547d06f1cb3102611a7a7df3d5a720fa645194.zip
AWK, Bash, C, Lua, Node,js, Perl, Python, and Ruby solutions for week 132
-rw-r--r--challenge-132/abigail/README.md6
-rw-r--r--challenge-132/abigail/awk/ch-1.awk43
-rw-r--r--challenge-132/abigail/bash/ch-1.sh41
-rw-r--r--challenge-132/abigail/c/ch-1.c62
-rw-r--r--challenge-132/abigail/lua/ch-1.lua45
-rw-r--r--challenge-132/abigail/node/ch-1.js70
-rw-r--r--challenge-132/abigail/perl/ch-1.pl81
-rw-r--r--challenge-132/abigail/perl/ch-2.pl157
-rw-r--r--challenge-132/abigail/python/ch-1.py43
-rw-r--r--challenge-132/abigail/ruby/ch-1.rb38
10 files changed, 585 insertions, 1 deletions
diff --git a/challenge-132/abigail/README.md b/challenge-132/abigail/README.md
index 4c27485f4c..5eef101325 100644
--- a/challenge-132/abigail/README.md
+++ b/challenge-132/abigail/README.md
@@ -3,10 +3,14 @@
## Part 1
* [AWK](awk/ch-1.awk)
+* [Bash](bash/ch-1.sh)
* [C](c/ch-1.c)
+* [Lua](lua/ch-1.lua)
+* [Node.js](node/ch-1.js)
* [Perl](perl/ch-1.pl)
+* [Python](python/ch-1.py)
+* [Ruby](ruby/ch-1.rb)
## Part 2
-* [AWK](awk/ch-2.awk)
* [Perl](perl/ch-2.pl)
diff --git a/challenge-132/abigail/awk/ch-1.awk b/challenge-132/abigail/awk/ch-1.awk
new file mode 100644
index 0000000000..59a0d20f40
--- /dev/null
+++ b/challenge-132/abigail/awk/ch-1.awk
@@ -0,0 +1,43 @@
+#!/usr/bin/awk
+
+#
+# See ../README.md
+#
+
+#
+# Run as: awk -f ch-1.awk < input-file
+#
+
+#
+# Conversion functions from Wikipedia
+#
+
+function g2j (Y, M, D) {
+ return (int ((1461 * (Y + 4800 + int ((M - 14) / 12))) / 4) + \
+ int ((367 * (M - 2 - 12 * int ((M - 14) / 12))) / 12) - \
+ int ((3 * int (((Y + 4900 + int ((M - 14) / 12)) / 100))) / 4) + \
+ D - 32075)
+}
+
+function j2g (J) {
+ e = 4 * (J + 1401 + int (int ((4 * J + 274277) / 146097) * 3 / 4) - 38) + 3
+ D = int (((5 * (int ((e % 1461) / 4)) + 2) % 153) / 5) + 1
+ M = ((int ((5 * (int ((e % 1461) / 4)) + 2) / 153) + 2) % 12) + 1
+ Y = int (e / 1461) - 4716 + int ((12 + 2 - M) / 12)
+ return sprintf ("%04d/%02d/%02d", Y, M, D)
+}
+
+BEGIN {
+ FS = "/"
+ TODAY_Y = 2021
+ TODAY_M = 9
+ TODAY_D = 22
+
+ julian_today = g2j(TODAY_Y, TODAY_M, TODAY_D)
+}
+
+{
+ julian_then = g2j($1, $2, $3)
+ print j2g(2 * julian_then - julian_today) ", " \
+ j2g(2 * julian_today - julian_then)
+}
diff --git a/challenge-132/abigail/bash/ch-1.sh b/challenge-132/abigail/bash/ch-1.sh
new file mode 100644
index 0000000000..5ea6e68cd3
--- /dev/null
+++ b/challenge-132/abigail/bash/ch-1.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+#
+# See ../README.md
+#
+
+#
+# Run as: bash ch-1.sh < input-file
+#
+
+set -f
+
+IFS="/"
+
+function g2j () {
+ local Y=$1
+ local M=$2
+ local D=$3
+ J=$(( ((1461 * (Y + 4800 + (M - 14) / 12)) / 4 +
+ (367 * (M - 2 - 12 * ((M - 14) / 12))) / 12 -
+ (3 * ((Y + 4900 + (M - 14) / 12) / 100)) / 4 + D - 32075) ))
+}
+
+function j2g () {
+ local J=$1
+ local e=$(( 4 * (J + 1401 +
+ (((4 * J + 274277) / 146097) * 3) / 4 - 38) + 3 ))
+ D=$(( ((5 * ((e % 1461) / 4) + 2) % 153) / 5 + 1 ))
+ M=$(( (((5 * ((e % 1461) / 4) + 2) / 153 + 2) % 12) + 1 ))
+ Y=$(( (e / 1461) - 4716 + (12 + 2 - M) / 12 ))
+}
+
+g2j 2021 9 22; julian_today=$J
+
+while read y m d
+do g2j $y ${m/#0/} ${d/#0/}; julian_then=$J
+ j2g $(( 2 * julian_then - julian_today ))
+ printf "%04d/%02d/%02d, " $Y $M $D
+ j2g $(( 2 * julian_today - julian_then ))
+ printf "%04d/%02d/%02d\n" $Y $M $D
+done
diff --git a/challenge-132/abigail/c/ch-1.c b/challenge-132/abigail/c/ch-1.c
new file mode 100644
index 0000000000..1a50d2b8df
--- /dev/null
+++ b/challenge-132/abigail/c/ch-1.c
@@ -0,0 +1,62 @@
+# include <stdlib.h>
+# include <stdio.h>
+# include <string.h>
+
+/*
+ * See ../README.md
+ */
+
+/*
+ * Run as: cc -o ch-1.o ch-1.c; ./ch-1.o < input-file
+ */
+
+# define idx_Y 0
+# define idx_M 1
+# define idx_D 2
+
+typedef unsigned short date_type;
+
+long g2j (date_type Y, date_type M, date_type D) {
+ return ((1461 * (Y + 4800 + (M - 14) / 12)) / 4 +
+ (367 * (M - 2 - 12 * ((M - 14) / 12))) / 12 -
+ (3 * ((Y + 4900 + (M - 14) / 12) / 100)) / 4 + D - 32075);
+}
+
+void j2g (long J, date_type * date) {
+ long e = 4 * (J + 1401 + (((4 * J + 274277) / 146097) * 3) / 4 - 38) + 3;
+ date [idx_D] = ((5 * ((e % 1461) / 4) + 2) % 153) / 5 + 1;
+ date [idx_M] = (((5 * ((e % 1461) / 4) + 2) / 153 + 2) % 12) + 1;
+ date [idx_Y] = (e / 1461) - 4716 + (12 + 2 - date [idx_M]) / 12;
+}
+
+unsigned short TODAY [] = {2021, 9, 22};
+
+int main (void) {
+ date_type Y, M, D;
+ date_type * date_early;
+ date_type * date_late;
+
+ if ((date_early = (date_type *) malloc (3 * sizeof (date_type))) == NULL) {
+ perror ("Malloc failed");
+ exit (1);
+ }
+ if ((date_late = (date_type *) malloc (3 * sizeof (date_type))) == NULL) {
+ perror ("Malloc failed");
+ exit (1);
+ }
+
+ long julian_today = g2j (TODAY [idx_Y], TODAY [idx_M], TODAY [idx_D]);
+
+ while (scanf ("%hu/%hu/%hu", &Y, &M, &D) == 3) {
+ long julian_then = g2j (Y, M, D);
+ j2g (2 * julian_then - julian_today, date_early);
+ j2g (2 * julian_today - julian_then, date_late);
+ printf ("%04d/%02d/%02d, %04d/%02d/%02d\n",
+ date_early [idx_Y], date_early [idx_M], date_early [idx_D],
+ date_late [idx_Y], date_late [idx_M], date_late [idx_D]);
+ }
+ free (date_early);
+ free (date_late);
+
+ return (0);
+}
diff --git a/challenge-132/abigail/lua/ch-1.lua b/challenge-132/abigail/lua/ch-1.lua
new file mode 100644
index 0000000000..a13cd4cf89
--- /dev/null
+++ b/challenge-132/abigail/lua/ch-1.lua
@@ -0,0 +1,45 @@
+#!/opt/local/bin/lua
+
+--
+-- See ../README.md
+--
+
+--
+-- Run as: lua ch-1.lua < input-file
+--
+
+function int (x)
+ if x > 0 then
+ return math . floor (x)
+ else
+ return math . ceil (x)
+ end
+end
+
+function g2j (Y, M, D)
+ return (int ((1461 * (Y + 4800 + int ((M - 14) / 12))) / 4) +
+ int ((367 * (M - 2 - 12 * int ((M - 14) / 12))) / 12) -
+ int ((3 * int (((Y + 4900 + int ((M - 14) / 12)) / 100))) / 4) +
+ D - 32075)
+end
+
+function j2g (J)
+ local e = 4 * (J + 1401 +
+ int (int ((4 * J + 274277) / 146097) * 3 / 4) - 38) + 3
+ local D = int (((5 * (int ((e % 1461) / 4)) + 2) % 153) / 5) + 1
+ local M = ((int ((5 * (int ((e % 1461) / 4)) + 2) / 153) + 2) % 12) + 1
+ local Y = int (e / 1461) - 4716 + int ((12 + 2 - M) / 12)
+ return Y, M, D
+end
+
+local julian_today = g2j (2021, 9, 22)
+local output_format = "%04d/%02d/%02d, %04d/%02d/%02d\n"
+
+for line in io . lines () do
+ local _, _, Y, M, D = line : find ("([0-9]+)/([0-9]+)/([0-9]+)")
+ local julian_then = g2j (Y, M, D)
+ local Y1, M1, D1 = j2g (2 * julian_then - julian_today)
+ local Y2, M2, D2 = j2g (2 * julian_today - julian_then)
+
+ io . write (output_format : format (Y1, M1, D1, Y2, M2, D2))
+end
diff --git a/challenge-132/abigail/node/ch-1.js b/challenge-132/abigail/node/ch-1.js
new file mode 100644
index 0000000000..e7f937e4b3
--- /dev/null
+++ b/challenge-132/abigail/node/ch-1.js
@@ -0,0 +1,70 @@
+#!/usr/local/bin/node
+
+//
+// See ../README.md
+//
+
+//
+// Run as: node ch-1.js < input-file
+//
+
+const util = require ('util')
+
+function int (x) {
+ if (x < 0) {
+ return Math . ceil (x)
+ }
+ else {
+ return Math . floor (x)
+ }
+}
+
+function g2j (Y, M, D) {
+ return (int ((1461 * (Y + 4800 + int ((M - 14) / 12))) / 4) +
+ int ((367 * (M - 2 - 12 * int ((M - 14) / 12))) / 12) -
+ int ((3 * int (((Y + 4900 + int ((M - 14) / 12)) / 100))) / 4) +
+ D - 32075)
+}
+
+function j2g (J) {
+ let e = 4 * (J + 1401 +
+ int (int ((4 * J + 274277) / 146097) * 3 / 4) - 38) + 3
+ let D = int (((5 * (int ((e % 1461) / 4)) + 2) % 153) / 5) + 1
+ let M = ((int ((5 * (int ((e % 1461) / 4)) + 2) / 153) + 2) % 12) + 1
+ let Y = int (e / 1461) - 4716 + int ((12 + 2 - M) / 12)
+ return [Y, M, D]
+}
+
+//
+// pad a number to a requested length
+//
+function pad (num, l) {
+ let out = num
+ while (out . length < l) {
+ out = "0" + out
+ }
+ return (out)
+}
+
+//
+// Pretty print the output, since node.js doesn't have sprintf(),
+// and util.format just doesn't do it.
+//
+function pp (d1, d2) {
+ let e1 = d1 . map (x => x . toString ())
+ let e2 = d2 . map (x => x . toString ())
+ console . log ("%s/%s/%s, %s/%s/%s",
+ pad (e1 [0], 4), pad (e1 [1], 2), pad (e1 [2], 2),
+ pad (e2 [0], 4), pad (e2 [1], 2), pad (e2 [2], 2))
+}
+
+let julian_today = g2j (2021, 9, 22)
+
+ require ('readline')
+. createInterface ({input: process . stdin})
+. on ('line', line => {
+ let [Y, M, D] = line . split ('/') . map (x => +x)
+ let julian_then = g2j (Y, M, D)
+ pp (j2g (2 * julian_then - julian_today),
+ j2g (2 * julian_today - julian_then))
+})
diff --git a/challenge-132/abigail/perl/ch-1.pl b/challenge-132/abigail/perl/ch-1.pl
new file mode 100644
index 0000000000..1500742a2c
--- /dev/null
+++ b/challenge-132/abigail/perl/ch-1.pl
@@ -0,0 +1,81 @@
+#!/opt/perl/bin/perl
+
+use 5.032;
+
+use strict;
+use warnings;
+no warnings 'syntax';
+
+use experimental 'signatures';
+use experimental 'lexical_subs';
+
+#
+# See ../README.md
+#
+
+#
+# Run as: perl ch-1.pl < input-file
+#
+
+#
+# First question we need to ask for any date related exercise is
+# "What calendar are we using?". If you answer "Gregorian", then
+# the next question is, "Where are we using the calendar?", as
+# different countries switched to the Gregorian calendar at different
+# times. The first countries switched in the 16th century, but others
+# switched as late as the 20th century.
+#
+
+#
+# We will opt to use the proleptic Gregorian calendar, which is basically
+# the Gregorian calendar extended backwards to the time no Gregorian
+# calender existed.
+#
+# Since the format is given as YYYY/MM/DD, we will assume non-negative years.
+#
+
+#
+# We could pull one of the gazillion date modules from CPAN and let it
+# do the calculations. But we'll do the calculations ourselves. We'll
+# take the date, calculate its Julian Day number (rounded down, as we don't
+# care about hours and minutes), compare it to the Julian Day number of today,
+# and then calculate the Julian Day numbers of the target dates, after
+# which we convert them back to dates.
+#
+
+#
+# Conversion functions from Wikipedia
+#
+
+sub g2j ($Y, $M, $D) {
+ use integer;
+ (1461 * ($Y + 4800 + ($M - 14) / 12)) / 4 +
+ (367 * ($M - 2 - 12 * (($M - 14) / 12))) / 12 -
+ (3 * (($Y + 4900 + ($M - 14) / 12) / 100)) / 4 + $D - 32075
+}
+
+sub j2g ($J) {
+ use integer;
+ my $e = 4 * ($J + 1401 + (((4 * $J + 274277) / 146097) * 3) / 4 - 38) + 3;
+ my $D = ((5 * (($e % 1461) / 4) + 2) % 153) / 5 + 1;
+ my $M = (((5 * (($e % 1461) / 4) + 2) / 153 + 2) % 12) + 1;
+ my $Y = ($e / 1461) - 4716 + (12 + 2 - $M) / 12;
+ ($Y, $M, $D)
+}
+
+
+my @TODAY = (2021, 9, 22); # Use a fixed today, so we have expected
+ # test results.
+
+my $julian_today = g2j @TODAY;
+
+while (<>) {
+ my ($Y, $M, $D) = /[0-9]+/g;
+ my $julian_then = g2j $Y, $M, $D;
+ printf "%04d/%02d/%02d, %04d/%02d/%02d\n",
+ j2g (2 * $julian_then - $julian_today),
+ j2g (2 * $julian_today - $julian_then);
+}
+
+
+__END__
diff --git a/challenge-132/abigail/perl/ch-2.pl b/challenge-132/abigail/perl/ch-2.pl
new file mode 100644
index 0000000000..1079f8f792
--- /dev/null
+++ b/challenge-132/abigail/perl/ch-2.pl
@@ -0,0 +1,157 @@
+#!/opt/perl/bin/perl
+
+use 5.032;
+
+use strict;
+use warnings;
+no warnings 'syntax';
+
+use experimental 'signatures';
+use experimental 'lexical_subs';
+
+#
+# See ../README.md
+#
+
+#
+# I have a very hard time of mapping the instructions for a relational
+# database to perl. Mainly, how to translate "If the size of the hash
+# table equals the maximum in-memory size"? Perl's solution to filling
+# up all memory is to crash. You certainly would not be able to add
+# anything to an existing structure.
+#
+# And it seems it is necessary to deal with cases not fitting into memory,
+# as the stated algorithm is explicitly used for the case it doesn't fit
+# into memory. The quote the line above the quoted algorithm:
+#
+# This algorithm is simple, but it requires that the smaller join
+# relation fits into memory, which is sometimes not the case.
+# A simple approach to handling this situation proceeds as follows:
+#
+# So, we're not asked to implement the classic hash join algorithm when
+# everything neatly fits into memory, but the case where it doesn't.
+# Which makes me really wonder, on what piss poor hardware is the
+# weekly challenge running where the given example doesn't fit in memory?
+#
+# There is a way out of this, but it requires a special compiled perl.
+# If your Perl has been compiled with the -DPERL_EMERGENCY_SBRK option,
+# and if it is using Perl's own malloc, then you can allocate some
+# emergency memory using $^M. So, we check if those conditions are set,
+# and allocate some emergency memory.
+#
+# Whenever we run out of memory, this is trapped, and we flush the
+# output so far, using the given algorithm.
+#
+# NOTE: This is a very flimsy algorithm, and will most likely result
+# in losing some data. But hey, if you want us to implement an
+# algorithm in Perl which deals with running out of memory, this
+# is the best you can get.
+# This is also gambling the state of the program is such that
+# we can actually continue after running out of memory. This
+# is not very likely.
+#
+# NOTE: This is completely untested. I couldn't be bothered to recompile
+# my perl.
+#
+
+#
+# First check if we can define emergency memory. If not, no hash join for you.
+# Else, define some emergency memory.
+#
+
+use Config;
+use List::Util 'max';
+
+BEGIN {
+ die "No hash join for you -- recompile first!\n" unless
+ $Config::Config {malloc_cflags} =~ /-DPERL_EMERGENCY_SBRK\b/ &&
+ $Config::Config {usemymalloc} eq 'y';
+
+ $^M = " " x (1 << 20); # 1 Mb.
+}
+
+my @R = (
+ [20, "Alex" ],
+ [28, "Joe" ],
+ [38, "Mike" ],
+ [18, "Alex" ],
+ [25, "David"],
+ [18, "Simon"],
+);
+
+my @S = (
+ ["Alex", "Stewart"],
+ ["Joe", "Root" ],
+ ["Mike", "Gatting"],
+ ["Joe", "Blog" ],
+ ["Alex", "Jones" ],
+ ["Simon","Duane" ],
+);
+
+my $idx_R_njk = 0;
+my $idx_R_jk = 1; # Join key
+my $idx_S_jk = 0; # Join key
+my $idx_S_njk = 1;
+
+#
+# To pretty print.
+#
+my $max_width = 3 + max map {length $$_ [$idx_R_jk]} @R;
+
+my %output;
+
+#
+# Whenever we run out of memory, we trap this, and flush the output.
+# This ought to release memory.
+#
+$SIG {__DIE__} = sub {
+ if ("@_" =~ /Out of memory/) {
+ flush (\@S, $idx_S_jk, \%output)
+ }
+ else {
+ die @_; # Propagate
+ }
+};
+
+sub flush ($S, $idx_S_jk, $output) {
+ undef $^M; # Release memory.
+ # Does this actually work this way? Or is $^M the only
+ # memory we can use? In that case, this entire program
+ # is not going to work.
+
+ #
+ # Scan $S. For each match in $output, output a line.
+ #
+ foreach my $entry (@$S) {
+ if ($$output {$$entry [$idx_S_jk]}) {
+ for (my $i = 0; $i < @{$$output {$$entry [$idx_S_jk]}}; $i ++) {
+ printf qq [%2d, %-${max_width}s "%s"\n],
+ $$output {$$entry [$idx_S_jk]} [$i],
+ '"' . $$entry [$idx_S_jk] . '",',
+ $$entry [$idx_S_njk];
+ }
+ }
+ }
+
+ #
+ # Reset output table
+ #
+ %$output = ();
+
+ #
+ # Claim emergency memory again
+ #
+ $^M = " " x (1 << 20);
+}
+
+#
+# Main loop.
+#
+foreach my $r (@R) {
+ push @{$output {$$r [$idx_R_jk]}} => $$r [$idx_R_njk];
+}
+
+
+flush (\@S, $idx_S_jk, \%output);
+
+__END__
diff --git a/challenge-132/abigail/python/ch-1.py b/challenge-132/abigail/python/ch-1.py
new file mode 100644
index 0000000000..0f70d519e4
--- /dev/null
+++ b/challenge-132/abigail/python/ch-1.py
@@ -0,0 +1,43 @@
+#!/opt/local/bin/python
+
+#
+# See ../README.md
+#
+
+#
+# Run as: python ch-1.py < input-file
+#
+
+import math
+import fileinput
+
+def _int (x):
+ if x < 0:
+ return math . ceil (x)
+ else:
+ return math . floor (x)
+
+
+def g2j (Y, M, D):
+ return (int ((1461 * (Y + 4800 + int ((M - 14) / 12))) / 4) +
+ int ((367 * (M - 2 - 12 * int ((M - 14) / 12))) / 12) -
+ int ((3 * int (((Y + 4900 + int ((M - 14) / 12)) / 100))) / 4) +
+ D - 32075)
+
+def j2g (J):
+ e = 4 * (J + 1401 + int (int ((4 * J + 274277) / 146097) * 3 / 4) - 38) + 3
+ D = int (((5 * (int ((e % 1461) / 4)) + 2) % 153) / 5) + 1
+ M = ((int ((5 * (int ((e % 1461) / 4)) + 2) / 153) + 2) % 12) + 1
+ Y = int (e / 1461) - 4716 + int ((12 + 2 - M) / 12)
+ return Y, M, D
+
+julian_today = g2j (2021, 9, 22)
+
+
+for line in fileinput . input ():
+ Y, M, D = map (lambda x: int (x), line . strip () . split ("/"))
+ julian_then = g2j (Y, M, D)
+ Y1, M1, D1 = j2g (2 * julian_then - julian_today)
+ Y2, M2, D2 = j2g (2 * julian_today - julian_then)
+ print ('{:04d}/{:02d}/{:02d}, {:04d}/{:02d}/{:02d}' .
+ format (Y1, M1, D1, Y2, M2, D2))
diff --git a/challenge-132/abigail/ruby/ch-1.rb b/challenge-132/abigail/ruby/ch-1.rb
new file mode 100644
index 0000000000..1574a72115
--- /dev/null
+++ b/challenge-132/abigail/ruby/ch-1.rb
@@ -0,0 +1,38 @@
+#!/usr/bin/ruby
+
+#
+# See ../README.md
+#
+
+#
+# Run as: ruby ch-1.rb < input-file
+#
+
+def div (x, y)
+ return (x . to_f / y) . to_i
+end
+
+def g2j (y, m, d)
+ return (div(1461 * (y + 4800 + div(m - 14, 12)), 4) +
+ div( 367 * (m - 2 - 12 * div(m - 14, 12)), 12) -
+ div( 3 * div(y + 4900 + div(m - 14, 12), 100), 4) + d - 32075)
+end
+
+def j2g (j)
+ e = 4 * (j + 1401 + div(div(4 * j + 274277, 146097) * 3, 4) - 38) + 3;
+ d = div((5 * div(e % 1461, 4) + 2) % 153, 5) + 1;
+ m = ((div( 5 * div(e % 1461, 4) + 2, 153) + 2) % 12) + 1;
+ y = div(e, 1461) - 4716 + div(12 + 2 - m, 12);
+ return y, m, d
+end
+
+julian_today = g2j 2021, 9, 22
+
+ARGF . each_line do
+ | line |
+ y, m, d = line . strip . split("/") . map {|x| x . to_i}
+ julian_then = g2j y, m, d
+ puts "%04d/%02d/%02d, %04d/%02d/%02d\n" %
+ [j2g(2 * julian_then - julian_today),
+ j2g(2 * julian_today - julian_then)] . flatten
+end