com um clique
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.
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.
| 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.