
Super Hexagon Bot - jsnell
http://crackedopenmind.com/portfolio/super-hexagon-bot/
======
undershirt
This is awesome. I used SimpleCV in Python to detect the walls, much like you
did. But I used it to transform the screen to make the platforms fall
vertically:

[https://github.com/shaunlebron/super-hexagon-
unwrapper](https://github.com/shaunlebron/super-hexagon-unwrapper)

~~~
daxelrod
An amazing concept, excellently executed. You just changed how I think about
this game.

~~~
undershirt
Thanks, I'm glad it changed your view of the game. My goal was to show this
beautiful isomorphism between the two representations.

------
nerdy
For anyone interested in alternate bot approaches:

While the author made this "pixel bot" to pair their Super Hexagon with
ambitions to learn OpenCV, pixel bots are almost always inferior to memory-
based bots. As mentioned elsewhere in these comments, code injection should
use caves and jumps, not overwrite existing code.

With a memory-based bot you often do not even need to write to the game's
memory. You can use the ReadProcessMemory API call for data gathering and
perform inputs with SendInput (emulate keyboard input with LLKHF_INJECTED set)
or PostMessage (no LLKHF_INJECTED, also works in backgrounded windows).

The disadvantage to memory bots is that they're often more complicated at
scale (beyond the point where a pixel bot would likely fail entirely),
particularly with games which are updated. In cases where a game client is
updated, signatures similar to virus definitions can be provided to find the
particular memory address of a sought value regardless of version. By scanning
the application's source code for a unique bytecode pattern known to contain
the target address, you can then extract the address and read the value. This
is commonly known as signature or pattern scanning.

There is another variant of bots for client/server programs where a "headless"
(no display) client can interact with the server via network communication
alone. Not as much fun to watch but also a very effective way of interacting
with games, though it does not apply to standalone clients like this one.

~~~
marcosmlopes
Interesting. Do you have any more resources about how these bots are made? ²

~~~
nerdy
I don't have any resources in particular but I've personally made them for
years. In general you read memory and take action (via keyboard input) based
upon what you read from memory.

For example in a game where you fish, you would wait until a fish is on hook
by watching the representative value in memory and pressing a key to catch a
fish when that value indicates you have a fish on-hook.

In Super Hexagon you would watch the values indicating where walls were
placed, which is likely an array of enumerable values indicating a shape (each
shape has at least one opening). So a 1 might indicate a wall only at north, a
3 might indicate every odd side of the hexagon is a wall which must be
avoided, etc.

Finding values is obviously easier when the value is displayed on-screen, like
ammo in first-person shooters. It takes some time to become familiar with
exploring memory like this and you certainly wouldn't want to write your own
memory scanning primitives to do it, start with a tool like Cheat Engine
([http://www.cheatengine.org/](http://www.cheatengine.org/)), ArtMoney
([http://www.artmoney.ru/](http://www.artmoney.ru/)), or one of the many other
memory editors available
([https://www.google.com/search?q=memory+editor](https://www.google.com/search?q=memory+editor)).

If you'd like more details please be specific about what you'd like explained!

~~~
marcosmlopes
Thank you!

------
epaga
Ever since my 8-year old son beat the game multiple times on level 6, I have
been working on getting there as well. The best I have made has been 19
seconds on level 6 - though I have beat the first five levels, level 6 is
truly insane.

Watching my son play is quite the experience. It seems my reflexes are not
what they once were. It's an amazing game.

I want to think that writing my own bot would count as beating the game, but I
doubt my son would say it counts. So, here's to the next few thousand attempts
at level 6. "Again!"

~~~
busterarm
I got pretty good at Super Hexagon and can beat all 6 levels, but on their
hard mode's I can't get very far on levels 5 & 6.

I think my level 1 record is somewhere near 10 minutes now.

~~~
barbs
What's this "hard mode" you speak of? As far as I know, there are only 6
levels, the hardest being "hexagonest" in hyper mode, which is the
"hardestestest" level. I'm playing it on PC via steam.

I've beaten that but I'm keen for a harder challenge!

~~~
runevault
I would assume by "hard mode" they meant the last 3 difficulties you unlock by
beating the first 3. And the challenge at that point is chasing even higher
times and doing leaderboard chasing (though good luck cracking the top 200 at
this point, my 250+ is only 317th last I looked).

------
baby
For anyone who hasn't tried this game, it's pretty awesome! I was one of the
top players on one of the level back then
([http://www.twitch.tv/david_u/c/1985844](http://www.twitch.tv/david_u/c/1985844)).

I guess OP could have just done pattern recognition since there are not so
many patterns in the end.

Also I'm impressed, here:
[https://www.youtube.com/watch?v=OyVcokAUj3E](https://www.youtube.com/watch?v=OyVcokAUj3E)
at 0:14 you can see that the screen is suddenly rotating. This is a super hard
moment to pass and I can see that as a very disturbing thing for a bot as
well.

------
byuu
(I initially posted this on the Reddit thread yesterday, but I thought I'd
repeat it here since there are many programmer types who might attempt this
here.)

From the article:

> Of course, because we replaced the function with our own, we have to
> actually swap the buffers by explicitly calling the original
> glutSwapBuffer() function. I did this by undoing the hook, calling the
> original function and hooking it again.

Background qualification: I do this sort of debug launcher + DLL injection
thing a lot. For one example with source, see my tool header magic (
[http://www.romhacking.net/utilities/796/](http://www.romhacking.net/utilities/796/)
)

As someone with experience, please take it from me: this is a really bad idea.
If you rewrite functions to call the originals, it becomes possible for
another thread to call that function in the middle of your rewrite, and end up
executing illegal instructions. Not only is this theoretically possible, it
routinely happens all the time. Even when you think for sure that your program
is not multi-threaded. Even something like hooking a Windows file size
function, you'll learn that the open file dialog on Windows Vista+ is
threaded, and will bomb out on you with alarming frequency.

The proper way to do this is to create "trampolines" instead. The idea is that
you copy the first few instructions from the original routine, and put them
somewhere else. And at the end, you jump back into the original function after
your patched jump. The address of where you put the original instructions is
your pointer to the "original function" that you can use if you want.

So basically, something like this:

    
    
        originalFunction:
          opcode1
          opcode2
          opcode3
    

Becomes:

    
    
        originalFunction:
          jmp detourFunction
          nop <padding>
        resumeAddress:
          opcode3
        
        trampolineFunction:
          opcode1
          opcode2
          jmp resumeAddress
        
        detourFunction:
          <do your function hooking magic here; modify arguments; whatever>
          call trampolineFunction <only if you want to>
          <do whatever you want with the results from the original function call>
    

Now, I know this sounds horrifyingly complicated: you probably think you'll
need a full-on x86/amd64 disassembler+assembler. And it's theoretically
possible to make a near-impossible function to trampoline. But keep in mind
that 99% of APIs are built in higher level languages, and as such, have very
consistent function prologues (usually saving the stack frame.) So in
practice, you can write trampoline installers using one or two "signatures"
and hook nearly every function you'd ever want to.

But if that seems too challenging, there is also a library called Detours (
[http://research.microsoft.com/en-
us/projects/detours/](http://research.microsoft.com/en-us/projects/detours/) )
that you could try instead. I didn't find it necessary for my own purposes.

~~~
MisterNegative
Minihook is a great minimalistic opensource alternative if you cant pay 10000$
for Detours. [http://www.codeproject.com/Articles/44326/MinHook-The-
Minima...](http://www.codeproject.com/Articles/44326/MinHook-The-Minimalistic-
x-x-API-Hooking-Libra)

~~~
byuu
Detours really costs $10,000??? Unbelievable. I hadn't even looked into it.
Thanks for the alternative suggestion!

~~~
mh-
$9,999.95, apparently..

[http://www.microsoftstore.com/store/msusa/en_US/pdp/Microsof...](http://www.microsoftstore.com/store/msusa/en_US/pdp/Microsoft-
Research-Detours-v3-Professional/productID.253663300)

------
seletz
Oh man, I __suck __so badly playing this game, but I absolutely love the sound
track:

[http://chipzel.co.uk/album/super-hexagon-
ep](http://chipzel.co.uk/album/super-hexagon-ep)

~~~
tra3
Fantastic, thanks!

I wonder, is there a name for this genre?

~~~
striking
Chiptune

------
algorias
Hmm, I'm a bit surprised that some sort of ad-hoc AI is used, instead of
extracting the topology of the level and running a pathfinding algorithm on
it.

Once you remove all the human-confusing effects, the levels are actually very
simple, being just 4-6 columns. Since the minimum thickness of obstacles is
quite high and they are aligned with each other, you could even represent the
level as a graph, and run your pathfinding without having to manage the
geometry explicitly.

But then again, I'm the guy who thought about implementing a bot when the game
came out, instead of actually doing it.

~~~
eterm
Yeah much of the game is based on human perception. All the rotation moves
both level _and_ human, the walls don't ever rotate relative to the player.

------
dcre
I'd love to see the code.

I attempted the same thing[1] but between the fact that I had no idea what I
was doing and having to screencap every frame (instead of hooking directly
into the game's buffer), it didn't work too well. I think at best it tended to
last about 10 seconds on level 1.

[1] [https://github.com/david-crespo/py-super-
hexagon](https://github.com/david-crespo/py-super-hexagon)

------
StavrosK
Not having managed to get past 30 sec on level 6, I applaud this bot. Using
DLL injection was a very good idea too, but I wish the algorithm could play
the post-finish level for a bit longer.

