ReturnTrue spoilers

2016-08-20

This month started with kind of a bang. For JS golfers, anyways. Somebody posted a bunch of JS golfing puzzles and decent interface to start golfing down some JS problems. These aren't at the scale of JS1k, instead I think their background were more in terms of infosec and obscure things, showing that certain types of protection may not suffice. Especially in light of ES6. Such a game changer, as the challenge proved.

I think by now most of the players that want to will have seen the challenge and have participated so I don't feel too bad about posting the spoilers. The owner of the site asked me to postpone posting this post for a bit and so I have. There's various Reddit threads (etc) already floating around, I think it's good to have a resource that actually properly explains what the wtfjs is going on. And I can help :)

The puzzles are designed by Erling Ellingsen and can be found over at https://alf.nu/ReturnTrue so go ahead and give it a spin if you haven't already before reading the solutions here.

As it stands I believe still nobody has been able to solve the last one, "random 4". The puzzle is supposed to be solveable in line with how the others are solved, so no cheating.

Since I still want to try and give you an opportunity to skip through certain spoilers I'm going to try and create lots of whitespace between solutions and a jump table.

I'm okay at golfing but not the best. The solutions presented here are not all my own. And not all are the best, but some people (of shorter solutions) just can't be reached and some solutions are fake. Cheated in the sense that they hacked the submitter to allow a bogus score. Most of the solutions here are actually the shortest :)

Jump table



id
reflexive
transitive
counter
peano
array
instance
proto1
undef
symmetric
ouroborobj
truth
wat
evil1
evil2
random1
random2
random3
random4
conclusion

Whitespace now, scroll (or click) down for the first puzzle.




































































id


The simplest puzzle of all. If you can't do this one, turn back now ;)

Code:
function id(x) {
return x;
}

The solution is to pass on the actual value true, so 1 will not pass. The smallest way of getting this value is not the keyword but instead using !.

Code:
id(!0)

This will always return a boolean and in the case of 0 that boolean will be true.


Jump to reflexive
Back to jump table

































































Reflexive


Code:
function reflexive(x) {
return x != x;
}

This puzzle demonstrates a common wtfjs moment for people new to JS, especially those coming from other languages. While there may be longer answers possible, the "obvious" shortest answer is the one primitive value that is never equal to itself.

Code:
reflexive(NaN)

Actually I think this is the only solution. The weak comparison algorithm will first check whether two values share the same reference (even if primitive). If they do they will be equal. IIRC NaN is pretty much the only exception to this rule.


Jump to transitive
Back to jump table



































































Transitive


Code:
function transitive(x,y,z) {
return x && x == y && y == z && x != z;
}

This may be the first head scratcher for some and frustrating one for others. It was quite obvious to me what was being exposed here; I've explained the coercion rules a while back, even made a "pretty" tool for it. To be honest I gave up trying a few values and later on had Reddit spoil it for me. The main gist is to use an empty array and have it compare to something falsy.

Code:
transitive([], 0, [])

In JS, coercing comparisons with primitives are converted to equal types, in steps. In this case the code will first do [] == 0 and 0 == []. In both cases the array is first converted to a string. This calls .join(). On an empty array that results in an empty string. The empty string is converted to a number which results in 0. That ends up doing 0 == 0 which obviously is true. So the last check is [] == []. The rules explicitly state that two objects will always and only be compared by their reference, coercion or not. So two empty arrays can never compare equal.

Note that an extra catch here is the first condition of the function that checks whether the first argument is truthy. You may be tempted to think that the empty array will be converted to falsy, but it is not (![] === false). This is why the shorter 0,[],0 won't work and similarly [],0,0 won't work because the thing hinges on comparing two arrays to each other. You can also throw in '0' or false (etc).

Note that null and undefined actually wouldn't work because nothing compares equal to them except null and undefined.


Jump to counter
Back to jump table




































































Counter


Code:
function counter(f) {
var a = f(), b = f();
return a() == 1 && a() == 2 && a() == 3
&& b() == 1 && b() == 2;
}

Ah, the first more interesting one. It may take a few moments to let the puzzle sink in but it's not asking for the impossible here. I can only give you the 11 char answer but don't mind it if somebody spoils the 10 and 9 char answer (I've tried to reach out but no luck). This is the first puzzle where we (probably ;) need to golf a little.

The puzzle asks for a function. Your function should return a function when called, twice. The first returned function should return the values 1, 2, 3 when called successively. The second only 1, 2.

The simple solution is to create a function that creates a function and does some manual accounting to return the proper values.

Code:
counter((x = 0, function(){
return function(){
return (++x % 4) + 1;
};
}))

This is where we can introduce the first bits of golfing. First of all, most (up-to-date) browsers support the es6 "arrow" function syntax:

Code:
counter((x=0,_=>_=>(++x%4)+1))

And since we're golfing; the x is used inside a function so it doesn't need to be initialized immediately. That means we can rearrange the order of the params and make use of the fact that the second parameter is unused:

Code:
counter(_=>_=>(++x%4)+1, x=0)

In case you're confused; the underscore can be any identifier but we can't omit it entirely. We use the underscore to signify that it's unused.

This is much shorter. The first call will return the inner function. The call will also initialize an implicit global x to zero. The inner function will increase the x and mod it to return 1 2 3 1 2 3 .... Of course it doesn't matter which function (a or b) actually does the incrementing.

The next step in this is to realize that the inner function will have a closure on params of the outer function. Furthermore ES6 supports default parameter value initialization. So we could do:

Code:
counter((x=0)=>_=>(++x%4)+1)

Unfortunately this will require the parenthesis and the result will be of equal length.

The approach is not wasted, though, since this creates one closure PER FUNCTION. So a AND b will both have their own version of x now, both starting at zero, both not affecting the value of the other. This means we can drop the mod:

Code:
counter((x=0)=>_=>x+++1)

And since we don't need to wrap-around, we can start at 1 and eliminate the trailing addition:

Code:
counter((x=1)=>_=>x++)

This looks pretty optimal, but there is still room for improvement. There is a bitwise trick I once saw Jed Schmidt call the "Guerilla operator" (some jsconf.us talk, 2011? I can't quickly find it). Doing -~x will increment x and reversing the unaries will do the reverse; ~-x decrements the value. The important property, at least in this context, for us is the fact that the "bitwise not" (~x) will convert an undefined to zero! This removes our NaN that other similar solutions get. Additionally we can, again, declare the variable as a closure of the outer function. This leads to:

Code:
counter(x=>_=>x=-~x)

Pretty bad-ass. While I knew about the trick, using it here was spoiled to me in a comment on the site before I could reach it myself. So be it.

This isn't the end of it. I tried to reach out to Qantas94Heavy, who at the time of writing shared the leading (real) solution len with 9 characters, for a shorter answer but I couldn't reach him.

Edit: Karl Cheng (Qantas94Heavy) followed up with his 9 solution which since then has been disallowed;

Code:
counter(_=>prompt)

I thought it was a pretty great solution, even if "breaks" the JS1k spirit of "no-external input".



Jump to peano
Back to jump table




































































Peano


Code:
function peano(x) {
return (x++ !== x) && (x++ === x);
}

I know Peano from logic courses in philosophy. IIRC he came up with a proof for a mathematical model that only used the numbers zero and one (lmgtfy... Ok, or something like that). I know he did a lot more but that's what I remember him for :)

The puzzle asks for, seemingly, a number that's not equal to itself after incrementing it that's also equal to itself after incrementing i... hold up.

I think the clue here is not that difficult to see to medior scripters, though advanced scripters can devise clever alternative hacks, which will end up at the bottom of the solutions in term of golf. They might be tempted to think of the wrong reasons, though.

The main clue is that there's a number that remains the same after incrementing it. In JS that's only true for NaN and Infinity. Since NaN is actually not equal to itself, we must be talking about a number that's one or two below the number representing Infinity. However, you can't really do Infinity-1 so that can't be it.

A lesser known fact is that there are "unsafe" large integers in JS. It's due to the way doubles are encoded in their spec. Some internal representations will represent NaN or Infinity (multiples, actually, though you couldn't tell one from another from within JS). The last "safe integer" is the exact value Number.MAX_SAFE_INTEGER that was introduced in ES6, which is equal to Math.pow(2, 53) - 1. That's what we'll abuse here:

Code:
peano(Number.MAX_SAFE_INTEGER)

Why did that name have to be so long, though. Can't we do better? Well, obviously;

Code:
peano(Math.pow(2, 53) - 1)

Which works because Math.pow(2,53) == Math.pow(2,53)+1 (you can test this yourself). It is not equal to Infinity, but that's not relevant to the puzzle.

So how do we go smaller? The literal for 2^53 is 9007199254740991, exactly the same length as above, or 0x1fffffffffffff, again exactly the same length. Hrmmmm, coincidence? I THINK NOT. Must be a conspiracy!

Recently somebody on twitter, probably Mathias, mentioned that the new ES7 power-of operator was now available in Chrome (yes yes, and Opera). After seeing that the best score at the time was that short I realized the new operator must've been what was used:

Code:
peano(2**53-1)

Quickly after that shorter answers (or well, their lengths) appeared.

I didn't bother to investigate that further as I was pretty sure this was just a variation of the same which ends in a number with the same shadowing property but where the power-of did not require -1.

Surely that was the case as Martin Kleppe spoiled to me:

Code:
peano(9**17)

A bit anti-climactic :)


Jump to array
Back to jump table




































































Array


Code:
function array(x,y) {
return Array.isArray(x) && !(x instanceof Array) &&
!Array.isArray(y) && (y instanceof Array);
}

This is a pretty good puzzle. I liked the anti-symmetry of it. For this it helps to know how exactly instanceof works, and how the ES6 Array.isArray works. Although you can always cheat your way through that one ;)

Code:
array(x, y, Array.isArray=_=>1)

This way you only have to solve the instanceof problem which is easier to grasp in the classical sense (ok, some irony there).

In JS the obj instanceof cls operator works by checking whether the Object.getPrototypeOf(obj) of the left side is equal to cls.prototype of the right value.

While prototype was a little dodgy to directly manipulate in ES5, it is easy to do so in ES6 (even though your perf will vary tank). You can create an object with arbitrary prototype link through Object.create(proto), so our initial solution is:

Code:
array({}, Object.create(Array.prototype), Array.isArray=_=>x--, x=1)

The first call to isArray will return 1, the second 0. At 58 chars I think we are done, right? Well.. almost ;)

We can tackle both conditions but first we need to know a little more about the environment.

The static Array.isArray function will return true if an object is actually an array, not just looks like it. It doesn't care about anything else but the fact "was this initially created as a true array?", a fact that is tracked through an internal meta property (I don't think you can access or even manipulate) so this function can tell you about it. It will not do duck typing so the TypedArray buffer types are not arrays according to this function. Sadly. This does make it a little tricky to fool the function if we can't fake the array.

The instanceof one is simpler since instanceof will ONLY check the prototype link. It doesn't care how what when why. If the objects are the same, it returns true and otherwise false.

Knowing this and some of the stuff before we can at least create an object that passes the instanceof test while failing isArray. We use Object.create(Array.prototype) for that.

The other hurdle is trickier without clobbering the function. It requires some spec knowledge; there is one standard default object that is an array but not instanceof an array: the Array.prototype itself!

This leads to:

Code:
array(Array.prototype,Object.create([]))

Okay, 33, that looks good? NO! BAD GOLFER!

You probably know the next step; due to legacy and slow spec progress and whatever browsers have a special property to access and even manipulate the "hidden" prototype link. It's time for the DUNDERPROTO: __proto__. To reiterate, obj.__proto__ should refer to the .prototype object of the function that created it through new. In other words: (new Date()).__proto__ === Date.prototype and (new Foo()).__proto__ === Foo.prototoype etc. That's precisely what instanceof checks :)

As you probably already realized two examples ago, you this also works on arrays. And [].__proto__ is shorter than Array.prototype so, when golfing, there's no need not to use this shortcut.

Code:
array([].__proto__,Object.create([]))

Hey, that 30 char solution still has some words I recognize. We can remove those, surely? Why, yes! The dunderproto also works in object literals.

Code:
array([].__proto__,{__proto__:[]})

Which lands us at 27. Where I got stuck.

Well almost stuck. I had a 26 but it wouldn't work and I think that's a bug. ES6 supports dynamic object literal property names like x="foo"; y={[x]:5}; // {foo:5}. This would open the door to caching the "__proto__" string. But it doesn't work since [][p='__proto__'],{[p]:[]} doesn't seem to work in this case. I did not get further down from 26 (or 27).

