14
\$\begingroup\$

I have a colleague at work that works from home every Tuesday and Thursday. At around 8:00 AM he sends us a message with the following text:

Hello today I'm working from home

In order to relieve him from the burden of doing this every day he stays at home, we would like to automate this task for him.

The challenge

Write in as few bytes as possible a piece of code that:

  • Receives the current time: your code may receive values for the current year, month (1-12), day of month (1-31), hour (0-23) and minute (0-59) and the day of the week (you can choose whether this number starts from 0 or 1, and if 0/1 means Sunday, Monday or any other day); alternatively you may receive a structure such as Date, DateTime, Calendar or any other time-related structure, if your language allows it. You can also receive a string with the date in yyyyMMddHHmm if you want, or two separate strings for date and time, and then an integer with the day of week. Feel free.
  • Returns two consistent truthy and falsey values, indicating if the message must be sent to the work chat or not.

Rules

  • This piece of code is assumed to be invoked periodically. The exact periodicity is irrelevant, nonetheless.
  • The truthy value must be returned if the day of week is Tuesday or Thursday and the time is 8:00 AM with an error margin of 10 minutes (from 7:50 to 8:10 inclusive).
  • The truthy value must be sent only if it is the first time the code is invoked between those hours for the specified day. We don't want the bot to send the same message several times in a row. The way you manage this restriction will be entirely up to you.
  • Your code may be an independent program executed repeatedly or it may be part of a bigger code that is always running. Your choice.
  • You may assume that there will be no reboots between executions of the code.
  • You may assume that the date will always be correct.
  • Explanations about your code and specifically about the method used to achieve persistence are encouraged.

Examples

(Week starts on Monday: 1, the following invokations will be made in succession)
2018,08,27,08,00,1 = falsey (not Tuesday or Thursday)
2018,08,28,07,45,2 = falsey (out of hours)
2018,08,28,07,55,2 = truthy (first time invoked this day at the proper hours)
2018,08,28,08,05,2 = falsey (second time invoked this day at the proper hours)
2018,08,28,08,15,2 = falsey (out of hours)
2018,08,29,08,00,3 = falsey (not Tuesday or Thursday)
2018,08,29,18,00,3 = falsey (not Tuesday or Thursday)
2018,08,30,07,49,4 = falsey (out of hours)
2018,08,30,07,50,4 = truthy (first time invoked this day at the proper hours)
2018,08,30,07,50,4 = falsey (second time invoked this day at the proper hours)
2018,08,30,08,10,4 = falsey (third time invoked this day at the proper hours)
2018,08,30,08,11,4 = falsey (out of hours)
2018,09,04,08,10,2 = truthy (first time invoked this day at the proper hours)

This is , so may the shortest code for each language win!

\$\endgroup\$
  • \$\begingroup\$ This comes from the sandbox. \$\endgroup\$ – Charlie Aug 28 '18 at 13:59
  • \$\begingroup\$ Is there any restriction in the input format? Can I take the date as a single parameter like YYYYmmdd and the time as well HHss? \$\endgroup\$ – Luis felipe De jesus Munoz Aug 28 '18 at 14:13
  • 1
    \$\begingroup\$ @LuisfelipeDejesusMunoz yes, if you want you may receive the date and time in that format. I have updated the question to make that clear. \$\endgroup\$ – Charlie Aug 28 '18 at 14:17
  • 1
    \$\begingroup\$ @KamilDrakari the program must check the date given as parameter, you cannot take the current date. If you do so it will be impossible to make the code pass a test battery like the one I propose in the question. \$\endgroup\$ – Charlie Aug 28 '18 at 16:07
  • 2
    \$\begingroup\$ So, you're polling a script regularly to be useful at most once a day, 2/7th of the days? If you automate all your tasks like that... \$\endgroup\$ – Mast Aug 28 '18 at 18:23

12 Answers 12

15
\$\begingroup\$

JavaScript (ES6), 43 bytes

f=(D,t,d)=>5>>d&t>749&t<811&&!f[D]*(f[D]=1)

Try it online!

Input

  • the date as a string in yyyymmdd format
  • the time as a string in hhmm format
  • the day of week as a 0-indexed integer, with 0 = Tuesday, 1 = Wednesday, ..., 6 = Monday

Output

Returns 0 or 1.

Commented

f = (            // named function, as the underlying object will be used as storage
  D,             // D = date (string)
  t,             // t = time (string)
  d              // d = day of week (integer)
) =>             //
  5              // 5 is 0000101 in binary, where 1's are set for Tuesday and Thursday
  >> d &         // test the relevant bit for the requested day of week
  t > 749 &      // test whether we are in the correct time slot
  t < 811        //
  && !f[D] *     // make sure that this date was not already invoked at a correct time
  (f[D] = 1)     // and store it in the underlying object of f()
