Hacker News new | past | comments | ask | show | jobs | submit login

One of my favorite things to do with these neat little games is to build something that plays them for me by just pasting stuff into the browser JS console.

https://pastebin.com/aTYuaNVS

At a score of 1,619 the ball is moving so fast it no longer works! I switched to a new tab (hoping that the event loop would be sent to the background/context switch/whatever) and ta-da - it misclicked. High score of 1,637.




You beat me to it, haha, This is what I just did:

function intersectRect(rectA, rectB) { return !( rectB.left >= rectA.right || rectB.right <= rectA.left || rectB.top >= rectA.bottom || rectB.bottom <= rectA.top ); }

const arc = document.getElementById("arc"); const ball = document.getElementById("ball");

setInterval(() => { if (intersectRect(arc.getBoundingClientRect(), ball.getBoundingClientRect())) { window.dispatchEvent(new KeyboardEvent('keypress', { keyCode: 32, })); } }, 10);

My code seems to go on forever, closed the tab after it reached 60K


Oh neat! You did the Harder version and didn't use the game's own code to check it. I find that with JS games it's better to imitate the game's exact logic and call it's functions to make sure the state is working/updates correctly.

Of course, for how delightfully simple this one is, your approach is definitely faster/better!


Definitely seems like alfon's solution is faster/better, as it's more accurate when the game speeds up. However, it's also more resource intensive! getBoundingClientRect (used to at least, long time I go I did browser performance stuff) forces a new layout calculation each time it's called, which is one of the most expensive things you can do in the DOM, and can lead to jank in the website. Some more information here: https://developers.google.com/web/fundamentals/performance/r...

Just adding this information for the ones who don't know and like to know more about browser performance :)


It is a bit of a slippery slope, because at some point, you could just do "GameApp.AddScore(10000)" which is clearly not playing the game. The line of what's "fair" and what's not isn't too clear. I do think staying out of the game code is actually a fairly good line though.

EDIT: Looked down thread and basically saw a bunch of examples of just that!


I believe that getBoundingClientRect does not force a layout calculation by itself, it only forces queued recalculations to happen synchronously.

So calling it 100 times in a loop should be fast, but calling it 100 times in a loot that also updates the DOM should be cripplingly slow.


Thanks for the note!


What the hell is happening past the point of 2k where the ball remains in the centre? Is it all happening too fast for my tiny brain to comprehend?


This overwrites the games internal `arc` variable so the arc no longer updates, hence the forever-ness.


Here's my solution:

    loopTapApp.score = Number.MAX_SAFE_INTEGER;


high score!


Not anymore

loopTapApp.score = Infinity


loopTapApp.score = Infinity^Infinity


You want loopTapApp.score = Infinity*Infinity, yours is 0 because ^ is XOR na anything XORed with itself is zero


This effectively turns this game into a spinning animation that appears to get increasingly frustrated that whatever is being loaded hasn't completed yet


Correct.. what it is loading, is effectively your score though. Or rather, measuring it, which takes some time? No idea, this is nonsense:)


Thank you!

I didn't peek and ended up with the same solution as you, so for an extra bit of fun I tried to golf it to be as short as possible. There's probably room for much improvement: (94 chars)

setInterval("l=loopTapApp;b=l.getBallAngle();a=l.arc;b+6>a[0]&b-6<a[1]&&l.tap(new Event(1))")


Nice! Managed to shave off a couple of bytes:

  setInterval("l=loopTapApp;b=l.getBallAngle();[a,c]=l.arc;b+6>a&b-6<c&&l.tap(new Event(1))")


This entire comment thread is hilarious


Strangely enough this shorter version reads and clicks better into my tiny brain


This is neat.

Also, in retrospect, I probably should have read the code before pasting it into my console.


Code run in the console has the same restrictions as code on the page it is for so it's not really any riskier than clicking the post link in this case. For sites you have (or will have) a presence on (bank, HN, email, etc) it's a very risky idea though.


Most definitely :D


Pasting here in case the pastebin disappears:

  function autoPlay() {
    const fakeClick = {
        preventDefault: function() {}, 
        stopPropagation: function() {}
    }   
    const ballAngle = loopTapApp.getBallAngle();
    if (ballAngle + 6 > loopTapApp.arc[0] && ballAngle - 6 < loopTapApp.arc[1]) {
        loopTapApp.tap(fakeClick)
    }   
  }
   
  const autoPlayer = setInterval(autoPlay, 10)


It's not exactly playing the game, but this was my approach:

    setInterval(() => {
     loopTapApp.arc = [ -Infinity, Infinity ]
     loopTapApp.tap({ preventDefault: () => {}, stopPropagation: () => {} })
    })


This is just "console.log("You Won!");" with extra steps... /s


Isn’t everything though? “Finally, the box of blinking lights is showing the pattern of lights I want it to!”


1,665 and the dot is just sitting in the center where the play button goes.

Safari Version 15.2 (16612.3.6.1.8, 16612) macOS Big Sur 11.6.2 (20G314) iMac Pro 2017


Brilliant, thanks.

Are you usually able to do this when e.g. it's more of a SPA and you have to drill down more to get to the state of some deeply nested component?


I haven't really tried. Most of the time I do this and use the actual game functions for autoclicker games like e.g. Cookie Clicker. It makes progression a lot simpler and I get to see the "fun" aspects of the game (like the super weird late game stuff) without actually breaking the fundamental game code. I like operating within the game's own code boundaries.


Mine was this

    loopTapApp.startPlay();
    setInterval(() => {
      if(loopTapApp.getBallAngle() > loopTapApp.arc[0] && loopTapApp.getBallAngle() < loopTapApp.arc[1]) {
        loopTapApp.tap({preventDefault: ()=>{}, stopPropagation: ()=>{}});
      }
    }, 50);


I got 1,683 in Firefox on a new M1 Pro MacBook Pro with your code… I'm gonna try the next guy's in Safari now. How optimal can I get haha!


Late to the party, but I prefer the more manual version:

  loopTapApp.setArc=function(){this.arc=[0,359];}


that works. If there was a leaderboard, this thing will win for sure :)


this is the reason that most FOSS games (especially browser games in JS) don't really do well with a leaderboard. Still a neat trick to mess around with!


No requestAnimationFrame?


Basically the same in this case, as the setInterval is set with 10ms between firings, and requestAnimationFrame would (most likely, depending on computer/display) fire every ~16ms. It would be more efficient though, that's for sure, but most likely basically the same :)


sad. i got stuck in a loop at 1477. it just kept going round and round.


Mine gave up at 1683




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: