Skip to content

Regalia v1.1.2

Choose a tag to compare

@YDW99 YDW99 released this 09 Jul 09:50
· 8 commits to main since this release
455ab18

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

  • fix(bug);docs(main);build(v1.1.2);chore(ui…) (#37) (@YDW99) 0e89c35

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.

Lines Audited
Bug Fixes
Signing
License
Engine: Stockfish 18
Xiaomi HyperOS 3
SonarQube Cloud

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 18 arm64-v8a-dotprod binary is excluded to keep the tarball small and avoid redistributing the engine with the source. Build instructions are in BUILDING.md (inside the tarball) — you'll download the engine separately and place it at src/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 _useOriginal is almost always true for imported PGNs (because importPGN sets time: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 _pgnCacheOpInProgress guard.
  • Phase 70: Even after the above, exiting review mode before saving would still lose [%eval] because the force-rebuild was gated on _inReview (now false). Fix: check _reviewEvalCache.size > 0 directly.

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] = nullself-copy then clear = king nulled.

Fix (defense-in-depth, 4 files):

  1. ai-bridge.js uciToCoords — attach castle='kingside'/'queenside' to result.to
  2. ui.js executeMove — check to.castle as primary source (covers AI moves where legalMvs is empty)
  3. game-logic.js _castleSide — explicit 0-distance branch
  4. stats.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:

  • renderPGNText movetext-walk fallback
  • Variation-text walk
  • firstMoves opening-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 onRenderProcessGone handler — 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 calls render() only every 10 steps (was: every step), using lightweight _refreshEvalTrendChart() + _updateReviewAnalyzeBtn() for intermediate updates — fixes WebView memory pressure on 100+ step games.
  • Next _requestBatchEval wrapped in setTimeout(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-block CSS: 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)
  • nativeRenice setpriority error check + PRIO_MIN/PRIO_MAX clamp ✓
  • makeMv inB(to.row, to.col) bounds check ✓
  • onHintMove bounds check ✓
  • Long.parseLong try-catch ✓
  • MainActivity.onDestroy WebView stopLoading()
  • Standard LICENSE file at project root ✓
  • gradle.properties cross-platform (no hardcoded Ubuntu path) ✓
  • build-chess.py try/except + __main__ guard ✓
  • Emoji-space formatting (6 i18n keys) ✓
  • _pgnCacheShowPartialEvalDialog (3 options) ✓
✅ Phase 68 (9 items)
  • _reviewAnalyzeAdvance render every 10 steps ✓
  • _refreshEvalTrendChart + _updateReviewAnalyzeBtn intermediate updates ✓
  • setTimeout(0) main-thread yield ✓
  • _prioritizeReviewStep long-press handler + _reviewAnalyzePriorityQueue
  • .rmv-block oncontextmenu
  • Stats nav buttons flex: 1 1 0
  • _pgnPartialEvalDialogActive back-button support ✓
  • .rmv-block CSS user-select: none + touch-action: manipulation
  • 3 new i18n keys (priority_eval_toast / already_cached / not_in_review) ✓
✅ Phase 69 (10 items)
  • _pgnCacheBuildSaveContext decoupled coverage check from _useOriginal
  • _reviewEvalCache.size > 0 force rebuild ✓
  • _pgnCacheOpInProgress guard (33 occurrences across all PGN cache ops) ✓
  • stats.html CSP hash auto-update by build-chess.py
  • worker-pool.js onmessageerror handler ✓
  • MultiPV cap 8 ✓
  • Move Overhead cap 1000ms ✓
  • Hash cap 50% JVM heap ✓
  • Threads cap 2× CPU cores ✓
  • UCI_AnalyseMode auto-toggle ✓
✅ Phase 70 (4 items)
  • _pgnCacheBuildSaveContext force-rebuild checks _reviewEvalCache.size > 0 (not _inReview) ✓
  • makeMvInPlace inB(to.row, to.col) check ✓
  • console.log cleanup in ai-bridge.js (8 remaining are all in removal-documentation comments) ✓
  • console.log cleanup in eco-data.js (1 remaining is in removal comment) ✓
✅ Phase 71 (12 items)
  • stats.html CSP 'unsafe-inline'
  • renderPGNText / variation / firstMoves _escFEN hardening ✓
  • uciToCoords castle flag attachment ✓
  • executeMove to.castle primary source ✓
  • _castleSide 0-distance branch ✓
  • stats.html 0-distance castling mirror ✓
  • readyOkLatchHolder _readyOkLock
  • engineStop TOCTOU _discardFlagLock
  • importSettings Phase 69 cap formulas inline ✓
  • StatsActivity deprecated shouldOverrideUrlLoading overload ✓
  • StatsActivity onRenderProcessGone
  • 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.apk

Install

adb install -r Regalia-v1.1.2-release.apk

HyperOS 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: _reviewAnalyzeAdvance completion 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.html CSP switched from 'sha256-<hash>' to 'unsafe-inline' (unblocked 23 inline onclick handlers).
  • XSS hardening: renderPGNText / variation / firstMoves route through _escFEN.
  • Chess960 0-distance castling fix across 4 files (uciToCoords, executeMove, _castleSide, stats.html).
  • Concurrency fixes: readyOkLatchHolder race (_readyOkLock), engineStop TOCTOU (_discardFlagLock), importSettings cap bypass.
  • StatsActivity robustness: deprecated shouldOverrideUrlLoading overload + 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: _pgnCacheBuildSaveContext force-rebuild now checks _reviewEvalCache.size > 0 (not _inReview), so [%eval] survives exiting review mode before save.
  • Robustness: makeMvInPlace inB(to.row, to.col) bounds check (matches Phase 67 makeMv).
  • Redundancy cleanup: 7 debug console.log removed from ai-bridge.js + 1 from eco-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 — _pgnCacheOpInProgress guard on all ops.
  • Bug 4: stats.html CSP SHA-256 hash mismatch — build-chess.py now auto-updates the hash.
  • Web Worker: worker-pool.js onmessageerror handler.
  • UCI optimization: MultiPV 8, Move Overhead 1000ms, Hash 50% JVM heap, Threads 2× cores, UCI_AnalyseMode auto-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-block oncontextmenu_prioritizeReviewStep + _reviewAnalyzePriorityQueue.
  • Stats nav buttons: flex: 1 1 0 (uniform full-width).
  • PGN cache dialog polish: 💾 emoji, back-button support.
  • .rmv-block CSS: user-select: none + touch-action: manipulation.

Phase 67 (2026-07-07) — Version Bump + PGN Cache [%eval] Root-Cause Fix + Code Review Report

  • Version bump: versionCode 111 → 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 nativeRenice setpriority check, P1 makeMv inB(to), P2 onHintMove bounds + Long.parseLong try-catch + MainActivity stopLoading, GOV-1 standard LICENSE file, GOV-2 gradle.properties cross-platform, MED-3 build-chess.py error handling.

⚠️ Known Limitations

  • arm64-v8a only — 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-dotprod separately (see BUILDING.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 _escFEN before insertion into innerHTML.

♟️ Regalia v1.1.2 — Built for chess enthusiasts, by chess enthusiasts. ♟️

Report Issue · Read the Manual · Privacy Policy


AI-GEN