Editorial illustration: Where do each game’s rules live?

Where do each game’s rules live?

The problem I needed to solve

If the shared core starts knowing Hokm and Pasur, every additional game becomes more costly. I wanted validation, winner evaluation and scoring to be separately definable.

Implementation in this snapshot

IGameRuleSet declares ValidateCardPlay, EvaluateRoundWinner and CalculateScore. Each receives its own context and returns its own result; CoreRuleSystem invokes these contracts.

The design decision and its cost

A small contract keeps generic logic from assuming a particular rule. However, not every complex game flow fits into those three functions, and specialized services can still be necessary.

Current boundaries

The documentation includes a Hokm RuleSet as an extension example. I do not treat that example as proof of a final scene-wired class; Hokm also runs through its specialized services.

Calculating a score before applying it

In a card game, asking whether a move is legal differs from asking who receives points. IGameRuleSet expresses these decisions through separate contexts and results, and CoreRuleSystem delegates to the chosen implementation. The wrapper adds no suit or rank rules. For Dalo, this makes each decision’s inputs explicit. The limitation is equally clear: if a context lacks information required by a game, the generic contract alone cannot model every stage.

CoreRuleSystem.ApplyScore illustrates separation between calculation and mutation. It ignores null or unchanged results, iterates ScoreChanges and adds each amount to the corresponding player’s Score. Changes without a Player are skipped rather than rejected. Readers should understand that applying a calculated report does not necessarily fail loudly. A consumer requiring every change to apply must validate the result before entering that loop.

The loop has no operation ID or record of previously applied results. Reapplying a result containing changes can add those points again; RuleSystem does not automatically provide duplicate protection. This is why I distinguish the generic contract from Hokm’s specialized services. The core documentation’s RuleSet example explains an extension path, but does not prove that the example class runs in the current scene. Claims about active wiring need scene references and construction paths, rather than an instructional excerpt alone.

What this stage taught me

For me, this was an exercise in boundaries. The core provides capabilities and the game makes decisions. Adding a game should not mean filling the core with conditions on game names.

Explore Dalo

Latest devlogs

Editorial illustration: Pasur launch and telemetry in the shared structure

Pasur launch and telemetry in the shared structure

Adding Pasur needs both a correct mode handoff and valid public telemetry.

Read article
Editorial illustration: Presenting selection and captures in Pasur

Presenting selection and captures in Pasur

Pasur motion should explain which hand card was played and which table cards were captured.

Read article
Editorial illustration: Pasur bot decisions from capture options

Pasur bot decisions from capture options

My teammate’s Pasur bot chooses among legal options without inspecting hidden opposing cards.

Read article
Dalo