Regalia v1.1.2
What's New in v1.1.2
Full Changelog: https://github.com/YDW99/Regalia/releases/tag/v1.1.2/compare/v1.1.1...v1.1.2
Contributors
Features
- Add files via upload (@YDW99)
6c9ebcb
Bug Fixes
Documentation
- docs(CONTRIBUTING):完善细节 (@YDW99)
03b16a8 - docs(CONTRIBUTING);security(#34);build(#33) | (#35) (@YDW99)
50e7b5c
Other
- Delete CONTRIBUTING-en.md (@YDW99)
f9bf776 - Delete CONTRIBUTING-zh.md (@YDW99)
6a2fe04 - Delete Manual/Regalia-v1.1.1-manual-zh.html (@YDW99)
cb9176f - Delete Manual/Regalia-v1.1.1-manual-en.html (@YDW99)
455ab18
Installation
Download the APK from the assets below and install it on your Android device.
Note: This app requires Stockfish chess engine binaries (libstockfish.so) to be built separately via NDK.
⚠️ Note: If you encounter any issues, please report them here.
♟️ Regalia v1.1.2 ♔
A professional-grade Android chess app built around Stockfish 18 — now more robust, more secure, and more thoroughly audited than ever.
| Version | 1.1.2 (versionCode = 112) |
| Release Date | 2026-07-12 |
| Min Android | 6.0 (API 23) |
| Target Android | 15 (API 35) |
| Engine | Stockfish 18 arm64-v8a-dotprod |
| Architecture | arm64-v8a only |
| HyperOS 3 | ✅ Compatible |
| Source Size | ~34,000 lines across 8 JS modules + 9 Java files + 1 JNI + 1 stats page |
📦 Download
| Asset | Description |
|---|---|
Regalia-v1.1.2-release.apk |
Signed release APK (v1 + v2 + v3 signature schemes). 75 MB. |
Regalia-v1.1.2-manual-zh.html |
Self-contained Chinese user manual. |
Regalia-v1.1.2-manual-en.html |
Self-contained English user manual. |
⚠️ Engine binary is NOT in the source tarball. The 114 MB Stockfish 18arm64-v8a-dotprodbinary is excluded to keep the tarball small and avoid redistributing the engine with the source. Build instructions are inBUILDING.md(inside the tarball) — you'll download the engine separately and place it atsrc/main/jniLibs/arm64-v8a/libstockfish.so.
🎯 What's New in v1.1.2
v1.1.2 is a maintenance release that keeps the version number (versionCode = 112) unchanged while delivering 6 same-version revision phases (Phase 67 → 72). Each phase was driven by user feedback, first-principles code review, or security hardening — no new features were added, but the app is now significantly more reliable.
Phase Overview
| Phase | Date | Theme | Key Deliverable |
|---|---|---|---|
| 67 | 2026-07-07 | Version bump + PGN cache [%eval] root-cause fix + code review report |
New _pgnCacheShowPartialEvalDialog (3 options) |
| 68 | 2026-07-08 | Analyze All optimization + long-press priority + UI polish | Long-press to prioritize a step during batch analysis |
| 69 | 2026-07-09 | 4 bug fixes + Web Worker robustness + UCI optimization | Phase 69 UCI caps (MultiPV 8, Overhead 1000ms, Hash 50%, Threads 2×) |
| 70 | 2026-07-10 | First-principles code review cleanup | Edge-case [%eval] loss fix + console.log cleanup |
| 71 | 2026-07-11 | Stats-page move-selection bug fix + full code review | CSP 'unsafe-inline' + Chess960 0-distance castling + concurrency fixes |
| 72 | 2026-07-12 | Review analyze-all "false completion" bug fix + manual accuracy | Full-range completion scan + manual sync |
🐛 Bug Fixes (User-Reported)
1. Stats Page Move Selection Was Broken (Phase 71)
Symptom: Clicking a PGN move (e.g. 1. e4) in the 📊 Statistics page did nothing — no highlight, no board switch.
Root cause: The stats.html Content-Security-Policy used a SHA-256-hash-based script-src policy. CSP Level 2+ silently blocked all 23 inline onclick event handlers because the policy didn't include 'unsafe-inline' or 'unsafe-hashes'. The <script> block ran fine (hash matched), but every onclick="selectMove(0)" was silently dropped.
Fix: Switched script-src from 'sha256-<hash>' blob: to 'unsafe-inline' blob:. This is safe because stats.html is a local asset (file:///android_asset/) with no externally injected content and all JavaScript is inlined. Bonus: removing the hash eliminates the recurring "CSP hash mismatch" bug class (Phase 69 Bug 4 was the same root cause).
2. Review "Analyze All" Falsely Reported Completion After Long-Press Priority (Phase 72)
Symptom: During an "Analyze All" batch, long-pressing an uncached move to prioritize it would sometimes cause the batch to report "all analysis complete" — even though earlier steps remained un-analyzed.
Root cause: The _reviewAnalyzeAdvance() completion check only walked forward from _reviewAnalyzeStep+1. When a priority eval jumped ahead (e.g., user long-pressed step 50 during a batch at step 5) and subsequent steps were cached, the forward walk reached _lastStep and the completion branch fired — even though steps 5–49 were still uncached.
Fix: When the forward walk finds nothing, scan the entire range [0.._lastStep] for the lowest uncached step and resume the batch from there. The forward-only fast-path is preserved for the common (no-priority) case to avoid an O(n) full scan on every step.
// Phase 72 fix — full-range completion scan
if (nextStep > _lastStep) {
let _lowestUncached = -1;
for (let i = 0; i <= _lastStep; i++) {
if (!_reviewEvalCache.has(i)) { _lowestUncached = i; break; }
}
if (_lowestUncached >= 0) nextStep = _lowestUncached;
// else: truly all cached → completion branch
}3. PGN Cache Save Lost [%eval] Annotations (Phase 67 + 69 + 70)
Symptom: After running "Analyze All" in review mode, saving the game to the PGN cache would sometimes produce a PGN missing [%eval] annotations.
Root cause (three layers, fixed across three phases):
- Phase 67: The coverage check was gated on
!_useOriginal, but_useOriginalis almost alwaystruefor imported PGNs (becauseimportPGNsetstime:null). The check never ran, so the partial-eval dialog never appeared. - Phase 69: Race conditions in the PGN cache manager (save/import/delete/rename/tags) could corrupt state. Added
_pgnCacheOpInProgressguard. - Phase 70: Even after the above, exiting review mode before saving would still lose
[%eval]because the force-rebuild was gated on_inReview(nowfalse). Fix: check_reviewEvalCache.size > 0directly.
Fix: A new 3-option dialog (💾 Some steps not yet analyzed) appears when coverage is incomplete:
- 🔬 Analyze All first (recommended) — runs the batch, auto-saves on completion
- 💾 Save anyway — legacy behavior (evals will be missing)
- ✖️ Cancel — returns to cache manager
4. Chess960 0-Distance Castling Nulled the King (Phase 71)
Symptom: For Chess960 SP-IDs where the king starts on its castling target square (e.g. king on g1, kingside rook on h1 → UCI g1h1), castling would silently remove the king from the board.
Root cause: uciToCoords rewrote the destination to col 6, producing a 0-distance "move" g1g1. The _castleSide distance heuristic rejected it (0 < minDist), castling wasn't detected, and makeMv ran board[to] = board[from]; board[from] = null — self-copy then clear = king nulled.
Fix (defense-in-depth, 4 files):
ai-bridge.js uciToCoords— attachcastle='kingside'/'queenside'toresult.toui.js executeMove— checkto.castleas primary source (covers AI moves wherelegalMvsis empty)game-logic.js _castleSide— explicit 0-distance branchstats.html— mirror all three fixes in its independent code
🔒 Security & Robustness Hardening
XSS Hardening on Stats Page (Phase 71)
The CSP relaxation to 'unsafe-inline' (required for the onclick fix above) introduced a theoretical XSS vector: the renderPGNText movetext-walk fallback appended unrecognized characters raw to the HTML string. A malicious PGN like 1. e4 <img src=x onerror="..."> e5 * could execute.
Fix: All unrecognized movetext/variation/notation characters now route through _escFEN() (escapes `& < > " ' ``) before HTML insertion. Applied to:
renderPGNTextmovetext-walk fallback- Variation-text walk
firstMovesopening-plies list (defense-in-depth — notation is engine-generated)
Concurrency Fixes in StockfishNative.java (Phase 71)
| Race | Root Cause | Fix |
|---|---|---|
readyOkLatchHolder |
JS binder thread + executor thread both wrote the single volatile field without sync → latch lost → 3s timeout | Dedicated _readyOkLock serializes all readyOk set+wait operations |
engineStop TOCTOU on _discardingPonderBestmove |
Flag set/read outside any lock → stopped search's bestmove processed as real AI move | Dedicated _discardFlagLock makes check-and-clear atomic |
importSettings cap bypass |
Direct field assignment with loose caps (1024/1048576/10000) bypassed Phase 69 setter caps | Apply Phase 69 cap formulas inline |
StatsActivity.java Robustness (Phase 71)
- Added deprecated
shouldOverrideUrlLoading(WebView, String)overload — on API 21–23, only this overload fires; without it, external URLs would load into the WebView instead of the system browser. - Added
onRenderProcessGonehandler — a render crash on the stats page now finishes the activity instead of leaving a blank WebView.
Low-Risk Defense-in-Depth Patches (Phase 71)
| File | Patch |
|---|---|
game-logic.js |
secureRandomInt crypto-undefined guard; moveAlg setupMode typeof guard; en-passant cr inB() bounds check |
chess960.js |
toShredderCastling null-board guard |
pgn-standard.js |
sevenTagRoster / composePGN null-params guard |
worker-pool.js |
3-strike transient-failure counter (no longer permanently disables pool on one OOM) |
⚙️ UCI Parameter Optimization (Phase 69)
Per the Stockfish 18 UCI optimization guide, the engine parameter caps were tightened from spec ceilings to practical best-practice values:
| Parameter | Old Cap | New Cap (Phase 69) | Rationale |
|---|---|---|---|
| MultiPV | 500 | 8 | Review recommends 3–5; higher wastes NPS |
| Move Overhead | 5000 ms | 1000 ms | Local play 10–30ms, network 50–150ms; higher wastes thinking time |
| Hash | 32 TB | 50% JVM heap | >50% RAM causes virtual memory swapping |
| Threads | 512 | 2× CPU cores | >physical cores causes thread contention |
| UCI_AnalyseMode | — | Auto-toggle | true during eval, false during gameplay |
✨ User-Facing Improvements (Phase 68)
Long-Press to Prioritize a Step During Analyze All
During an active "Analyze All" batch, long-press any uncached move in the move list to jump its evaluation to the front of the queue:
- 🔴 Immediately aborts the current in-flight eval via
engineStop() - 💾 The interrupted eval's result is NOT lost — cached for the original step
- 🔔 Toast notification + haptic feedback
- ♻️ If the move is already cached, shows "Already analyzed" and skips
- ⬇️ If no batch is active, degrades gracefully to a single eval
Analyze All Performance (Issue 30)
_reviewAnalyzeAdvance()now callsrender()only every 10 steps (was: every step), using lightweight_refreshEvalTrendChart()+_updateReviewAnalyzeBtn()for intermediate updates — fixes WebView memory pressure on 100+ step games.- Next
_requestBatchEvalwrapped insetTimeout(0)to yield the main thread between batch steps (prevents ANR on aggressive OEM ROMs).
UI Polish
- Stats nav buttons (⏮ ◀ ▶ ⏭) now use
flex: 1 1 0(uniform full-width) - PGN cache partial-eval dialog: 💾 emoji in title, Android back-button support
.rmv-blockCSS:user-select: none+-webkit-touch-callout: none+touch-action: manipulation(prevents text selection during long-press)
📋 Phase 67→72 Verification (Phase 72)
As part of Phase 72, all Phase 67→71 changes were re-verified to be correctly implemented. The full checklist (40+ items) passed with no corrections needed:
✅ Phase 67 (10 items)
nativeRenicesetpriority error check +PRIO_MIN/PRIO_MAXclamp ✓makeMvinB(to.row, to.col)bounds check ✓onHintMovebounds check ✓Long.parseLongtry-catch ✓MainActivity.onDestroyWebViewstopLoading()✓- Standard
LICENSEfile at project root ✓ gradle.propertiescross-platform (no hardcoded Ubuntu path) ✓build-chess.pytry/except +__main__guard ✓- Emoji-space formatting (6 i18n keys) ✓
_pgnCacheShowPartialEvalDialog(3 options) ✓
✅ Phase 68 (9 items)
_reviewAnalyzeAdvancerender every 10 steps ✓_refreshEvalTrendChart+_updateReviewAnalyzeBtnintermediate updates ✓setTimeout(0)main-thread yield ✓_prioritizeReviewSteplong-press handler +_reviewAnalyzePriorityQueue✓.rmv-blockoncontextmenu✓- Stats nav buttons
flex: 1 1 0✓ _pgnPartialEvalDialogActiveback-button support ✓.rmv-blockCSSuser-select: none+touch-action: manipulation✓- 3 new i18n keys (
priority_eval_toast/already_cached/not_in_review) ✓
✅ Phase 69 (10 items)
_pgnCacheBuildSaveContextdecoupled coverage check from_useOriginal✓_reviewEvalCache.size > 0force rebuild ✓_pgnCacheOpInProgressguard (33 occurrences across all PGN cache ops) ✓stats.htmlCSP hash auto-update bybuild-chess.py✓worker-pool.jsonmessageerrorhandler ✓- MultiPV cap 8 ✓
- Move Overhead cap 1000ms ✓
- Hash cap 50% JVM heap ✓
- Threads cap 2× CPU cores ✓
UCI_AnalyseModeauto-toggle ✓
✅ Phase 70 (4 items)
_pgnCacheBuildSaveContextforce-rebuild checks_reviewEvalCache.size > 0(not_inReview) ✓makeMvInPlaceinB(to.row, to.col)check ✓console.logcleanup inai-bridge.js(8 remaining are all in removal-documentation comments) ✓console.logcleanup ineco-data.js(1 remaining is in removal comment) ✓
✅ Phase 71 (12 items)
stats.htmlCSP'unsafe-inline'✓renderPGNText/ variation /firstMoves_escFENhardening ✓uciToCoordscastle flag attachment ✓executeMoveto.castleprimary source ✓_castleSide0-distance branch ✓stats.html0-distance castling mirror ✓readyOkLatchHolder_readyOkLock✓engineStopTOCTOU_discardFlagLock✓importSettingsPhase 69 cap formulas inline ✓StatsActivitydeprecatedshouldOverrideUrlLoadingoverload ✓StatsActivityonRenderProcessGone✓- Low-risk robustness patches (6 items) ✓
🏗️ Build & Install
Prerequisites
| Component | Version |
|---|---|
| JDK | Temurin 21.0.5+11 |
| Android SDK | cmdline-tools + platform-tools + build-tools;34.0.0 + platforms;android-35 + ndk;27.2.12479018 + cmake;3.22.1 |
| Stockfish | 18 arm64-v8a-dotprod (download) |
| Python | 3.x (for build-chess.py) |
Build Steps
# 1. Extract source
tar -xzf Regalia-v1.1.2-src.tar.gz
cd Regalia-v1.1.2-src
# 2. Place the engine binary
mkdir -p src/main/jniLibs/arm64-v8a
cp /path/to/stockfish-android-armv8-dotprod src/main/jniLibs/arm64-v8a/libstockfish.so
chmod +x src/main/jniLibs/arm64-v8a/libstockfish.so
# 3. Configure SDK path
echo "sdk.dir=/path/to/android-sdk" > local.properties
# 4. Build chess.html (merges 8 JS modules)
python3 build-chess.py
# 5. Build the APK
./gradlew clean assembleRelease --no-daemon --console=plain
# 6. Verify signature
/path/to/apksigner verify --verbose build/outputs/apk/release/Regalia-release.apkInstall
adb install -r Regalia-v1.1.2-release.apkHyperOS 3 note: The APK is signed with v1 + v2 + v3 schemes and targets API 35, ensuring compatibility with Xiaomi HyperOS 3's stricter installation policies.
📚 Documentation
| File | Description |
|---|---|
README.md |
Project overview, build instructions, full Phase 1→72 changelog |
BUILDING.md |
Detailed build guide + per-phase build notes |
PRIVACY.md |
Privacy policy (fully offline, no data collection) |
NOTICE |
Third-party attributions + version history |
UBIQUITOUS_LANGUAGE.md |
Domain terminology glossary (80+ chess/engine/PGN/UI terms) |
Regalia-v1.1.2-manual-zh.html |
Self-contained Chinese user manual |
Regalia-v1.1.2-manual-en.html |
Self-contained English user manual |
📜 License
Regalia is free software licensed under the AGPL v3 (application code) with components under GPL v3 (DroidFish-derived PGN parsing + engine integration) and Apache v2.0 (Gradle).
| Component | License |
|---|---|
Application code (MainActivity, ChessApp, etc.) |
AGPL v3 |
DroidFish-derived (StockfishNative, game-logic.js, pgn-standard.js, stats.html) |
GPL v3 |
| Stockfish 18 engine | GPL v3 |
| Gradle build system | Apache v2.0 |
See LICENSE, LICENSE-AGPL v3, LICENSE-GPL v3, LICENSE-Apache v2.0 for full text.
🙏 Acknowledgments
- Stockfish — the world-class open-source chess engine that powers Regalia's analysis. GitHub
- DroidFish — Peter Österlund's Android chess app, from which Regalia's PGN parsing and engine integration logic is derived. GitHub
- Fischer Random Chess (Chess960) — invented by Bobby Fischer, fully supported in Regalia with Shredder-FEN notation and UCI_Chess960 mode.
📝 Full Changelog (Phase 67 → 72)
🔍 Click to expand the full same-version revision history
Phase 72 (2026-07-12) — Review Analyze-All "False Completion" Fix
- Bug fix:
_reviewAnalyzeAdvancecompletion check now scans the entire[0.._lastStep]range when the forward walk finds nothing, preventing false "all analysis complete" reports after a long-press priority eval jumped ahead. - Verification: All Phase 67→71 changes re-verified correct (40+ checklist items).
- Manual sync: Engine config table Phase 69 caps, long-press priority feature, partial-eval dialog, stats-page move-click regression note — all added to both manuals.
Phase 71 (2026-07-11) — Stats-Page Move-Selection Bug Fix + Full Code Review
- Bug fix:
stats.htmlCSP switched from'sha256-<hash>'to'unsafe-inline'(unblocked 23 inline onclick handlers). - XSS hardening:
renderPGNText/ variation /firstMovesroute through_escFEN. - Chess960 0-distance castling fix across 4 files (uciToCoords, executeMove, _castleSide, stats.html).
- Concurrency fixes:
readyOkLatchHolderrace (_readyOkLock),engineStopTOCTOU (_discardFlagLock),importSettingscap bypass. - StatsActivity robustness: deprecated
shouldOverrideUrlLoadingoverload +onRenderProcessGone. - 6 low-risk robustness patches (crypto guard, board guard, null guards, 3-strike worker, en-passant bounds).
Phase 70 (2026-07-10) — First-Principles Code Review Cleanup
- Edge-case bug fix:
_pgnCacheBuildSaveContextforce-rebuild now checks_reviewEvalCache.size > 0(not_inReview), so[%eval]survives exiting review mode before save. - Robustness:
makeMvInPlaceinB(to.row, to.col)bounds check (matches Phase 67makeMv). - Redundancy cleanup: 7 debug
console.logremoved fromai-bridge.js+ 1 fromeco-data.js.
Phase 69 (2026-07-09) — 4 Bug Fixes + Web Worker Robustness + UCI Optimization
- Bug 1+2: PGN cache partial-eval dialog never appeared +
[%eval]lost after reload — decoupled coverage check from_useOriginal; force rebuild when_reviewEvalCache.size > 0. - Bug 3: PGN cache manager race conditions —
_pgnCacheOpInProgressguard on all ops. - Bug 4:
stats.htmlCSP SHA-256 hash mismatch —build-chess.pynow auto-updates the hash. - Web Worker:
worker-pool.jsonmessageerrorhandler. - UCI optimization: MultiPV 8, Move Overhead 1000ms, Hash 50% JVM heap, Threads 2× cores,
UCI_AnalyseModeauto-toggle.
Phase 68 (2026-07-08) — Analyze All Optimization + Long-Press Priority + UI Polish
- Analyze All optimization (Issue 30):
render()every 10 steps +setTimeout(0)yield. - Long-press priority:
.rmv-blockoncontextmenu→_prioritizeReviewStep+_reviewAnalyzePriorityQueue. - Stats nav buttons:
flex: 1 1 0(uniform full-width). - PGN cache dialog polish: 💾 emoji, back-button support.
.rmv-blockCSS:user-select: none+touch-action: manipulation.
Phase 67 (2026-07-07) — Version Bump + PGN Cache [%eval] Root-Cause Fix + Code Review Report
- Version bump:
versionCode111 → 112,versionName"1.1.1" → "1.1.2". - Emoji-space formatting: Unified in 6 i18n keys + stats.html hardcoded titles.
- PGN cache
[%eval]root-cause fix: New_pgnCacheShowPartialEvalDialog(3 options: Analyze All first / Save anyway / Cancel). - Code review report implementation: P0
nativeRenicesetpriority check, P1makeMvinB(to), P2onHintMovebounds +Long.parseLongtry-catch +MainActivitystopLoading, GOV-1 standardLICENSEfile, GOV-2gradle.propertiescross-platform, MED-3build-chess.pyerror handling.
⚠️ Known Limitations
arm64-v8aonly — no x86/ARMv7 builds (modern devices are all arm64; older 32-bit devices are not supported).- Engine binary not in source tarball — download Stockfish 18
arm64-v8a-dotprodseparately (seeBUILDING.md). - Stats page CSP uses
'unsafe-inline'— safe for a local asset with no external content, but means inline event handlers are allowed. All user-pasted PGN content is HTML-escaped via_escFENbefore insertion intoinnerHTML.
♟️ Regalia v1.1.2 — Built for chess enthusiasts, by chess enthusiasts. ♟️
AI-GEN