Skip to content

Commit 4a5c309

Browse files
authored
Add swift-scheduling exercise (#372)
1 parent 8b586cd commit 4a5c309

File tree

9 files changed

+323
-0
lines changed

9 files changed

+323
-0
lines changed

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1630,6 +1630,14 @@
16301630
"practices": [],
16311631
"prerequisites": [],
16321632
"difficulty": 5
1633+
},
1634+
{
1635+
"slug": "swift-scheduling",
1636+
"name": "Swift Scheduling",
1637+
"uuid": "e6ab1dea-ad65-499b-ab5e-140d4d76420e",
1638+
"practices": [],
1639+
"prerequisites": [],
1640+
"difficulty": 4
16331641
}
16341642
],
16351643
"foregone": [
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Instructions
2+
3+
Your task is to convert delivery date descriptions to _actual_ delivery dates, based on when the meeting started.
4+
5+
There are two types of delivery date descriptions:
6+
7+
1. Fixed: a predefined set of words.
8+
2. Variable: words that have a variable component, but follow a predefined set of patterns.
9+
10+
## Fixed delivery date descriptions
11+
12+
There are three fixed delivery date descriptions:
13+
14+
- `"NOW"`
15+
- `"ASAP"` (As Soon As Possible)
16+
- `"EOW"` (End Of Week)
17+
18+
The following table shows how to translate them:
19+
20+
| Description | Meeting start | Delivery date |
21+
| ----------- | ----------------------------- | ----------------------------------- |
22+
| `"NOW"` | - | Two hours after the meeting started |
23+
| `"ASAP"` | Before 13:00 | Today at 17:00 |
24+
| `"ASAP"` | After or at 13:00 | Tomorrow at 13:00 |
25+
| `"EOW"` | Monday, Tuesday, or Wednesday | Friday at 17:00 |
26+
| `"EOW"` | Thursday or Friday | Sunday at 20:00 |
27+
28+
## Variable delivery date descriptions
29+
30+
There are two variable delivery date description patterns:
31+
32+
- `"<N>M"` (N-th month)
33+
- `"Q<N>"` (N-th quarter)
34+
35+
| Description | Meeting start | Delivery date |
36+
| ----------- | -------------------------- | ----------------------------------------------------------- |
37+
| `"<N>M"` | Before N-th month | At 8:00 on the _first_ workday¹ of this year's N-th month |
38+
| `"<N>M"` | After or in N-th month | At 8:00 on the _first_ workday¹ of next year's N-th month |
39+
| `"Q<N>"` | Before or in N-th quarter² | At 8:00 on the _last_ workday¹ of this year's N-th quarter² |
40+
| `"Q<N>"` | After N-th quarter² | At 8:00 on the _last_ workday¹ of next year's N-th quarter² |
41+
42+
¹ A workday is a Monday, Tuesday, Wednesday, Thursday, or Friday.
43+
² A year has four quarters, each with three months: January/February/March, April/May/June, July/August/September, and October/November/December.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Introduction
2+
3+
This week, it is your turn to take notes in the department's planning meeting.
4+
In this meeting, your boss will set delivery dates for all open work items.
5+
Annoyingly, instead of specifying the _actual_ delivery dates, your boss will only _describe them_ in an abbreviated format.
6+
As many of your colleagues won't be familiar with this corporate lingo, you'll need to convert these delivery date descriptions to actual delivery dates.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"authors": [
3+
"glennj"
4+
],
5+
"files": {
6+
"solution": [
7+
"swift-scheduling.tcl"
8+
],
9+
"test": [
10+
"swift-scheduling.test"
11+
],
12+
"example": [
13+
".meta/example.tcl"
14+
]
15+
},
16+
"blurb": "Convert delivery date descriptions to actual delivery dates."
17+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
proc deliveryDate {timestamp target} {
2+
set t [clock scan $timestamp -format {%Y-%m-%dT%T}]
3+
4+
switch -regexp -matchvar m -- $target {
5+
{^NOW$} { set t [now $t] }
6+
{^ASAP$} { set t [asap $t] }
7+
{^EOW$} { set t [eow $t] }
8+
{^(\d+)M$} { set t [month $t [lindex $m 1]] }
9+
{^Q(\d)$} { set t [quarter $t [lindex $m 1]] }
10+
default { error "Don't understand $target" }
11+
}
12+
13+
return [clock format $t -format {%Y-%m-%dT%T}]
14+
}
15+
16+
#########################################################
17+
proc now {timeVal} {
18+
return [clock add $timeVal 2 hours]
19+
}
20+
21+
proc asap {timeVal} {
22+
set hour [clock format $timeVal -format {%k}]
23+
# truncate time to midnight
24+
set midnight [clock scan [clock format $timeVal -format {%Y-%m-%d}] -format {%Y-%m-%d}]
25+
26+
if {$hour < 13} {
27+
return [clock add $midnight 17 hours]
28+
} else {
29+
return [clock add $midnight 1 day 13 hours]
30+
}
31+
}
32+
33+
proc eow {timeVal} {
34+
set dow [clock format $timeVal -format {%w}]
35+
set midnight [clock scan [clock format $timeVal -format {%Y-%m-%d}] -format {%Y-%m-%d}]
36+
37+
if {$dow in {1 2 3}} {
38+
set days [expr {5 - $dow}]
39+
set hours 17
40+
} else {
41+
set days [expr {7 - $dow}]
42+
set hours 20
43+
}
44+
return [clock add $midnight $days days $hours hours]
45+
}
46+
47+
proc month {timeVal targetMonth} {
48+
# %N is the month number with no leading zero
49+
lassign [clock format $timeVal -format {%Y %N}] year month
50+
if {$month >= $targetMonth} {
51+
incr year
52+
}
53+
set firstDay [clock scan "$year-$targetMonth-01" -format {%Y-%N-%d}]
54+
55+
set dow [clock format $firstDay -format {%u}]
56+
if {$dow > 5} {
57+
# add one or two days
58+
set firstDay [clock add $firstDay [expr {8 - $dow}] days]
59+
}
60+
61+
return [clock add $firstDay 8 hours]
62+
}
63+
proc quarter {timeVal targetQuarter} {
64+
set lastQuarterMonth [expr {3 * $targetQuarter}]
65+
lassign [clock format $timeVal -format {%Y %N}] year month
66+
if {$month > $lastQuarterMonth} {
67+
incr year
68+
}
69+
set lastQuarterMonthFirstDay [clock scan "$year-$lastQuarterMonth-01" -format {%Y-%N-%d}]
70+
set targetDay [clock add $lastQuarterMonthFirstDay 1 month -1 day]
71+
72+
set dow [clock format $targetDay -format {%u}]
73+
if {$dow > 5} {
74+
# subtract one or two days
75+
set targetDay [clock add $targetDay [expr {5 - $dow}] days]
76+
}
77+
78+
return [clock add $targetDay 8 hours]
79+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[1d0e6e72-f370-408c-bc64-5dafa9c6da73]
13+
description = "NOW translates to two hours later"
14+
15+
[93325e7b-677d-4d96-b017-2582af879dc2]
16+
description = "ASAP before one in the afternoon translates to today at five in the afternoon"
17+
18+
[cb4252a3-c4c1-41f6-8b8c-e7269733cef8]
19+
description = "ASAP at one in the afternoon translates to tomorrow at one in the afternoon"
20+
21+
[6fddc1ea-2fe9-4c60-81f7-9220d2f45537]
22+
description = "ASAP after one in the afternoon translates to tomorrow at one in the afternoon"
23+
24+
[25f46bf9-6d2a-4e95-8edd-f62dd6bc8a6e]
25+
description = "EOW on Monday translates to Friday at five in the afternoon"
26+
27+
[0b375df5-d198-489e-acee-fd538a768616]
28+
description = "EOW on Tuesday translates to Friday at five in the afternoon"
29+
30+
[4afbb881-0b5c-46be-94e1-992cdc2a8ca4]
31+
description = "EOW on Wednesday translates to Friday at five in the afternoon"
32+
33+
[e1341c2b-5e1b-4702-a95c-a01e8e96e510]
34+
description = "EOW on Thursday translates to Sunday at eight in the evening"
35+
36+
[bbffccf7-97f7-4244-888d-bdd64348fa2e]
37+
description = "EOW on Friday translates to Sunday at eight in the evening"
38+
39+
[d651fcf4-290e-407c-8107-36b9076f39b2]
40+
description = "EOW translates to leap day"
41+
42+
[439bf09f-3a0e-44e7-bad5-b7b6d0c4505a]
43+
description = "2M before the second month of this year translates to the first workday of the second month of this year"
44+
45+
[86d82e83-c481-4fb4-9264-625de7521340]
46+
description = "11M in the eleventh month translates to the first workday of the eleventh month of next year"
47+
48+
[0d0b8f6a-1915-46f5-a630-1ff06af9da08]
49+
description = "4M in the ninth month translates to the first workday of the fourth month of next year"
50+
51+
[06d401e3-8461-438f-afae-8d26aa0289e0]
52+
description = "Q1 in the first quarter translates to the last workday of the first quarter of this year"
53+
54+
[eebd5f32-b16d-4ecd-91a0-584b0364b7ed]
55+
description = "Q4 in the second quarter translates to the last workday of the fourth quarter of this year"
56+
57+
[c920886c-44ad-4d34-a156-dc4176186581]
58+
description = "Q3 in the fourth quarter translates to the last workday of the third quarter of next year"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
proc deliveryDate {timestamp target} {
2+
throw {NOT_IMPLEMENTED} "Implement this procedure."
3+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#!/usr/bin/env tclsh
2+
package require tcltest
3+
namespace import ::tcltest::*
4+
source testHelpers.tcl
5+
6+
############################################################
7+
source "swift-scheduling.tcl"
8+
9+
test swift-scheduling-01 "NOW translates to two hours later" -body {
10+
deliveryDate "2012-02-13T09:00:00" "NOW"
11+
} -returnCodes ok -result "2012-02-13T11:00:00"
12+
13+
skip swift-scheduling-02
14+
test swift-scheduling-02 "ASAP before one in the afternoon translates to today at five in the afternoon" -body {
15+
deliveryDate "1999-06-03T09:45:00" "ASAP"
16+
} -returnCodes ok -result "1999-06-03T17:00:00"
17+
18+
skip swift-scheduling-03
19+
test swift-scheduling-03 "ASAP at one in the afternoon translates to tomorrow at one in the afternoon" -body {
20+
deliveryDate "2008-12-21T13:00:00" "ASAP"
21+
} -returnCodes ok -result "2008-12-22T13:00:00"
22+
23+
skip swift-scheduling-04
24+
test swift-scheduling-04 "ASAP after one in the afternoon translates to tomorrow at one in the afternoon" -body {
25+
deliveryDate "2008-12-21T14:50:00" "ASAP"
26+
} -returnCodes ok -result "2008-12-22T13:00:00"
27+
28+
skip swift-scheduling-05
29+
test swift-scheduling-05 "EOW on Monday translates to Friday at five in the afternoon" -body {
30+
deliveryDate "2025-02-03T16:00:00" "EOW"
31+
} -returnCodes ok -result "2025-02-07T17:00:00"
32+
33+
skip swift-scheduling-06
34+
test swift-scheduling-06 "EOW on Tuesday translates to Friday at five in the afternoon" -body {
35+
deliveryDate "1997-04-29T10:50:00" "EOW"
36+
} -returnCodes ok -result "1997-05-02T17:00:00"
37+
38+
skip swift-scheduling-07
39+
test swift-scheduling-07 "EOW on Wednesday translates to Friday at five in the afternoon" -body {
40+
deliveryDate "2005-09-14T11:00:00" "EOW"
41+
} -returnCodes ok -result "2005-09-16T17:00:00"
42+
43+
skip swift-scheduling-08
44+
test swift-scheduling-08 "EOW on Thursday translates to Sunday at eight in the evening" -body {
45+
deliveryDate "2011-05-19T08:30:00" "EOW"
46+
} -returnCodes ok -result "2011-05-22T20:00:00"
47+
48+
skip swift-scheduling-09
49+
test swift-scheduling-09 "EOW on Friday translates to Sunday at eight in the evening" -body {
50+
deliveryDate "2022-08-05T14:00:00" "EOW"
51+
} -returnCodes ok -result "2022-08-07T20:00:00"
52+
53+
skip swift-scheduling-10
54+
test swift-scheduling-10 "EOW translates to leap day" -body {
55+
deliveryDate "2008-02-25T10:30:00" "EOW"
56+
} -returnCodes ok -result "2008-02-29T17:00:00"
57+
58+
skip swift-scheduling-11
59+
test swift-scheduling-11 "2M before the second month of this year translates to the first workday of the second month of this year" -body {
60+
deliveryDate "2007-01-02T14:15:00" "2M"
61+
} -returnCodes ok -result "2007-02-01T08:00:00"
62+
63+
skip swift-scheduling-12
64+
test swift-scheduling-12 "11M in the eleventh month translates to the first workday of the eleventh month of next year" -body {
65+
deliveryDate "2013-11-21T15:30:00" "11M"
66+
} -returnCodes ok -result "2014-11-03T08:00:00"
67+
68+
skip swift-scheduling-13
69+
test swift-scheduling-13 "4M in the ninth month translates to the first workday of the fourth month of next year" -body {
70+
deliveryDate "2019-11-18T15:15:00" "4M"
71+
} -returnCodes ok -result "2020-04-01T08:00:00"
72+
73+
skip swift-scheduling-14
74+
test swift-scheduling-14 "Q1 in the first quarter translates to the last workday of the first quarter of this year" -body {
75+
deliveryDate "2003-01-01T10:45:00" "Q1"
76+
} -returnCodes ok -result "2003-03-31T08:00:00"
77+
78+
skip swift-scheduling-15
79+
test swift-scheduling-15 "Q4 in the second quarter translates to the last workday of the fourth quarter of this year" -body {
80+
deliveryDate "2001-04-09T09:00:00" "Q4"
81+
} -returnCodes ok -result "2001-12-31T08:00:00"
82+
83+
skip swift-scheduling-16
84+
test swift-scheduling-16 "Q3 in the fourth quarter translates to the last workday of the third quarter of next year" -body {
85+
deliveryDate "2022-10-06T11:00:00" "Q3"
86+
} -returnCodes ok -result "2023-09-29T08:00:00"
87+
88+
89+
cleanupTests
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#############################################################
2+
# Override some tcltest procs with additional functionality
3+
4+
# Allow an environment variable to override `skip`
5+
proc skip {patternList} {
6+
if { [info exists ::env(RUN_ALL)]
7+
&& [string is boolean -strict $::env(RUN_ALL)]
8+
&& $::env(RUN_ALL)
9+
} then return else {
10+
uplevel 1 [list ::tcltest::skip $patternList]
11+
}
12+
}
13+
14+
# Exit non-zero if any tests fail.
15+
# The cleanupTests resets the numTests array, so capture it first.
16+
proc cleanupTests {} {
17+
set failed [expr {$::tcltest::numTests(Failed) > 0}]
18+
uplevel 1 ::tcltest::cleanupTests
19+
if {$failed} then {exit 1}
20+
}

0 commit comments

Comments
 (0)