\$\endgroup\$
  • 7
    \$\begingroup\$ Javascript (and your mastery of it) will always amaze me. \$\endgroup\$ – Charlie Aug 28 '18 at 14:31
  • 1
    \$\begingroup\$ ES6 is fun to golf with :) Is the 2nd input format valid? \$\endgroup\$ – Arnauld Aug 28 '18 at 14:36
  • \$\begingroup\$ Yes, I already specified that in the text of the question. \$\endgroup\$ – Charlie Aug 28 '18 at 14:37
5
\$\begingroup\$

Python 3, 69 bytes

f=lambda w,r,*t,l={0}:r not in l!=w in(2,4)<(7,49)<t<(8,11)!=l.add(r)

Try it online!

Takes input as f(day of the week, date, hours, minutes), where date can be in any consistent format.

\$\endgroup\$
5
\$\begingroup\$

APL (Dyalog Unicode), 61 53 50 48 37 36 bytesSBCS

Anonymous infix lambda. Called with YYYYMMDD f hhmm and then prompts for weekday number; 2 and 4 are Tuesday and Thursday. Redefines the global D to remember dates.

D←⍬
{≢D,←⍺/⍨(⎕∊2 4)∧(⍺∊D)<30≥|780-⍵}

Try it online!

D←⍬ initialise D to be an empty set

{} anonymous lambda; is YYYYMMDD, is hhmm
780-⍵ difference between 780 (mean of 0750 and 0810) and the time
| absolute value of that
30≥ is 30 greater or equal to that?
()< and it is not true that:
  ⍺∊D the date is a member of D
()∧ and it is true that:
  ⎕∊2 4 the prompted for weekday is a member of the set {2,4}
⍺/⍨ use that to compress the date (i.e. gives {} if false, {date} if true)
D,← append that to D
 and return its tally (i.e. 0 or 1, which are APL's false and true)

\$\endgroup\$
4
\$\begingroup\$

Excel formula, 85 bytes

=IF(AND(MID(WEEKDAY(A1)/0,684;3;1)="3";A1-INT(A1)>=0,32638;A1-INT(A1)<=0,34028);TRUE)

Weekday with no parameters are from 1 (Sunday) to 7 (Saturday). The days we want are 3 and 5. Dividing all numbers from 1 to 7 for 0,648, only 3 and 5 gives a result where the first decimal is 3 (Got it by dividing with rand())

Input is inserted on Cell A1

\$\endgroup\$
  • \$\begingroup\$ You could use MID(WEEKDAY(A1)/0,29;5;1)="4" and also ;1;) instead of ;TRUE) \$\endgroup\$ – adebunk Aug 28 '18 at 21:01
4
\$\begingroup\$

Clean, 343 326 303 279 216 bytes

Clean is so ill-suited to this it's like trying to paint a fence with a chainsaw.

import StdEnv,System.Environment,System._Unsafe
?(y,x,z)=y*480+x*40+z
$y h m d=(d-3)^2==1&&((h-8)*60+m)^2<121&&appUnsafe(setEnvironmentVariable"l"(fromInt(?y)))(maybe 0toInt(accUnsafe(getEnvironmentVariable"l")))< ?y

Try it online!

Golfing then explaination.

\$\endgroup\$
  • 1
    \$\begingroup\$ +1 Just for the painting a fence with a chainsaw reference! :D \$\endgroup\$ – PerpetualJ Sep 27 '18 at 18:44
4
\$\begingroup\$

R, 114 106 bytes

function(D,y=D:"%D",u=D$h==7&D$mi>49|D$h==8&D$mi<11&D$w%in%2^4&!y%in%L,`:`=format,`^`=c){L<<-L^y[u];u}
L=F

Try it online!

Persistence:

Date is checked against L, the list of dates where the code returned TRUE. When the code returns TRUE, today's date is appended to this list. Otherwise the list is not modified.

Saved 6 bytes thanks to @Giuseppe!

Made the code actually work and saved 2 bytes thanks to @digEmAll!

\$\endgroup\$
  • \$\begingroup\$ This method takes the current time instead of receiving it as a parameter, doesn't it? \$\endgroup\$ – Charlie Aug 28 '18 at 15:25
  • \$\begingroup\$ @Charlie looks I I should have read the challenge more carefully... would have made my life easier ! I will update. \$\endgroup\$ – JayCe Aug 28 '18 at 15:27
  • \$\begingroup\$ ^ has higher precedence than %any% but * has lower precedence than %any%, so using ^ you can get rid of some parentheses, and I golfed a few more down, too! Pretty sure it works for 108 bytes \$\endgroup\$ – Giuseppe Aug 28 '18 at 15:41
  • 1
    \$\begingroup\$ You could also use : instead of ^, for the fun of it, and so your code has a million : in it. \$\endgroup\$ – Giuseppe Aug 28 '18 at 15:41
  • \$\begingroup\$ @Giuseppe It does have a ton of : now! \$\endgroup\$ – JayCe Aug 28 '18 at 16:23
