Add DRC Destroyer arcade game for routing visualization#9773
Add DRC Destroyer arcade game for routing visualization#9773oharboe wants to merge 1 commit intoThe-OpenROAD-Project:masterfrom
Conversation
A fun demo with a serious undertone: all of this was done automatically with zero programming in ca. 30 minutes. The trick is now to identify use cases, stakeholders, and minimize the cognitive load for maintainers and users. This also demonstrates the democratization of the EDA build flow. Do what you need to do for your chip and use-case. The source code for the OpenROAD project is the user-interface to Claude. The grander vision (see The-OpenROAD-Project#9770): today the Qt GUI stands between you and what you want to do. The Qt GUI is an OpenROAD developer debugging tool. The user will use Claude to generate directly what they need — whether that's a standalone HTML visualization, a custom report, or an interactive tool tailored to their specific use-case. No generic GUI can anticipate every user's needs, but an AI that reads the source code can build exactly what's needed on the fly. The serious undertone to generating a standalone static HTML: we've identified and addressed the deployment use-case — a single file with zero dependencies that anyone can open in a browser, share as a link, or attach to a PR. No servers, no installs, no runtime dependencies. This is how you ship tooling that people actually use. The unit tests close the feedback loop so Claude can quickly add extension points: write extension, add test, run bazelisk test, iterate — all within a single conversation. This is just a fun feature and has no practical value. Also fix Resizer.cc makeScenes call to match updated STA API (StringSeq passed by pointer). How to run: # Demo mode (instant, no build needed) python3 test/orfs/mock-array/game.py --demo # With real routing data (builds MockArray, ca. 30 min) bazelisk run //test/orfs/mock-array:game # Unit tests (49 tests, headless) bazelisk test //test/orfs/mock-array:test_game How to release (anyone can play by clicking the link): bazelisk run //test/orfs/mock-array:game gh release create game-v1.0 \ --title "DRC Destroyer" \ --notes "Download drc_destroyer.html and open in any browser." \ /tmp/drc_destroyer.html Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
38bed5f to
ec68178
Compare
|
clang-tidy review says "All clean, LGTM! 👍" |
There was a problem hiding this comment.
Code Review
This pull request introduces a creative and fun "DRC Destroyer" arcade game for visualizing routing DRCs. The implementation, which includes a Python script to generate a standalone HTML/JS game from ODB data, the game logic itself, and comprehensive unit tests, is a great demonstration of the project's capabilities. The addition of documentation and a fix for the Resizer API are also appreciated.
My review focuses on the new code, with a few suggestions to improve robustness, performance, and code cleanliness in the JavaScript and Python files. These are minor points in an otherwise impressive and enjoyable feature.
| function layerZ(name) { | ||
| for (const k in LAYER_Z) if (name.includes(k)) return LAYER_Z[k]; | ||
| return 0; | ||
| } | ||
|
|
||
| function layerColor(name) { | ||
| for (const k in LAYER_COLORS) if (name.includes(k)) return LAYER_COLORS[k]; | ||
| return "#888"; | ||
| } |
There was a problem hiding this comment.
The current implementation of layerZ and layerColor using name.includes(k) can lead to incorrect matches if layer names are substrings of one another (e.g., 'M1' matching 'M10'). To make this more robust, you can iterate through the layer keys sorted by length in descending order. This ensures that longer, more specific keys are checked first.
| function layerZ(name) { | |
| for (const k in LAYER_Z) if (name.includes(k)) return LAYER_Z[k]; | |
| return 0; | |
| } | |
| function layerColor(name) { | |
| for (const k in LAYER_COLORS) if (name.includes(k)) return LAYER_COLORS[k]; | |
| return "#888"; | |
| } | |
| function layerZ(name) { | |
| const sortedKeys = Object.keys(LAYER_Z).sort((a, b) => b.length - a.length); | |
| for (const k of sortedKeys) if (name.includes(k)) return LAYER_Z[k]; | |
| return 0; | |
| } | |
| function layerColor(name) { | |
| const sortedKeys = Object.keys(LAYER_COLORS).sort((a, b) => b.length - a.length); | |
| for (const k of sortedKeys) if (name.includes(k)) return LAYER_COLORS[k]; | |
| return "#888"; | |
| } |
| function detonate(bx, by) { | ||
| const blastR = 0.04; | ||
| for (const t of targets) { | ||
| if (!t.alive) continue; | ||
| const dx = t.nx - bx, dy = t.ny - by; | ||
| if (Math.sqrt(dx*dx + dy*dy) < blastR) { | ||
| t.alive = false; | ||
| score += bonusActive ? 20 : 10; | ||
| } | ||
| } | ||
| for (const w of warningMarkers) { | ||
| if (!w.alive) continue; | ||
| const dx = w.nx - bx, dy = w.ny - by; | ||
| if (Math.sqrt(dx*dx + dy*dy) < blastR) { | ||
| w.alive = false; | ||
| score += bonusActive ? 20 : 10; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
For performance, it's better to compare squared distances to avoid using Math.sqrt in a loop. This is a common optimization in game development.
| function detonate(bx, by) { | |
| const blastR = 0.04; | |
| for (const t of targets) { | |
| if (!t.alive) continue; | |
| const dx = t.nx - bx, dy = t.ny - by; | |
| if (Math.sqrt(dx*dx + dy*dy) < blastR) { | |
| t.alive = false; | |
| score += bonusActive ? 20 : 10; | |
| } | |
| } | |
| for (const w of warningMarkers) { | |
| if (!w.alive) continue; | |
| const dx = w.nx - bx, dy = w.ny - by; | |
| if (Math.sqrt(dx*dx + dy*dy) < blastR) { | |
| w.alive = false; | |
| score += bonusActive ? 20 : 10; | |
| } | |
| } | |
| } | |
| function detonate(bx, by) { | |
| const blastR = 0.04; | |
| const blastR2 = blastR * blastR; | |
| for (const t of targets) { | |
| if (!t.alive) continue; | |
| const dx = t.nx - bx, dy = t.ny - by; | |
| if (dx*dx + dy*dy < blastR2) { | |
| t.alive = false; | |
| score += bonusActive ? 20 : 10; | |
| } | |
| } | |
| for (const w of warningMarkers) { | |
| if (!w.alive) continue; | |
| const dx = w.nx - bx, dy = w.ny - by; | |
| if (dx*dx + dy*dy < blastR2) { | |
| w.alive = false; | |
| score += bonusActive ? 20 : 10; | |
| } | |
| } | |
| } |
| import subprocess | ||
| import sys |
| return villains | ||
|
|
||
|
|
||
| def parse_drc_log(log_dir): |
|
clang-tidy review says "All clean, LGTM! 👍" |
A fun demo with a serious undertone: all of this was done automatically with zero programming in ca. 30 minutes. The trick is now to identify use cases, stakeholders, and minimize the cognitive load for maintainers and users.
This PR is just a self contained demo, an example of a use-case specific emphemral code that has little value in the ORFS repository.
This also demonstrates the democratization of the EDA build flow. Do what you need to do for your chip and use-case. The source code for the OpenROAD project is the
user-interface to Claude.
The grander vision (see #9770): today the Qt GUI stands between you and what you want to do. The Qt GUI is an OpenROAD developer debugging tool. The user will use Claude to generate directly what they need — whether that's a standalone HTML visualization, a custom report, or an interactive tool tailored to their specific use-case. No generic GUI can anticipate every user's needs, but an AI that reads the source code can build exactly what's needed on the fly.
The serious undertone to generating a standalone static HTML: we've identified and addressed the deployment use-case — a single file with zero dependencies that anyone can open in a browser, share as a link, or attach to a PR. No servers, no installs, no runtime dependencies. This is how you ship tooling that people actually use.
The unit tests close the feedback loop so Claude can quickly add extension points: write extension, add test, run bazelisk test, iterate — all within a single conversation.
This is just a fun feature and has no practical value.
Also fix Resizer.cc makeScenes call to match updated STA API (StringSeq passed by pointer).
How to run:
Demo mode (instant, no build needed)
python3 test/orfs/mock-array/game.py --demo
With real routing data (builds MockArray, ca. 30 min)
bazelisk run //test/orfs/mock-array:game
Unit tests (49 tests, headless)
bazelisk test //test/orfs/mock-array:test_game
How to release (anyone can play by clicking the link):
bazelisk run //test/orfs/mock-array:game
gh release create game-v1.0
--title "DRC Destroyer"
--notes "Download drc_destroyer.html and open in any browser."
/tmp/drc_destroyer.html