Steven Wittens revealed his 23 to me:

Code:
array(0,[Array.isArray=x=>!x])

This is back to the butchering hack we started with. It overrides the isArray check such that nearly any falsy value will pass the first set of checks. The actual array will then pass the instanceof check and be "truthy" such that the overridden function returns false, passing the tests. It also uses the fact that the contents of the array is completely unused to save a byte. Nice!

I was definitely stuck in a __proto__ frame of mind myself.

(Here is another 30 I came up with:)

Code:
[][r='__proto__'],y={},y[r]=[]

Pfssj, 30, pah! But sometimes bad solutions can open new avenues to finding new good solutions :) This one didn't, though.


Jump to instance
Back to jump table




































































Instance


Code:
function instance(x,y) {
return x instanceof y && y instanceof x && x !== y;
}

Heh, this is a fun one. I'm surprised that at the time of writing I'm still only one of three people to figure this out. In all fairness it was more of a trial and error thing and a TIL when it worked. May actually be bugged, but it makes sense in a way. I didn't read up on this factoid.

Unfortunately you don't get to see old solutions and I'm not even sure what my first solution was. Probably this one:

Code:
instance(Function,Object)

Every object is an instance of Object (and functions are objects too) and Object is a function so it's an instance of Function. However, the shortest solution here seems to be:

Code:
instance(Object, Proxy)

This works because every object is, by default, an instance of Object (many objects have a few prototype steps in between but instanceof doesn't care). Actually hold up, so I lied omitted a small fact about instanceof before. The instanceof doesn't just check obj.__proto__ === cls.prototype. It checks whether this is true for the entire prototype chain up until the object that has null for a prototype. So looking at a function, for example. It will first do f.__proto__ === Function.prototype. If that fails it will do f.__proto__ === Function.prototype.__proto__ which is actually f.__proto__ === Object.prototype, after which it will fizzle out because Object doesn't have a parent by default. So there's a little more to instanceof than I initially led on ;)

Anyways, it seems Proxy is specced such that every object is an instance of that as well. That kind of makes sense in the spirit of what Proxy does although I think it's an explicit exception rather than part of the prototype chain. In 10 years we'll probably cry about this exception. In 20 we'll laugh again.

I'm a little surprised this few people figured that last step out, especially since some of the other puzzles (may) require Proxy. So it's not like you weren't activated for it.


Jump to proto1
Back to jump table




































































Proto1


Code:
function proto1(x) {
return x && !("__proto__" in x);
}

I don't think there's a proto2. This puzzle revolves around every object having a prototype link. So you explicitly need to get an object that has no such link, anyways. And it has to be an object since primitives (like strings and numbers) will throw an error when used as the right hand side of in. And of course boxed versions (new Number(5)) are still objects with a proto link.

ES5 gave us a simple mechanic of defining an object without proto:

Code:
proto1(Object.create(null))

It may not be undefined because it must be an object and null is the value for an object type that has no value. Creating an object like that will make the object have no __proto__ property. But we can improve on that by using similar knowledge of before:

Code:
proto1({__proto__:null})

Even though I came up with this myself, it was more of a trial and error and TIL. But I guess a property that null returns false for the in operator.

There appears to be a shorter hack possible in Edge but I don't know what it is and I don't know who that person is but if you know, let me know :)


Jump to undef
Back to jump table




































































undef


Code:
function undef(x) {
return !{ undefined: { undefined: 1 } }[typeof x][x];
}

This one had me puzzled for a while. What the hell is typeof undefined but not undefined? I did eventually remember what did this though it's a bit of an arcane piece of wisdom.

First of all, the way to read this code can be a little daunting. !{ undefined: { undefined: 1 } }[typeof x][x]; can be disected to an object { undefined: { undefined: 1 } }. Then first you access the property with value typeof x on this object, returning { undefined: 1 }. The whole thing is inverted so our goal is to pass on a value x that does not evaluate to undefined (otherwise we get !1 which is not true).

An interesting fact that may help to get a solution here is that (dynamic) property names are always converted to a string. So you can always try to use the toString hacks.

I'm not even sure if I solved this with anything but "the right" answer. I can't think of anything from the top of my head. So let's just skip to the answer:

Code:
undef(document.all)

Whattt?? Yeah, document.all is an artifact from the early IE dominance days. Sites would do if (document.all) ... and Opera would also have this to be detected as an IE browser and the whole landscape was in a clusterf... So in the end they solved it by making document.all evaluate to falsy, to be typeof undefined, to not be equal to undefined, to be callable, to be an array (ok, dom collection). It is the purest evil on the web. As we'll see later.

I guess an alternative to solving this is to set a relevant property on Object.prototype.

Code:
undef(1, Object.prototype.number = {})
// or the more succint
undef(1, {}.__proto__.number = {})

Though that's clearly longer :)


Jump to symmetric
Back to jump table




































































Symmetric


Code:
function symmetric(x,y) {
return x == y && y != x;
}

This one had me puzzled for a long time. Even when David confirmed it was related to coercion, which in hindsight is true yet quite irrelevant, it took me solving another puzzle (and way too much time) before realizing the straightforward solution to this one.

It is, again, a spec thing. Firstly; coercion, we meet again. If we use a primitive with an object in a weak comparison, the object will be converted to the primitive type in steps. In this case we pass on 1 as the second parameter so the comparison will convert an object to a number.

The interesting detail is to know that when objects are converted to a primitive there are two methods they check. Which method exactly depends on the target primitive when translating, most of the time it is string. For a string, the method to call is toString. For numbers the method is valueOf. If one is absent the other is checked, anyways.

That coercion fact is what we use here. We pass on an object with a custom valueOf such that the result is never the same. Since it'll get no arguments we need to use a global to toggle. Luckily we needed to pass on a second value, anyways, so we can use that field and initialize a var at the same time:

Code:
symmetric({valueOf:_=>x++},x=0)

The first evaluation of the object will result in returning x++, which returns zero which equals the value passed on for y. The second evaluation will return one, but y remains zero. That's why this works.


Jump to ouroborobj
Back to jump table




































































ouroborobj


Code:
function ouroborobj(x) {
return x in x;
}

I don't remember what I had at first. I can see what I ended up with and remember I realized that shortly after seeing the shortest solution length :)

There are various ways of solving this. The main thing to keep in mind is that in also works on array indexes.

Actually, another important fact is that property names in JS are always coerced to a string. The left hand side of in is considered a property name. Ergo, by transitivity, the left hand side of in is converted to a string.

As we remember from previous puzzles, arrays coerce to strings by calling .join() on them. This leads us to one beautiful solution:

Code:
ouroborobj([0])

The key becomes '0' which is in fact a property of the array because it contains one value.


Jump to truth
Back to jump table




































































Truth


Code:
function truth(x) {
return x.valueOf() && !x;
}

The !x part really stumped me for a while. Then my initial solution used document.all for it, once I was primed for it. We can override document.all.valueOf which makes this easy:

Code:
truth(d=document.all,d.valueOf=_=>1)

I went ahead and did this caching optimization for you. You're welcome.

However, this 29 char solution can be beaten by something completely unrelated and way more straightforward. Took me a while to see it myself but I did find it myself (fwiw :)

Code:
truth('',''.__proto__.valueOf=[])

So obvious in hindsight. The empty string is falsy, satisfying the second condition. The valueOf can be overridden explicitly and so it works.

This solution is 28, but there's also a 27. The step is fairly easy yet I couldn't see it myself. Luckily David spoiled it for me, there are more falsys that work this way and one is shorter :) So obvious in hindsight.

Code:
truth(0,(0).__proto__.valueOf=_=>1)

Wait this isn't shorter...? No, but this is:

Code:
truth(0,0..__proto__.valueOf=_=>1)

Which may require a bit of knowledge of the syntactic rules of JS. You need two dots (or the parens) there because JavaScript parses "greedy", meaning it will want to parse as much as possible for a single "token". A token is like a string or a number. Numbers in JS can have a trailing dot (5.). I mean, if you really wanted to (this would signify certain data types in other languages). So the parser must parse the a trailing dot if it finds one and assume it is part of the number. That's why 0..foo looks a little dodgy but works fine. It is parsed like (0.).foo. Alternatives are just adding the parenthesis ((0).foo) or whitespace (0 .foo). The whitespace version tends to trip up minifiers though.

