这个游戏是一个13 KiB的单个文件,可在Windows、Linux和浏览器上运行。
This game is a single 13 KiB file that runs on Windows, Linux and in the Browser

原始链接: https://iczelia.net/posts/snake-polyglot/

这个项目详细介绍了贪吃蛇游戏(小于16KB)的创建,该游戏设计为原生运行在Windows、Linux和Web浏览器上——所有这些都来自单个源文件。受到Justine Tunney的libc项目的启发,作者旨在实现跨平台兼容性,同时保持较小的二进制文件大小。 游戏具有标准的贪吃蛇游戏玩法,包括计分、关卡和不同的水果价值。它被实现三次:C语言用于Windows(使用WinAPI和压缩stub),C语言用于Linux(使用clang和X11,并使用lzma解压缩),以及JavaScript用于浏览器(HTML5 Canvas)。 这种多语言方法的关键在于巧妙地将每个实现打包在同一个文件中。每个平台的操作系统识别并执行其对应的代码,忽略其余部分作为良性数据。这是通过shell脚本、不寻常的PE头以及浏览器对初始垃圾数据的容忍来实现的,最终生成一个13.7KB的可执行文件。

一款新的单文件游戏,体积仅为13 KiB,因其跨平台兼容性而备受关注——可在Windows、Linux和网页浏览器(iczelia.net)上运行。然而,使其正常运行并不总是那么简单。 用户报告称,在Linux上需要`xz`软件包进行解压缩,而在Windows上,需要禁用数据执行保护(DEP)。一位用户最初在使用Mono尝试在Linux上启动文件时遇到问题,通过使用Bash明确运行文件解决了这个问题。 讨论集中在游戏使用`lzma`压缩以及潜在的更广泛兼容性替代方案上。评论员们也回忆起过去类似令人印象深刻的小尺寸游戏,例如*kkrieger*。有人要求提供浏览器版本链接,并称赞该游戏设计巧妙,强调即使在十年前,实现这样的壮举也是可行的。
相关文章

原文

Not that long ago I became aware of Justine Tunney’s cosmopolitan libc project. It’s a toolkit that allows you to compile C source code into a single binary that runs natively on multiple operating systems, including Windows, Linux, various flavours of BSD, even including booters.

Unfortunately, back then the project didn’t seem to support GUI interfaces and produces quite swollen binaries. Hence I decided to take a stab at a similar (simpler? harder? up to you to decide) challenge: create a video game (<16 KiB) that runs natively on Windows, Linux and in the Browser, all from a single source file.

The Game

It’s a pretty standard Snake game with the same rules and interface on all platforms. You control a snake that grows longer as it eats food, and the goal is to avoid running into walls. The snake is controlled using either the arrow keys or WASD keys. It can be terminated via ESC (if permissible by the platform), reset via R, and paused via P. Spacebar starts the game.

The game keeps track of your score. Each piece of food eaten increases your score by 10 points, except yellow fruit (which spawns with a 15% chance) that gives you 20 points. Fruit spawns at a fixed rate and despawns after a certain time if not eaten. The despawn timer is proportional to the speed of the snake at the time of spawning, which itself is proportional to the snake’s length.

Once ten fruit are eaten, the game proceeds to the next level, randomizing the walls’ layout. The maze is created as to ensure that there is always a path from the snake’s head to any piece of food. The initial placement of the snake is also randomized, but always in a position that has at least five empty tiles in the direction the snake is facing.

Download the game here (13,772 bytes).

The Polyglot

I implemented the game three times in total: once in C for the i686 Visual C platform using WinAPI, once in C for the x86_64 Linux platform using clang and X11, and once in JavaScript for the browser using HTML5 Canvas. Each implementation is around 3-5 KiB in size when compiled/minified.

The Windows implementation was produced using a compressing script that prepends a decompressing stub. This stub has a quite unusual PE header that has many freely controllable bytes after the MZ signature. This allows us to place a shell script there that skips over the remainder of the file, rendering the (valid) PE executable runnable on Windows while also making the entire file a valid shell script, that will do (thus far) nothing on Linux.

Because the PE file is so awkward, we rely on Windows’ apphelp mechanism. Without compatibility mode, executing for the first time will yield the message:

“The application was unable to start correctly (0xc0000005). Click OK to close the application.”

Which should disappear after re-running.

The Linux implementation was produced using a similar approach; we use lzma for decompression and a small shell dropper that extracts the compressed ELF64 binary and runs it, skipping over the head and the tail of the file.

The HTML version is also packed and abuses the fact that browsers will happily process all the benign garbage at the start of the file before reaching the actual HTML content. Then we make it invisible/unobtrusive through a bit of CSS magic.

Finally, we concatenate all three files together in such an order that each platform will pick the correct part of the file to execute. The final file is exactly 13,312 bytes in size.

Technical Details

联系我们 contact @ memedata.com