From d6547d06f1cb3102611a7a7df3d5a720fa645194 Mon Sep 17 00:00:00 2001 From: Abigail Date: Tue, 28 Sep 2021 14:21:01 +0200 Subject: AWK, Bash, C, Lua, Node,js, Perl, Python, and Ruby solutions for week 132 --- challenge-132/abigail/README.md | 6 +- challenge-132/abigail/awk/ch-1.awk | 43 ++++++++++ challenge-132/abigail/bash/ch-1.sh | 41 +++++++++ challenge-132/abigail/c/ch-1.c | 62 ++++++++++++++ challenge-132/abigail/lua/ch-1.lua | 45 ++++++++++ challenge-132/abigail/node/ch-1.js | 70 ++++++++++++++++ challenge-132/abigail/perl/ch-1.pl | 81 ++++++++++++++++++ challenge-132/abigail/perl/ch-2.pl | 157 +++++++++++++++++++++++++++++++++++ challenge-132/abigail/python/ch-1.py | 43 ++++++++++ challenge-132/abigail/ruby/ch-1.rb | 38 +++++++++ 10 files changed, 585 insertions(+), 1 deletion(-) create mode 100644 challenge-132/abigail/awk/ch-1.awk create mode 100644 challenge-132/abigail/bash/ch-1.sh create mode 100644 challenge-132/abigail/c/ch-1.c create mode 100644 challenge-132/abigail/lua/ch-1.lua create mode 100644 challenge-132/abigail/node/ch-1.js create mode 100644 challenge-132/abigail/perl/ch-1.pl create mode 100644 challenge-132/abigail/perl/ch-2.pl create mode 100644 challenge-132/abigail/python/ch-1.py create mode 100644 challenge-132/abigail/ruby/ch-1.rb 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 +# include +# include + +/* + * 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 -- cgit