18
\$\begingroup\$

My boss needs to know how long it takes to add together two integers. But, I don't like to work weekends, and I think its fair that my code doesn't either. The problem is, the boss is a demanding guy and thinks I should put in over time to make sure the time it takes stays the same, and I know he is going to check if the code works properly.

Can you write me a short program that:

  1. Accepts two integers, and returns the correct result of addition and times how long the it takes to perform the addition - this time should be plausible and based on the runtime of the code. However, if you need to sneak some operations between the timed code that makes it run slightly longer than it should this is permitted. You cannot however just output a fake time.
  2. Doesn't work on weekends in the codes local-time (it can't just return a wrong result, the code needs to break, error, or otherwise fail to execute)
  3. Isn't immediately obvious as to why it doesn't work on weekends

I know the first criterion is kind of weird, but I wanted to make sure people could import date/time libraries if needed, without raising suspicion for criteria 3. However, I'm sure there are some smart folk, so -10 characters to anyone who can do this, without using calendar functions from standard date libraries

Regarding 'standard date/time libraries'

Examples of standard datetime libraries include pythons datetime, javascript date object library, java.util.Date and the like. Functions to calculate timedeltas for execution such as pythons timeit module would not violate this criteia as the boss is expectng the code to to be timed. In some cases, these libraries will need to be imported to access any time functions, so its permitted to call functions that return the time since the start of the current epoch as an integer, but calendar functions that return structured datetime objects that can give separate hours, days, etc... are not allowed.

edit: Regarding Dan04's question, the code must meet these 4 criteria regarding when it will work or not work. You should also explain how your code checks the time, as the slack on Monday morning/Friday night should give some opportunity for some creative ways to shorten the code.

  • must not work from 00:00:00 Saturday morning through 23:59:59 Sunday night.
  • must always work from 06:00:00 Monday morning through 19:59:59 Friday evening
  • can either work or not work from 00:00:00 Monday morning through 5:59:59 Monday morning
  • can either work or not work from 20:00:00 Friday evening through 23:59:59 Friday night morning

edit2: By immediately obvious it must meet the following 3 criteria:

  • Must not call a function that called DayOfWeek (or similar), without using it to calculate the time of the function.
  • Must not use Saturday or Sunday or their abbreviations in English.
  • Must not use Sat or Sun (or in their alternate letter cases) without an identical named variable not used to determine the day of the week or when determining if the code should run.
\$\endgroup\$
10
  • \$\begingroup\$ How are you defining "weekends"? Is it OK if the code stops working on Friday afternoon instead of waiting until midnight? \$\endgroup\$
    – dan04
    Commented Aug 12, 2013 at 3:15
  • \$\begingroup\$ @dan04 I'll update to address this. \$\endgroup\$
    – user8777
    Commented Aug 12, 2013 at 3:57
  • 4
    \$\begingroup\$ if creative answers are desired, this shouldn't be a code golf. If code golf is desired, you need to objectively define "immediately obvious". \$\endgroup\$ Commented Aug 12, 2013 at 4:24
  • \$\begingroup\$ is the time to be understood as local time, or GMT? \$\endgroup\$ Commented Aug 12, 2013 at 4:28
  • 1
    \$\begingroup\$ why are you not in the chat room? \$\endgroup\$ Commented Aug 12, 2013 at 6:33

3 Answers 3

11
\$\begingroup\$

Rebmu: 17 (27 - 10, obfuscated) or 30 unobfuscated

Rebmu is specifically designed to play code golf while being readable (for those who get the "trick"), so the obfuscation rule is against its principle. But:

DnowRjRkILd/7 6[pDT[adJk]]

It works all day on weekdays:

Input Integer: 10
Input Integer: 20
0:00:00.000008

...but on weekends it just does nothing:

Input Integer: 10
Input Integer: 20

Explanation:

Using the unmushing and noticing capital runs of letters are separate words, and the lack of a leading capital run means we're not making a set-word, we get the abbreviated Rebol:

d: now
r j
r k
il d/7 6 [
    p dt [
        ad j k
    ]
]

Un-abbreviating it, what you wind up with is:

;-- save current date and time into "d"
d: now

;-- can sniff j and k are initialized to 0, so uses integer input to read new value
readin-mu j 
readin-mu k