Not all numbers can have this trailing dot. Hex numbers can't, numbers that already have a dot can't have another dot, numbers that have an e can't have a trailing dot. Seriously though, don't use the double dot notation in an actual project. I can think of very few reasons why you would outside of a golfing or quick repl context (I often do stuff like 45232..toString(2).length in a repl).


Jump to wat
Back to jump table



































































Wat


Code:
function wat(x) {
return x('hello') == 'world:)' && !x;
}

Haha, this one. It's funny. But once I was primed for the solution, it was fairly easy and a matter of golfing it down.

The horrible truth is that it heavily uses the monstrosity that is document.all. It is undefined, it is a function that acts like getElementById AND getElementByName, it is a dom collection (array-like but also as function calls by index) with all the elements, and did I mention it is undefined? So we need to set the id or name of some element to "hello" and explicitly clobber its toString method to return the string "world:)". Kay.

Code:
wat(document.all,document.body.id='hello',document.body.toString=_=>'world:)')
wat((d=document,h=d.body,h.id='hello',d.toString=_=>'world:)',d.all))
wat((d=document).all,h=d.body,h.id='hello',h.toString=_=>'world:)')
wat((d=document).all,d.body.id='hello',hello.toString=_=>'world:)')

Then I discovered you can also do document.all(0) or document.all[0]. Maybe it doesn't do the same, it doesn't matter much for length anyways, but this a quick way to get the html element. So putting that together:

Code:
wat(d=document.all,d(0).id='hello',d(0).toString=_=>'world:)')

This passes document.all as the main value. It caches it as well, calls it to get the html element. It sets the id and toString such that it will pass the test. And finally it evaluates to falsy.

A shorter version was golfed down by Steven:

Code:
wat([y]=document.all,y.id='hello',y.valueOf=_=>'world:)')

This 52 makes use of destructuring, which can be used as an expression and returns the original value. This trick also assigns the first element of document.all (which as we learned is the html element) to a temp variable. It then does and work the same as I did it before.

Edit: Karl Cheng (Qantas94Heavy) followed up with his 57 solution. It has been blocked since but I still thought it was a great idea:

Code:
wat(a=document.all,a[2].id='hello',a[2].valueOf=b=>prompt())

Which I believe could be reduced even further to 52 because a function is a function:
Code:
wat(a=document.all,a[2].id='hello',a[2].valueOf=prompt)

Though I didn't test this.

Combining that to Steven's solution would give us this 46 :)
Code:
wat([y]=document.all,y.id='hello',y.valueOf=prompt)

It's a little cheating with the external input, but still quite impressive :)



Jump to evil1
Back to jump table




































































Evil1


Code:
var eval = window.eval;
function evil1(x) {
return eval(x+'(x)') && !eval(x)(x);
}

This was a very quick puzzle for me. I started to type something and it just accepted my answer before I finished. Mkay. And it was the shorter than all the other answers for a while. It's still the shortest and I'm not sure what could beat it at this point. Of course you never know ;)

Code:
evil1(_=>0)

Feels a bit anti-climactic, no? So let's see why this works because I think the puzzle is pretty nifty. And we get another one just like it too :)

The first thing TIL was that arrow functions stringify to their original representation. At least Chrome doesn't normalize _=>0 to something like function(){ return 0; } but unless it's specced that way it will depend on browsers. And since throwing away the original source is an optimization step, especially on mobile, I don't think it's specced this way. Anyways, Chrome does stringify it like that at the moment, so stringifying an arrow function returns itself as a string. That helps.

The puzzle is eval(x+'(x)') && !eval(x)(x); so we can see that the first would end up doing eval('_=>0(x)'). That may look like a syntax error, but for a time it was syntactically legal for any value to have call parenthesis. I'm not sure whether ES6 fixed this, but browsers won't easily change their mind now. Perhaps in strict mode or module mode that won't be allowed but we are obviously not in those modes here :)

So the first eval returns a function whose body will throw when executed (probably some tautology like "0 is not a function", orly). The function will be truthy and so the test passes.

The second eval evals the stringified function. Essentially it's doing eval(_=>0) which it stringifies (I think, or executes as is?) and does eval('_=>0') which would return the function, in eval semantics. The function is then immediately called with an unused parameter: eval(...)(x) to (_=>0)(x) and returns 0. This is inverted to return true. The last x is just a red herring (or maybe you can use it in a different solution to this puzzle?).


