一键导入
new-rule-completeness-validator
// Validates that all necessary code changes are implemented when adding new game rules; use when adding new game rules or variants to ensure no files are missed.
// Validates that all necessary code changes are implemented when adding new game rules; use when adding new game rules or variants to ensure no files are missed.
| name | New Rule Completeness Validator |
| description | Validates that all necessary code changes are implemented when adding new game rules; use when adding new game rules or variants to ensure no files are missed. |
When adding a new game rule or rule variant to Sanmill, you need to modify multiple files (typically 70-80 files, including ~60 localization files). This skill provides a completeness checklist to ensure no necessary code changes are missed.
Reference: docs/guides/ADDING_NEW_GAME_RULES.md
Sanmill is configuration-based, not inheritance-based. Rule variants are expressed as data (
Rulein C++,RuleSettingsin Flutter) and toggled at runtime. Any new mechanics must be gated by booleans/params so existing variants remain untouched and fast.
src/rule.cppRULES[] arrayname - Rule name (max 32 chars)description - Rule description (max 512 chars)pieceCount, flyPieceCount, piecesAtLeastCounthasDiagonalLines - Whether diagonal lines existmayFly, nMoveRule, etc.)Example structure:
{
"Your Rule Name",
"Short description",
9, 3, 3, // pieceCount, flyPieceCount, piecesAtLeastCount
false, // hasDiagonalLines
MillFormationActionInPlacingPhase::removeOpponentsPieceFromBoard,
/*mayMoveInPlacingPhase*/ false,
/*isDefenderMoveFirst*/ false,
/*mayRemoveMultiple*/ false,
// ... other fields
kDefaultCaptureRuleConfig, // custodian
kDefaultCaptureRuleConfig, // intervention
kDefaultCaptureRuleConfig, // leap
/*mayFly*/ true,
/*nMoveRule*/ 100,
/*endgameNMoveRule*/ 100,
/*threefoldRepetitionRule*/ true
}
src/rule.hN_RULES constant (to match new RULES[] length)Rule struct?// e.g., if it was 11, now it should be 12
constexpr auto N_RULES = 12;
lib/rule_settings/models/rule_settings.dartRuleSet enumRuleSettings subclass (e.g., YourNewVariantRuleSettings)Rule structruleSetDescriptions map with descriptionruleSetProperties map with default property instanceExample:
enum RuleSet {
// ... existing variants
yourNewVariant, // new
}
class YourNewVariantRuleSettings extends RuleSettings {
const YourNewVariantRuleSettings({
// All params must match C++ Rule fields
}) : super(/* ... */);
}
lib/rule_settings/widgets/modals/rule_set_modal.dartRadioListTile or similar UI component for selecting new ruleRuleSet enum valuerule_settings_page.dart?lib/l10n/intl_*.arb (~60 files)intl_en.arb - Added English translationsintl_zh_CN.arb - Added Simplified Chinese translationsintl_*.arb files - At least copied English versionflutter gen-l10n to generate localization codeKey strings:
src/position.cpp (C++ side)if (!rule.yourFeature) return fastPath();
// new logic
lib/game_page/services/engine/position.dart (Flutter side)position.cpp_putPiece, _movePiece, _removePiece related logicImportant: User-visible game logic must be symmetrically implemented in both C++ and Dart. Move generation (movegen) is C++ only.
src/movegen.cppsrc/mills.cpplib/game_page/services/engine/engine.dartRule struct gained new fieldssetRuleOptions() method to send new parameterssrc/ucioption.cppRule struct gained new fieldson_change handlers to apply values to global rule objectExample:
// ucioption.cpp
{"YourNewOption", "false", "bool", {}, on_your_new_option}
void on_your_new_option(Option &o) {
rule.yourNewField = o.get<bool>();
}
When to extend FEN: Only when you must persist dynamic state that cannot be recomputed from the board.
preferredRemoveTarget)hasDiagonalLines, etc.)mayFly, mayRemoveMultiple)src/position.h, src/position.cppposition.hfen() methodset() methodlib/game_page/services/engine/position.dart_getFen() export logicsetFen() parsing logictests/test_position.cpp, Flutter integration testssrc/evaluate.cppsrc/search.cpptests/test_*.cppset_rule(i) correctly loads new rule)tests/test_position.cpp)make test to ensure all tests passRun tests:
cd src
make build all
make test
_putPiece, _movePiece, _removePieceRun tests:
cd src/ui/flutter_app
flutter test
make benchmark)# Format all code
./format.sh
cd src/ui/flutter_app
flutter gen-l10n
# C++ build
cd src
make build all
# Flutter build (pick a platform to test)
cd ../src/ui/flutter_app
flutter build apk # Android
# or
flutter build ios # iOS
# or
flutter build windows # Windows
docs/guides/ADDING_NEW_GAME_RULES.md (if needed)Before submitting PR, confirm all of the following:
RULES[] has new entry, N_RULES incrementedRuleSet enum and RuleSettings subclass match C++Rule fields added, engine options updatedsrc/rule.h and src/rule.cppsrc/position.cpp, src/movegen.cpp, etc.src/ucioption.cpprule_settings.dart (enum + subclass + mappings)rule_set_modal.dart (UI selection)position.dartengine.dart's setRuleOptions()intl_en.arb and intl_zh_CN.arbflutter gen-l10nForgot to increment N_RULES
N_RULES in src/rule.h matches RULES[] lengthC++ and Flutter fields don't match
RuleSettings fields match Rule struct 1-to-1Missing UCI options
ucioption.cppDidn't mirror game logic to Dart
position.dart mirrors position.cpp logicIncomplete localization
Performance regression
Over-extended FEN
RULES[] as templatesdocs/guides/ADDING_NEW_GAME_RULES.md - Official guide for adding rules (must read)src/rule.h - Rule struct definitionsrc/rule.cpp - RULES[] arraysrc/position.h/.cpp - Game position and logicsrc/movegen.cpp - Move generationsrc/ucioption.cpp - UCI optionssrc/mills.cpp - Mill formation logicinclude/config.h - Default config (rarely modified)lib/rule_settings/models/rule_settings.dart - Rule modelslib/rule_settings/widgets/modals/rule_set_modal.dart - UI selectionlib/game_page/services/engine/position.dart - Position mirrorlib/game_page/services/engine/engine.dart - Engine communicationlib/l10n/intl_*.arb - Localization filestests/test_*.cpp - C++ unit teststest/ - Flutter unit and widget testsintegration_test/ - Flutter integration testsValidation results should be reported clearly:
✓ [Complete] Core File Modifications
✓ src/rule.cpp - RULES[] added
✓ src/rule.h - N_RULES incremented
✓ rule_settings.dart - RuleSet enum added
...
⚠ [Warning] Conditional File Modifications
✓ src/position.cpp - Logic updated
✗ position.dart - Logic not mirrored (needs fix)
...
✓ [Complete] Test Validation
✓ C++ tests all passed (25/25)
✓ Flutter tests all passed (42/42)
...
✗ [Failed] Localization
✓ intl_en.arb - Updated
✓ intl_zh_CN.arb - Updated
✗ Other ARB files - Not updated (needs completion)
...
📊 Completion: 75% (15/20 checks passed)
💡 Recommendation: Priority fix position.dart mirror and localization
Adding a new game rule is a systematic effort requiring careful coordination between the C++ engine and Flutter UI. Using this checklist ensures:
Remember: When in doubt, refer to docs/guides/ADDING_NEW_GAME_RULES.md and existing rule implementations.
Batch update ARB translation files across all languages when new translation keys are added to English and Chinese files; use when adding new i18n strings to the Flutter app.
Format C++ code in Sanmill project to ensure consistent code style; use when formatting C++ code or checking code style compliance.
Run Sanmill's Flutter test suite, including unit tests, widget tests, and integration tests; use when running tests or checking test coverage.