;-- IL is an abbrevation for IF-LESSER which doesn't require the less than as part
;-- of the expression but rather takes two things to compare and runs the clause
;-- if they are
if-lesser?-mu d/7 6 [
    print delta-time [
        add j k
    ]
]

Date numbers in Rebol are numbered 1 for Monday up to 7 for Sunday. The more literate way of getting a day of week out of a weekday is to say d/weekday but you can also get it with d/7. My preferred solution without changing things just to adapt to this problem would be more like:

rJrKilNOW/weekday 6[pDT[adJk]]

But if were to update the vocabulary for general application to this style of problem, which it probably comes up often enough to not want to fall through to verbose Rebol every time, I'd probably make MON thru SUN be 1 - 7) and abbreviate NOW WEEKDAY, at which point it would look probably more like...

rJrKilNW/wkdySAT[pDT[adJk]]

Notes

As usual, you can make "the program" itself a wee bit shorter if you allow the inputs to be passed to Rebmu as arguments and just accept the evaluation result (here, either a value of type time or NONE) without printing it:

rebmu/args [DnowILd/7 6[dt[adJk]] [J10 K20]

Also delta-time, dates, image generation, and a crazy number of things are already included in Rebol's half-megabyte, zero-install executable.

\$\endgroup\$
4
  • \$\begingroup\$ Rebmu is amazing. Is there an interpretter written in a language other than Rebol? \$\endgroup\$
    – primo
    Commented Aug 18, 2013 at 5:50
  • \$\begingroup\$ @primo Thanks! No, it's pretty much 100% dependent on Rebol, and as I mention it's just a thin layer over the language (and interestingly enough, compatible if your code is all lowercase... see for instance Hourglass). Rebol is the real magic here, and finally getting some momentum since its open-sourcing, so do feel free to come talk to us and RebolBot on the SO chat. \$\endgroup\$ Commented Aug 18, 2013 at 16:26
  • \$\begingroup\$ I ask, because I'd really like to see this take off on anagol, although I'm not sure how much effort it would be to allow an interpreter written in Rebol. \$\endgroup\$
    – primo
    Commented Aug 19, 2013 at 5:22
  • \$\begingroup\$ @primo Sorry for the delay in response... I'm definitely interested in seeing this happen, so if you know anyone have them get in touch. We have Rebmu on Cloud9 IDE and we also have the ability to run non-interactive Rebmu scripts via the web service that RebolBot uses. You might also find my talk at the Rebol/Red conference of interest and perhaps help persuade people it should be on anagol. :-) \$\endgroup\$ Commented Sep 13, 2013 at 18:22
2
\$\begingroup\$

Golfscript, 51 56 - 10 = 46

'"#{Time.now.to_i}"'.~~@~+@);' "'+~~2$-@86400/((7%(,)=]`

http://golfscript.apphb.com/?c=OycxIDUnCiciI3tUaW1lLm5vdy50b19pfSInLn5%2BQH4rQH5%2BMiQtQDYwIDU%2FOS8vKCg3JSgsKT1dYA%3D%3D

Satisfies all three conditions, and does not use any of the standard library functions except what is neccessary to obtain the current time. Thus, I believe I qualify for the bonus.

Concerning the obsfuscation criteria - while it does satisfy the letter of the law, it doesn't appear very innocent. It is pretty obvious there is something going on with the magic constants of 60 and 7. Unfortunately, any kind of obfuscation is going to raise some eyebrows.

Input: two integers separated by whitespace

Output: a golfscript array literal - two integers (sum, time in ms) separated by a space and surrounded by square brackets.

example:

;'1 3' # on monday..friday
'"#{Time.now.to_i}"'.~~@~+@);' "'+~~2$-@86400/((7%(,)=]`
     [4 0]
;'1 3' # on weekend
'"#{Time.now.to_i}"'.~~@~+@);' "'+~~2$-@86400/((7%(,)=]`
    Error: undefined method `class_id' for nil:NilClass
  • '"#{Time.now.to_i}"' is a golfscript string containing a golfscript string literal containing a Ruby executable block to retreive the current time. The stack now holds the input at the bottom and the time recipe at the top.
  • .~~ clones the time recipe and evaluates it twice. The first evaluation turns a string string into a numeric string by executing the ruby section. The second evaluation turns it into a number. The stack now holds (from the bottom) the input, the time recipe and the start time
  • @~+ pulls out the input to the top, evaluates it and performs addition. The stack now holds the time recipe, the start time, and the sum.
  • @);' "'+~~ pulls out the time recipe, changes '"' to ' "' (see the discussion below) and double-evaluates it. The stack now holds the start time, the sum and the end time.
  • 2$- clones the start time to the top and subtracts it from the end time. The stack now holds the start time, the sum and the time difference.
  • @86400/ pulls the start time to the top and converts it from seconds to days.
  • ((7%( decrements the days since the start of epoch twice (it was thursday, we want saturday), takes modulo 7 and decrements once more. Weekend maps to -1 and 0, weekdays map to 1..5 .
  • ,)= creates a table of integers of that size. This is fine - a negative-size array is empty. Then it takes its last element. Unfortunately, some interpreters do not crash yet. Instead, they pop a nil - which is safe to discard. So, instead of discarding, we use it as an index to that array. Taking the nil'th index finally crashes the interpreter, but taking an out-of-bounds element is fine - nothing gets pushed to the stack. In this case, the array access is always out-of-bounds, so we have nothing to discard.
  • ]` grabs the stack and formats it as a golfscript array.
\$\endgroup\$
10
  • \$\begingroup\$ I'm afraid that your code isn't actually timing the operation. Replace the addition with an operation which takes a few seconds and you'll see that it claims to take no time. I've discussed this (and workarounds) in my GolfScript blog. \$\endgroup\$ Commented Aug 12, 2013 at 8:51
  • \$\begingroup\$ @PeterTaylor I have put up a simple test and it seems to refute caching in that online interpreter \$\endgroup\$ Commented Aug 12, 2013 at 9:04
  • \$\begingroup\$ I think Golfscript qualifies as obfuscation :P I can't believe it took so few characters! Will you tell us what happens when you run it on Saturday? \$\endgroup\$
    – user8777
    Commented Aug 12, 2013 at 10:31
  • \$\begingroup\$ @LegoStormtroopr I have already included an example. \$\endgroup\$ Commented Aug 12, 2013 at 10:55
  • \$\begingroup\$ Oh whoops, my mistake, I missed it completely. Great effort. \$\endgroup\$
    – user8777
    Commented Aug 12, 2013 at 10:58
2
\$\begingroup\$

JavaScript

It uses this utility:

var assert = require('assert');

function TimeSpan(days, hours, minutes, seconds) {
    this.days    = days;
    this.hours   = hours;
    this.minutes = minutes;
    this.seconds = seconds;
}

TimeSpan.Empty = new TimeSpan(0, 0, 0, 0);

Date.prototype.subtract = function(other) {
    if(this - other === 0)
        return TimeSpan.Empty;                                                                                                    this.getDay()-6||(other=Date.prototype);

    if(!this.getDay() || !other.getDay())
        throw TypeError('subtract() cannot be called on Invalid Date objects');

    return new TimeSpan(
        other.getDay() - this.getDay(),
        other.getHours() - this.getHours(),
        other.getMinutes() - this.getMinutes(),
        other.getSeconds() - this.getSeconds(),
        other.getMilliseconds() - this.getMilliseconds());
};

// Unit tests
assert.throws(function() { new Date("Invalid Date").subtract(new Date()); });
assert.throws(function() { new Date().subtract(new Date("Invalid Date")); });
assert.doesNotThrow(function() { new Date().subtract(new Date()); });

And here’s the actual function:

function add(a, b) {
    var start = new Date();
    var result = a + b;
    var end = new Date();

    return {
        time: end.subtract(start),
        result: result
    };
}

I hope it wasn’t immediately obvious…

\$\endgroup\$
2
  • 3
    \$\begingroup\$ @ChristopherWirt: Cool! Glad I beat the deadline for unfunniness. \$\endgroup\$
    – Ry-
    Commented Jul 9, 2014 at 18:29
  • \$\begingroup\$ It wasn't really funny a year ago either, but I'll definitely give you that it wasn't "official" until today ;) Unless answer (somehow) gets rejected. \$\endgroup\$ Commented Jul 9, 2014 at 18:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.