3
\$\begingroup\$

C (gcc),  78   50  49 bytes

D;f(d,w,t){w=d-D&&w<4&&w%2&&t>749&&t<811&&(D=d);}

Try it online!

The expected inputs are:

  • d: the date, as a single number yyyymmdd
  • w: the day of the week, starting with Monday (0)
  • t: the time, as a single number hhmm

Explanation

D;                                      // the date we last said hello.
f(d,                                    // date
    w,                                  // day of the week
      t)                                // time
{
  w=                                    // replaces return
    d-D                                 // if we did not say hello today
       &&w<4&&w%2                       // and we are Tuesday(1) or Thursday(3)
                 &&t>749&&t<811         // and time is between 7:50 and 8:10, inclusive
                               &&(D=d); // then we say hello (evaluated to true) and update D
}

Edits

  • Saved 28 bytes thanks to Adám
  • Saved 1 more byte, since abs() was actually not helping with the new version
\$\endgroup\$
  • 1
    \$\begingroup\$ Why not take YYYYMMDD and hhmm as single numbers? \$\endgroup\$ – Adám Aug 28 '18 at 15:51
  • \$\begingroup\$ @Adám Indeed... I'll try that when I have some time \$\endgroup\$ – Annyo Aug 30 '18 at 6:27
  • \$\begingroup\$ Suggest w<4&w%2&t>749&t<811 instead of w<4&&w%2&&t>749&&t<811 \$\endgroup\$ – ceilingcat Sep 22 '18 at 9:59
2
\$\begingroup\$

Batch, 109 bytes

@if %3 neq 2 if %3 neq 4 exit/b1
@if %2 geq 07:50 if %2 leq 08:10 if .%1 neq .%l% set l=%1&exit/b0
@exit/b1

Takes input in the form date time dow e.g. 2018-09-04 08:10 2 and outputs via exit code. Explanation: The environment variable l (or any other single letter would work) is used to store the last successful date that passes the test. (The date format itself does not matter as long as it is consistent and does not contain spaces.)

\$\endgroup\$
2
\$\begingroup\$

Perl 6, 33 bytes

{811>$^t>749>5+>$^w%2>(%){$^d}++}

Try it online!

Heavily inspired by Arnauld's solution. Uses the same input format.

\$\endgroup\$
1
\$\begingroup\$

C#, 121 Bytes

int[] d=new int[]{2,4};
double s=>Now.TimeOfDay.TotalSeconds;
bool h=>d.Contains((int)Now.DayOfWeek)&&s>=470&&s<=490;

Moving all three to the same line reduces size to 117 bytes. h is used as a property, just read the value prior to sending the message:

if (h) SendMessage();
\$\endgroup\$
1
\$\begingroup\$

F#, 119 bytes

let f w d h m l = if not(l|>Seq.contains d)&&[3;5]|>Seq.contains w&&(h=7&&m>49||h=8&&m<11)then(l@[d],true)else(l,false)

let f w d h m l =

declare function called f with parameters w (day of week) d (date) h (hour) m (minute) l (list of dates it's run on)

if not(l|>Seq.contains d) if the list of dates doesn't contain the passed date

&&[3;5]|>Seq.contains w and the day is Tuesday (3) or Wednesday (5)

&&(h=7&&m>49||h=8&&m<11) and the time is between (exclusive) 7:49 and 8:11

then(l@[d],true) then return a tuple containing the list of dates with the current date appended, and true

else(l,false) else return a tuple containing the list of dates without today and false

\$\endgroup\$
0
\$\begingroup\$

Bash 95 87 bytes

[ $(ps -ef|grep $0|wc -l) -gt 3 -o $2 -lt 750 -o $2 -gt 810 ]||((10>>$3&1))&&sleep 20m

Edit: saved 8 bytes by stealing an idea from Annyo

Call with yyyymmdd HHMM D, with D starting at 0, for Monday.

I'm not entirely sure why I have the line count check set to three, it seems it should be two, but two fails to work and three seems to work.

Also, I haven't bothered using the date, but the requirements seem to indicate that we should accept the date, so I took the option mentioned to take the time separately and just ignore the date value.

\$\endgroup\$
  • \$\begingroup\$ If you don't use the date, how do you check that you don't send the message twice for the same day? \$\endgroup\$ – Charlie Aug 30 '18 at 9:49
  • \$\begingroup\$ It sticks around for 20 minutes and the first check ensures that there's not an existing copy running \$\endgroup\$ – crystalgecko Aug 30 '18 at 9:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.