Jump to evil2
Back to jump table




































































Evil2


Code:
var eval = window.eval;
function evil2(x) {
return eval('('+x+')(x)') && !eval(x)(x);
}

For me, this one was solved similarly to the first. I was typing a similar solution when it was promptly accepted. It still needed to be golfed down and I don't remember what I started with exactly, but this is my solution now:

Code:
evil2(_=>x=_=>0)

That was before I really understood what was going on, nice :)

The puzzle is again a two-step but this time slightly trickier because the first eval is wrapped in parens; eval('('+x+')(x)') && !eval(x)(x);.

If we tried the previous solution here, the first would end up doing eval('(_=>0)(x)'), returning 0, which is falsy, and fails the test. That means we must do something different. To make matters (slightly) worse, the next part does almost the same but expects a different solution. It's not exactly the same, though at this point that is irrelevant for us because "the damage has been done".

Since the eval here is a "direct eval", it has access to the local variables. That's what we're abusing here. My solution is a function whose body sets x to a new function that returns zero. Normally that x would be a global, but since it is stringified and put through a direct eval it will now target the local variable x. That means the next part will execute a different function in x, stringified or not, which simply returns zero.

To be explicit; eval('(_=>x=_=>0)(x)'), as a direct eval, will invoke the outer function and execute x=_=>0 on the local scope, clobbering the current value of x, which was our input, with the function _=>0. The second part does eval(_=>0)(x), which is then stringified or executed as is, either way returning a function which is immediately called (with itself but we ignore that) and returns a zero. Since !0 is true, we have a winner.

This solution is 9 chars. But there's also an 8 that David spoiled to me. This one kind of answers the "does eval stringify a function arg?" question as it's kind of vital to the solution:

Code:
evil2(_=>x,x=0)

Took me a minute to process but the clue here is that the first eval will explicitly stringify the function and run a "direct eval". This means the evalled code has access to the local scope x, which is that function and therefor truthy. Passing on x is irrelevant. The second eval does not stringify the function and so it uses the global x, which was initialized to zero in the input. Again, passing on x is ignored and it returns zero. Well done!

TIL about eval and function args; it simply returns the same function as is.


Jump to random1
Back to jump table



































































Random1


Code:
function random1(x) {
return Math.random() in x;
}

Ermahgerd the randoms. These looked a little daunting at first, some still do. The first one was pretty simple, though.

The Math.random function is called after you pass on the parameters so there's nothing stopping you from replacing it. That solution should be trivial by now.

Code:
random1({z:1},Math.random=_=>'z')

Obviously that works but obviously it won't be the shortest answer at 24.

As we saw earlier the index properties are also subject to the in operator, so we can simplify this to an array based solution:

Code:
random1([0],Math.random=_=>0)

That's 20, but we can do better.

Keep in mind the actual value of the array element is irrelevant. We can save two bytes by replacing the zero and by no longer needing an extra comma:

Code:
random1([Math.random=_=>0])

It's gonna be hard to get this 18 even shorter. You'd need a function that returns falsy in under 5 chars. Or some other creepy way to change Math.random.


Jump to random2
Back to jump table




































































Random2


Code:
var rand = Math.random();
function random2(x) {
return rand in x;
}

Step up! Some puzzles could be solved in a similar way, so you may already be primed for this. Only one best solution uses this approach so random2 could still be a little trouble for you. It requires ES6. Surprise surprise.

Code:
random2(new Proxy({},{has:_=>1}))

Oh that Proxy is going to spell so much trouble for JS. But for this puzzle it is the solution; the proxy can intercept many operations on the object and do something custom in a similar way of how ES5 setters and getters work. Please don't ever use this in prod. Seriously. Your collegues will thank you for it.

This works pretty straightforward otherwise; we set up a proxied object which intercepts in checks. When intercepted a custom function is invoked and in this case we return truthy for it regardless of the property being looked up. That way it doesn't matter what value Math.random() produced, the proxy will always tell the engine that the proxied object has that property. Hence passing the test.

