From e921f528bf55574f74fcf6e4ded3419bdb5ddd22 Mon Sep 17 00:00:00 2001 From: Roger Bell_West Date: Tue, 5 Mar 2024 09:33:39 +0000 Subject: RogerBW solutions for challenge no. 259 --- challenge-259/roger-bell-west/javascript/ch-1.js | 30 ++++ challenge-259/roger-bell-west/kotlin/ch-1.kt | 32 ++++ challenge-259/roger-bell-west/perl/ch-1.pl | 30 ++++ challenge-259/roger-bell-west/postscript/ch-1.ps | 200 +++++++++++++++++++++++ challenge-259/roger-bell-west/python/ch-1.py | 25 +++ challenge-259/roger-bell-west/raku/ch-1.p6 | 25 +++ challenge-259/roger-bell-west/ruby/ch-1.rb | 34 ++++ challenge-259/roger-bell-west/rust/ch-1.rs | 41 +++++ challenge-259/roger-bell-west/rust/ch-2.rs | 123 ++++++++++++++ challenge-259/roger-bell-west/scala/ch-1.scala | 32 ++++ challenge-259/roger-bell-west/tests.yaml | 15 ++ 11 files changed, 587 insertions(+) create mode 100755 challenge-259/roger-bell-west/javascript/ch-1.js create mode 100644 challenge-259/roger-bell-west/kotlin/ch-1.kt create mode 100755 challenge-259/roger-bell-west/perl/ch-1.pl create mode 100644 challenge-259/roger-bell-west/postscript/ch-1.ps create mode 100755 challenge-259/roger-bell-west/python/ch-1.py create mode 100755 challenge-259/roger-bell-west/raku/ch-1.p6 create mode 100755 challenge-259/roger-bell-west/ruby/ch-1.rb create mode 100755 challenge-259/roger-bell-west/rust/ch-1.rs create mode 100755 challenge-259/roger-bell-west/rust/ch-2.rs create mode 100644 challenge-259/roger-bell-west/scala/ch-1.scala create mode 100644 challenge-259/roger-bell-west/tests.yaml diff --git a/challenge-259/roger-bell-west/javascript/ch-1.js b/challenge-259/roger-bell-west/javascript/ch-1.js new file mode 100755 index 0000000000..903fd4e349 --- /dev/null +++ b/challenge-259/roger-bell-west/javascript/ch-1.js @@ -0,0 +1,30 @@ +#! /usr/bin/node + +"use strict" + +function bankingdayoffset(start, offset, bankholidays) { + let bh = new Set(bankholidays.map(x => new Date(Date.parse(x)).toString())); + let d = new Date(Date.parse(start)); + for (let i = 1; i <= offset; i++) { + d.setDate(d.getDate() + 1); + while (bh.has(d.toString()) || d.getDay() == 0 || d.getDay() == 6) { + d.setDate(d.getDate() + 1); + } + } + return d.getFullYear().toString().padStart(4, "0") + "-" + + (d.getMonth()+1).toString().padStart(2, "0") + "-" + + d.getDate().toString().padStart(2, "0"); +} + +if (bankingdayoffset('2018-06-28', 3, ['2018-07-03']) == '2018-07-04') { + process.stdout.write("Pass"); +} else { + process.stdout.write("FAIL"); +} +process.stdout.write(" "); +if (bankingdayoffset('2018-06-28', 3, []) == '2018-07-03') { + process.stdout.write("Pass"); +} else { + process.stdout.write("FAIL"); +} +process.stdout.write("\n"); diff --git a/challenge-259/roger-bell-west/kotlin/ch-1.kt b/challenge-259/roger-bell-west/kotlin/ch-1.kt new file mode 100644 index 0000000000..9b7cfb52aa --- /dev/null +++ b/challenge-259/roger-bell-west/kotlin/ch-1.kt @@ -0,0 +1,32 @@ +import java.time.LocalDate +import java.time.format.DateTimeFormatter + +fun bankingdayoffset(start: String, offset: Int, bankholidays: List): String { + val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") + val bh = bankholidays.map {LocalDate.parse(it, formatter)}.toSet() + var current = LocalDate.parse(start, formatter) + for (i in 1 .. offset) { + current = current.plusDays(1) + while (bh.contains(current) || current.getDayOfWeek().getValue() > 5) { + current = current.plusDays(1) + } + } + return current.format(formatter) +} + +fun main() { + + if (bankingdayoffset("2018-06-28", 3, listOf("2018-07-03")) == "2018-07-04") { + print("Pass") + } else { + print("Fail") + } + print(" ") + if (bankingdayoffset("2018-06-28", 3, emptyList()) == "2018-07-03") { + print("Pass") + } else { + print("Fail") + } + println("") + +} diff --git a/challenge-259/roger-bell-west/perl/ch-1.pl b/challenge-259/roger-bell-west/perl/ch-1.pl new file mode 100755 index 0000000000..ccaf86c903 --- /dev/null +++ b/challenge-259/roger-bell-west/perl/ch-1.pl @@ -0,0 +1,30 @@ +#! /usr/bin/perl + +use strict; +use warnings; +use experimental 'signatures'; + +use Test::More tests => 2; + +is(bankingdayoffset('2018-06-28', 3, ['2018-07-03']), '2018-07-04', 'example 1'); +is(bankingdayoffset('2018-06-28', 3, []), '2018-07-03', 'example 2'); + +use DateTime; +use DateTime::Format::Strptime; + +sub bankingdayoffset($start, $offset, $bankholidays) { + my $strp = DateTime::Format::Strptime->new( + pattern => '%Y-%m-%d', + strict => 1, + time_zone => 'GMT', + ); + my %bh = map {$strp->parse_datetime($_) => 1} @{$bankholidays}; + my $current = $strp->parse_datetime($start); + foreach (1 .. $offset) { + $current = $current->add(days => 1); + while (exists $bh{$current} || $current->day_of_week > 5) { + $current = $current->add(days => 1); + } + } + return $current->strftime('%Y-%m-%d'); +} diff --git a/challenge-259/roger-bell-west/postscript/ch-1.ps b/challenge-259/roger-bell-west/postscript/ch-1.ps new file mode 100644 index 0000000000..6e2e31189f --- /dev/null +++ b/challenge-259/roger-bell-west/postscript/ch-1.ps @@ -0,0 +1,200 @@ +%!PS + +% begin included library code +% see https://codeberg.org/Firedrake/postscript-libraries/ +/test { + /test.count test.count 1 add def + { + /test.pass test.pass 1 add def + } { + ( ) print + test.count (....) cvs print + (-fail) print + } ifelse +} bind def + +/jd2ymd { + 15 dict begin + /y 4716 def + /v 3 def + /j 1401 def + /u 5 def + /m 2 def + /s 153 def + /n 12 def + /w 2 def + /r 4 def + /B 274277 def + /p 1461 def + /C -38 def + dup + 4 mul B add 146097 idiv 3 mul 4 idiv C add j add add /f exch def + r f mul v add /e exch def + e p mod r idiv u mul w add /h exch def + /day h s mod u idiv 1 add def + /month h s idiv m add n mod 1 add def + /year e p idiv y sub n m add month sub n idiv add def + [ year month day ] + end +} bind def + +/map { % array proc -> array + 2 dict begin + /p exch def + [ exch + { + p + } forall + ] + end +} bind def + +/toset { % array -> dict of (value, true) + << exch + { + true + } forall + >> +} bind def + +/test.end { + ( ) print + test.count 0 gt { + (Passed ) print + test.pass (...) cvs print + (/) print + test.count (...) cvs print + ( \() print + test.pass 100 mul test.count idiv (...) cvs print + (%\)) print + (\r\n) print + } if +} bind def + +/strjoin % [(a) (b) (c)] (j) -> (ajbjc) +{ + 3 dict begin + /j exch def + dup 0 get /out exch def + /first true def + { + first { + pop + /first false def + } { + out j strconcat + exch strconcat + /out exch def + } ifelse + } forall + out + end +} bind def + +/a2s { + 2 dict begin + /i exch def + i length dup string /o exch def + 1 sub 0 exch 1 exch { + dup i 3 -1 roll get o 3 1 roll put + } for + o + end +} bind def + + +/test.start { + print (:) print + /test.pass 0 def + /test.count 0 def +} bind def + +/s2a { + [ exch { } forall ] +} bind def + +/ymd2jd { + 4 dict begin + aload pop + /d exch def + /m exch def + /y exch def + /mn m 14 sub 12 idiv def + y 4800 add mn add 1461 mul 4 idiv + mn 12 mul neg 2 sub m add 367 mul 12 idiv add + y 4900 add mn add 100 idiv 3 mul 4 idiv sub + d add + 32075 sub + end +} bind def + +/jd2dow { + 1 add 7 mod +} bind def + +/strconcat % (a) (b) -> (ab) +{ + [ + 3 -1 roll + s2a aload length + 2 add -1 roll + s2a aload pop + ] a2s +} bind def + + +% end included library code + +/s2jd { + 0 dict begin + /s exch def + [ exch + s 0 4 getinterval cvi + s 5 2 getinterval cvi + s 8 2 getinterval cvi + ] ymd2jd + end +} bind def + +/flz { + 0 dict begin + /width exch def + /value exch def + value type /stringtype ne { + /value value width string cvs def + } if + /out [ width { 48 } repeat ] a2s def + out width value length sub value putinterval + out + end +} bind def + +/bankingdayoffset { + 0 dict begin + /bh exch { s2jd } map toset def + /offset exch def + /d exch s2jd def + offset { + /d d 1 add def + { + d jd2dow dup + 0 gt exch 6 lt and + bh d known not and { + exit + } if + /d d 1 add def + } loop + } repeat + [ + d jd2ymd aload pop + 2 flz 3 1 roll + 2 flz 3 1 roll + 4 flz 3 1 roll + ] (-) strjoin + end +} bind def + +(bankingdayoffset) test.start +(2018-06-28) 3 [(2018-07-03)] bankingdayoffset (2018-07-04) eq test +(2018-06-28) 3 [] bankingdayoffset (2018-07-03) eq test +test.end diff --git a/challenge-259/roger-bell-west/python/ch-1.py b/challenge-259/roger-bell-west/python/ch-1.py new file mode 100755 index 0000000000..fef13ed084 --- /dev/null +++ b/challenge-259/roger-bell-west/python/ch-1.py @@ -0,0 +1,25 @@ +#! /usr/bin/python3 + +from datetime import date, timedelta + +def bankingdayoffset(start, offset, bankholidays): + bh = set(date.fromisoformat(i) for i in bankholidays) + d = date.fromisoformat(start) + day = timedelta(days = 1) + for _ in range(offset): + d += day + while d in bh or d.weekday() > 4: + d += day + return d.strftime("%Y-%m-%d") + +import unittest + +class TestBankingdayoffset(unittest.TestCase): + + def test_ex1(self): + self.assertEqual(bankingdayoffset("2018-06-28", 3, ["2018-07-03"]), "2018-07-04", 'example 1') + + def test_ex2(self): + self.assertEqual(bankingdayoffset("2018-06-28", 3, []), "2018-07-03", 'example 2') + +unittest.main() diff --git a/challenge-259/roger-bell-west/raku/ch-1.p6 b/challenge-259/roger-bell-west/raku/ch-1.p6 new file mode 100755 index 0000000000..f95a7cd92c --- /dev/null +++ b/challenge-259/roger-bell-west/raku/ch-1.p6 @@ -0,0 +1,25 @@ +#! /usr/bin/raku + +use Test; + +plan 2; + +is(bankingdayoffset('2018-06-28', 3, ['2018-07-03']), '2018-07-04', 'example 1'); +is(bankingdayoffset('2018-06-28', 3, []), '2018-07-03', 'example 2'); + +sub parsedate($s) { + $s ~~ /(<[0..9]>+)\D(<[0..9]>+)\D(<[0..9]>+)/; + return Date.new($0, $1, $2); +} + +sub bankingdayoffset($start, $offset, @bankholidays) { + my $bh = Set(@bankholidays.map({parsedate($_)})); + my $current = parsedate($start); + for (1 .. $offset) { + $current = $current.later(days => 1); + while ($bh{$current}:exists || $current.day-of-week > 5) { + $current = $current.later(days => 1); + } + } + return $current.yyyy-mm-dd; +} diff --git a/challenge-259/roger-bell-west/ruby/ch-1.rb b/challenge-259/roger-bell-west/ruby/ch-1.rb new file mode 100755 index 0000000000..4ea9277f76 --- /dev/null +++ b/challenge-259/roger-bell-west/ruby/ch-1.rb @@ -0,0 +1,34 @@ +#! /usr/bin/ruby + +require 'set' +require 'time' + +def parsedate(s) + return Time.strptime(s + " 12:00 +0000", '%Y-%m-%d %H:%M %z') +end + +def bankingdayoffset(start, offset, bankholidays) + bh = Set.new(bankholidays.map {|d| parsedate(d)}) + s = parsedate(start) + 1.upto(offset) do + s += 86400 + while bh.include?(s) || s.wday == 0 || s.wday == 6 do + s += 86400 + end + end + return s.strftime('%Y-%m-%d') +end + +require 'test/unit' + +class TestBankingdayoffset < Test::Unit::TestCase + + def test_ex1 + assert_equal('2018-07-04', bankingdayoffset('2018-06-28', 3, ['2018-07-03'])) + end + + def test_ex2 + assert_equal('2018-07-03', bankingdayoffset('2018-06-28', 3, [])) + end + +end diff --git a/challenge-259/roger-bell-west/rust/ch-1.rs b/challenge-259/roger-bell-west/rust/ch-1.rs new file mode 100755 index 0000000000..38598b9589 --- /dev/null +++ b/challenge-259/roger-bell-west/rust/ch-1.rs @@ -0,0 +1,41 @@ +// [dependencies] +// chrono = "0.4.34" + +use chrono::{Datelike, NaiveDate}; +use std::collections::HashSet; + +#[test] +fn test_ex1() { + assert_eq!( + bankingdayoffset("2018-06-28", 3, vec!["2018-07-03"]), + "2018-07-04" + ); +} + +#[test] +fn test_ex2() { + assert_eq!( + bankingdayoffset("2018-06-28", 3, Vec::<&str>::new()), + "2018-07-03" + ); +} + +fn parsedate(s: &str) -> NaiveDate { + NaiveDate::parse_from_str(s, "%Y-%m-%d").unwrap() +} + +fn bankingdayoffset( + start: &str, + offset: u32, + bankholidays: Vec<&str>, +) -> String { + let bh = bankholidays.iter().map(|i| parsedate(i)).collect::>(); + let mut d = parsedate(start); + for _ in 0..offset { + d = d.succ_opt().unwrap(); + while bh.contains(&d) || d.weekday().num_days_from_monday() > 4 { + d = d.succ_opt().unwrap(); + } + } + d.format("%Y-%m-%d").to_string() +} diff --git a/challenge-259/roger-bell-west/rust/ch-2.rs b/challenge-259/roger-bell-west/rust/ch-2.rs new file mode 100755 index 0000000000..70a0124249 --- /dev/null +++ b/challenge-259/roger-bell-west/rust/ch-2.rs @@ -0,0 +1,123 @@ +#! /bin/sh +//usr/bin/env rustc --test $0 -o ${0}x && ./${0}x --nocapture; rm -f ${0}x ; exit + +use std::collections::{HashMap, VecDeque}; + +#[derive(PartialEq, Debug)] +pub struct Lump { + id: String, + fields: HashMap, +} + +#[test] +fn test_ex1() { + assert_eq!( + lineparser( + "{% id field1=\"value1\" field2=\"value2\" field3=42 %}" + ), + Lump { + id: "id".to_string(), + fields: HashMap::from([ + ("field3".to_string(), "42".to_string()), + ("field2".to_string(), "value2".to_string()), + ("field1".to_string(), "value1".to_string()) + ]) + } + ); +} + +#[test] +fn test_ex2() { + assert_eq!( + lineparser("{% youtube title=\"Title \\\"quoted\\\" done\" %}"), + Lump { + id: "youtube".to_string(), + fields: HashMap::from([( + "title".to_string(), + "Title \"quoted\" done".to_string() + )]) + } + ); +} + +#[test] +fn test_ex3() { + assert_eq!( + lineparser( + "{% youtube title=\"Title with escaped backslash \\\\\" %}" + ), + Lump { + id: "youtube".to_string(), + fields: HashMap::from([( + "title".to_string(), + "Title with escaped backslash \\".to_string() + )]) + } + ); +} + +#[derive(PartialEq, Debug)] +enum State { + Outside, + PreID, + InID, + InterField, + FieldName, + FieldValue, + FieldValueQuoted, +} + +fn lineparser(line: &str) -> Lump { + let mut l = line.chars().collect::>(); + let mut state = State::Outside; + let mut trail: Vec = Vec::new(); + let mut fieldname = "".to_string(); + let mut out = Lump { id: "".to_string(), fields: HashMap::new() }; + while l.len() > 0 { + let mut c = l.pop_front().unwrap(); + if state == State::Outside && c == '{' { + c = l.pop_front().unwrap(); + if c == '%' { + state = State::PreID; + } + } else if (state == State::PreID || state == State::InID) && c != ' ' { + trail.push(c); + state = State::InID; + } else if state == State::InID && c == ' ' { + out.id = trail.into_iter().collect(); + trail = Vec::new(); + state = State::InterField; + } else if (state == State::InterField || state == State::FieldName) + && c != ' ' + && c != '=' + && c != '%' + { + trail.push(c); + state = State::FieldName; + } else if state == State::FieldName && c == '=' { + fieldname = trail.into_iter().collect(); + trail = Vec::new(); + state = State::FieldValue; + } else if state == State::FieldValue && trail.len() == 0 && c == '"' { + state = State::FieldValueQuoted; + } else if state == State::FieldValue || state == State::FieldValueQuoted + { + let mut literal = false; + if c == '\\' { + c = l.pop_front().unwrap(); + literal = true; + } + if (c == ' ' && state == State::FieldValue) + || (c == '"' && state == State::FieldValueQuoted && !literal) + { + out.fields + .insert(fieldname.clone(), trail.into_iter().collect()); + trail = Vec::new(); + state = State::InterField; + } else { + trail.push(c); + } + } + } + out +} diff --git a/challenge-259/roger-bell-west/scala/ch-1.scala b/challenge-259/roger-bell-west/scala/ch-1.scala new file mode 100644 index 0000000000..6e5b2e3f52 --- /dev/null +++ b/challenge-259/roger-bell-west/scala/ch-1.scala @@ -0,0 +1,32 @@ +import java.time.LocalDate +import java.time.format.DateTimeFormatter + +object Bankingdayoffset { + def bankingdayoffset(start: String, offset: Int, bankholidays: List[String]): String = { + val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") + val bh = bankholidays.map(d => LocalDate.parse(d, formatter)).toSet + var current = LocalDate.parse(start, formatter) + for (i <- 1 to offset) { + current = current.plusDays(1) + while (bh.contains(current) || current.getDayOfWeek().getValue() > 5) { + current = current.plusDays(1) + } + } + return current.format(formatter) + } + def main(args: Array[String]) { + if (bankingdayoffset("2018-06-28", 3, List("2018-07-03")) == "2018-07-04") { + print("Pass") + } else { + print("Fail") + } + print(" ") + if (bankingdayoffset("2018-06-28", 3, List()) == "2018-07-03") { + print("Pass") + } else { + print("Fail") + } + println("") + + } +} diff --git a/challenge-259/roger-bell-west/tests.yaml b/challenge-259/roger-bell-west/tests.yaml new file mode 100644 index 0000000000..3bc7c11499 --- /dev/null +++ b/challenge-259/roger-bell-west/tests.yaml @@ -0,0 +1,15 @@ +--- +ch-1: + - function: bankingdayoffset + multiarg: true + arguments: + - 2018-06-28 + - 3 + - - 2018-07-03 + result: 2018-07-04 + - multiarg: true + arguments: + - 2018-06-28 + - 3 + - [] + result: 2018-07-03 -- cgit