Underground 2 Revived
Play Need for Speed: Underground 2 (2004) in Chrome and Firefox with WebGPU graphics, Web Audio, up to 120 fps widescreen, controller support, free roam and Online races with friends. Fan project, not
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗▶ Demo: bengreff.github.io/polytopia-ai: watch the bot's games move by move (whole board shown) and see every self-play generation's results. The site updates itself after each new generation.
A neural network that plays The Battle of Polytopia in the World Championship format: 1v1, Might, Lakes, small 14×14 map, any of the 12 regular tribes on either side, with fog of war. Its rules engine is the game's own compiled code, driven headlessly and checked byte for byte against the real app. The network first learned from 7,732 human tournament games and now improves by self-play, one generation at a time.
Each line is 200 games against the game's hardest built-in bot (Crazy), on fixed maps, every map played twice with the seats swapped. The network plays greedily: no search, and it sees only what its own player would see.
| Policy | Win rate vs Crazy |
|---|---|
| The game's own AI playing our seat (the imitation teacher) | 10%* |
| Behaviour cloning of that AI (20k games) | 9%* |
| Fine-tuned on 7,732 human championship games (R7, "generation 0") | 94% (188/200) |
| Self-play, generation 7 | 98% (196/200); beats generation 0 in 58.5% of head-to-head games |
* Measured before the seat-assignment fix described below, so half of those games were mirror matches.
Details, intervals and paired significance tests are in
docs/design/research-log.md. Every experiment there is
pre-registered with its hypothesis and falsifier, and negative results are kept: three RL variants
that didn't help, winners-only imitation, a self-play run that diverged, and a seat-assignment bug
that made half of the bot evaluations mirror matches until it was found and fixed.
polyhost/, C++): loads the game's il2cpp library with no Unity and calls its
own game creation, map generator, move execution, legal-move generators and built-in AI.
py/model.py): a 5.9M-parameter transformer over the 196 map tiles plus a global
token, with:
py/train_bc.py);py/sp_loop.py, py/selfplay.py, py/train_rl.py):
py/eval_vs_bot.py, py/selfplay.py --match).Developed by Ben Greff, with Claude Code (Anthropic) as the coding agent.
Not included: the game's files (game/, gitignored; you need your own copy of the game) and the
downloaded replays. This is an unofficial research project, not affiliated with or endorsed by
Midjiwan AB. The Battle of Polytopia is a trademark of Midjiwan AB.
This project runs The Battle of Polytopia's own compiled rules code, with no Unity and no
reimplementation. The rules live in GameLogicAssembly, which ships inside the game as native
code (libil2cpp.so). polyhost loads that library, starts the il2cpp runtime, and calls the
game's own functions directly:
ClientBase.CreateSession's pass-and-play branch, rebuilt step for step, creates a match,
including map generation (MapGenerator).ActionManager.ExecuteCommand applies moves.CommandUtils, UnitDataExtensions.GetMovementOptions/GetAttackOptions and each command's
IsValid say which moves are legal.AI.GetMove is the built-in bot.Nothing in the rules is written by us.
Source build: Android 2.17.3.16375, which reports game version 123 and logic data version 28.
polyhost env serves matches in the championship format (1v1 Might, Lakes, Small 14×14) to
Python (py/polyenv.py):
new(slot, Spec(tribes, bots, seed)). Each seat is either driven from outside
(the agent) or by the game's AI at a difficulty. Built exactly as the real app builds a
pass-and-play game: checked byte for byte against a game the real app created.(type, a, b, arg) rows: the game's CommandType, source tile,
target tile, and argument (unit, improvement or tech type, city reward, opponent).step([(slot, index)]) plays a legal command, then lets bot seats move. Index
STEP_BOT_OWN plays the built-in AI's own command, for generating data from bot games.bot([slot]) gives where the AI's choice sits in the legal list.One process hosts many matches; run several processes for parallelism.
| Path | What |
|---|---|
polyhost/il2cpp.hpp | Binding to the il2cpp runtime exports |
polyhost/game.hpp | Loads the shipped rules data, verified single-player builders (createLocalGame, generateMap) |
polyhost/env.hpp | The bot interface: env::Match (pass-and-play construction, legal list, observation, save/load) |
polyhost/wire.hpp | Binary protocol server for the interface |
polyhost/envtest.hpp | Checks the interface against the game (legality, bot coverage, encoding, determinism) |
polyhost/json.hpp, polyhost/dump.hpp | JSON of any game object; GameState save/load |
polyhost/serve.hpp, polyhost/web/ | HTTP server and browser UI: play the bot, watch recorded games; static.js is the public site's no-server mode |
polyhost/main.cpp | Commands (below) |
py/polyenv.py, py/smoke.py | Python client (numpy) and its smoke test |
py/model.py, py/train_bc.py, py/train_rl.py | The network; behaviour cloning; PPO |
py/selfplay.py, py/sp_loop.py, py/sp_strategy.py | Self-play games and matches; the generation loop; strategy profiles |
py/eval_vs_bot.py, py/rank_games.py | Evaluation against the built-in bots; ranking games by back-and-forth |
py/fetch_replays.py, py/cm_replays.py, py/convert_replays.py | Human replay download and conversion |
py/export_site.py, tools/site_update.sh | Builds and publishes the demo site |
tools/setup_pc_games.sh | Runs the game's ARM build on an x86 Linux PC under QEMU |
tools/frida/ | Real-app tracing and recording (trace.py, hook lists, boundary recorder) |
air.com.midjiwan.polytopia_2.17.3...apkm
is signed by Midjiwan. Unzip it into game/android/splits/, then unzip base.apk into
game/android/base/ and split_config.arm64_v8a.apk into game/android/arm64/.game/android/base/assets/bin/Data with UnityPy and save the
GameLogicData1–28 and AvatarData TextAssets to game/dump/gamedata/<name>.txt.game/tools/android-ndk-r30. Boot an arm64 Android emulator:
emulator -avd PolyRef -no-window -no-snapshot -cores 6 -memory 4096 -gpu swiftshader_indirect../polyhost/run.sh push copies the game binary, metadata and data to the emulator../polyhost/run.sh build, then python3 py/smoke.py: the Python interface end to end../polyhost/run.sh envtest <games> [seed] [every] [turn cap]: checks the interface against the
game../polyhost/run.sh envbench <games>: times each part of the interface../polyhost/run.sh bench <games>: Crazy vs Crazy championship games../polyhost/run.sh hotseatcheck <real.bin> <seeds>: rebuilds a recorded real-app pass-and-play
game and compares bytes../polyhost/run.sh serve: then open http://localhost:8123 to play the built-in bot (paused)../polyhost/run.sh symbols /data/local/tmp/poly/symbols.tsv: method addresses for
tools/ghidra/decompile.sh 'GameRules$$LoadPreset/1'.env::Match::build rebuilds that game byte-identical (8,244 bytes) from the recorded
seeds and tribes.envtest, 12 games, 10,430 decisions)IsValid over every class, tile and argument), on 869 sampled states.IsValid alone is laxer than the client: it accepts captures, recovers and abilities that the
game's own Can* checks (used by the generators and the UI) reject. So the generators are
the authority, and the extra commands are reported, not offered.StayCommand, which marks a unit done; the client never offers it
to a person.tools/frida/agent.js autoplay; see HANDOFF.md).runtime_invoke, a cheaper legal list, and
threads in one process.tools/ghidra/ |
| Decompile any game method by name |
tools/statediff.py, tools/statecompare.py | Diff two dumped GameStates |
docs/design/ | Design of the AI: decision log, architecture, training plan |
game/ | Game files, extracted data, tools, traces. Not committed: it contains Midjiwan's code |