This was a 24 but somebody seems to have a 19. Unfortunately it's very hard to determine the legitimacy since the website is pretty broken in terms of input validation (oh the irony). I don't think you can go shorter with proxies but maybe there's some other obscure way to achieve it. If I find out I'll put it up here.


Jump to random3
Back to jump table




































































Random3


Code:
var key = crypto.getRandomValues(new Uint32Array(4));
function random3(x) {
var d = 0;
for (var i=0; i<key.length; i++) {
d |= key[ i ] ^ x[ i ];
}
return d === 0;
}

I think this one had people (including myself!) stumped the most, next to "random 4" and after "wat". The problem with this puzzle is that it relies on a pretty obscure spec artifact, I'd even go as far as to call it a bug. And even knowing that it is a spec thing I think you'll be pressed to figure out what it is but hey, that's why you're here.

Actually Martin did figure this out with a few high level pointers. Very impressive.

Anyways. I did not know this, somebody told me the answer, so definitely TIL for me. My 39 score is also a bug. Somehow it somewhere accepted an answer (maybe random bug on mobile?). It since cannot reproduce (you get "undefined /* did not work this time */" as your last accepted answer). Don't know when it happened or why. Pretty sure I had no valid solution when it did so ignore my 39.

The problem lies in TypedArray, specifically how their length is specced as a getter. Apparently you can override their prototype and this is reflected in their children. This won't work on regular arrays, I tried :) Before you think you can simply override it, that's not exactly true.

Code:
random3(Uint32Array.prototype.length = 0)

Will NOT do the trick. You need to dig a little deeper into archaic JS methods for it to work;

Code:
random3(Object.defineProperty(Uint32Array.prototype, 'length', {value: 0}))

This uses a standard method to (very very) explicitly (re)define a length property on Uint32Array.prototype. The reason the one above doesn't work is that the property is a getter/setter. Setting a new value to it won't override the getter/setter. The setter is probably a black hole and the operation a noop. By explicitly redefinining the property with {value:0} the getter/setter is replaced by a regular "value" property which is then inherited by all the children, which previously would lookup the getter. Regular arrays also use a similar getter/setter (because .length is dynamic for them) but I guess it's not specced that way.

Kudos to those that actually figured this out. That's pretty obscure!

Karl Cheng (Qantas94Heavy) actually had a much simpler solution at 34:

Code:
Uint32Array.prototype.__proto__={}

Nice! :D


Jump to random4
Back to jump table




































































Random4


Code:
var rand = Math.random();
function random4(x) {
return rand === x;
}

Screw this one :)

As far as I know nobody really got this one yet. Only cheaters on the board (I've been told). Nobody's been able to find a solution that is in line with the other puzzles. I mean, you can hack it through devtools but that is not the solution. You can also predict the solution on some browsers. That'd require a pretty hefty solution though. The designer did say it's solveable through regular means, so I guess you'll have to keep trying :)

I'm going to chalk this one up to either very obscure, not in line with previous solutions, or a red herring. I'm interested in hearing a solution to it but I'm not sweating it myself.


Jump to conclusion
Back to jump table



































































Conclusion


I love puzzles like this. I was a little bummed to learn about this just when I was going camping for the weekend. These golfing matches don't work that well on mobile ;)

The puzzles were great. The interface sufficient, though I'd love to see a list of my prior attempts, and succint. And to golfers like myself this is just candy that wastes entire days.

Some of the puzzles require certain pieces of knowledge about JS, some deeper than others. I tend to love those kinds of details so for me this is great. I can understand if you don't really care about the nitty that much and that's fine too. Just means these puzzles are probably a lot harder for you to figure out. Throwing your hands in the air shouting "MEH" is totally acceptable :)

The interface allows for submitting your own puzzles. I hope this enticed some people to submit their own and that there will be a followup set of puzzles in this "contest". Erling did mention he's working on a "random5", goody.

For now I'd like to thank Erling Ellingsen (@steike) for putting the whole thing up. Great work :) I'd also like to thanks some golfers for giving me their answers for this writeup.

If you have a solution that is drastically different (or in any way better) than the ones listed here and would like it listed, just send it to me on twitter (@kuvos) and I'll see about adding it. No promises for worse solutions... Feel free to send me corrections as well!

As it goes with these contests, I hope you learned something. I know I did, which says something :)


Back to jump table