The Candidate Generation phase is the first stage of the ManueAgent.Decide() pipeline. It transforms raw legal actions provided by the domain layer into actionCandidate objects. These candidates represent not just an immediate action, but a potential future state (hand composition, shanten, and goals) used by the Monte Carlo simulation to evaluate the action's value.
Every potential move is encapsulated in an actionCandidate struct. This structure links the immediate domain action with the resulting hand state and shanten analysis.
| Field | Description |
|---|---|
traceKey | A unique string identifier (e.g., -1.5m, 0.3p) used for logging and tracking trial results. |
evaluationGroup | Integer used to group related candidates (e.g., all discards after a specific Pon belong to the same group). |
action | The domain action.Action to be executed if this candidate is selected. |
riichi | Boolean indicating if this candidate involves declaring Riichi. |
scoreAsRiichi | Boolean indicating if future win values should include the Riichi yaku. |
pruneToTenpai | Boolean indicating if non-tenpai goals should be removed before win estimation. |
afterDiscardHand | The VisibleHand state after the action and its associated discard are performed. |
shanten | The shanten of the hand after the discard. |
shantenGoals | A list of service.Goal objects representing optimal paths to a winning hand. |
Sources: internal/domain/ai/candidate.go14-36 internal/domain/ai/self_turn_candidates.go103-129
buildSelfTurnCandidates)When it is the agent's turn to discard, buildSelfTurnCandidates processes the available legal actions.
selfTurnHand internal/domain/ai/self_turn_candidates.go14-17service.AnalyzeShanten to identify all possible winning hand structures and their current shanten internal/domain/ai/self_turn_candidates.go18normalizedSelfTurnDiscards ensures that if a tile can be discarded from the hand or via tsumogiri, the agent keeps only the tsumogiri action to match original Manue behavior internal/domain/ai/self_turn_candidates.go81-101Riichi action is legal, the generator creates a candidate with riichi: true.scoreAsRiichi and pruneToTenpai are set to true for immediate Riichi candidates internal/domain/ai/self_turn_candidates.go53-55Ankan), Promoted Kans (Kakan), and Kyushukyuhai are intentionally ignored by the candidate generator and are not selected by the AI policy internal/domain/ai/self_turn_candidates.go21-22The traceKey for self-turn discards follows a specific format:
-1.[tile] (e.g., -1.5m)0.[tile] (e.g., 0.5m)Sources: internal/domain/ai/self_turn_candidates.go13-79 internal/domain/ai/self_turn_candidates_test.go13-58
buildReactionCandidates)When another player discards or declares a Kan, the agent generates reaction candidates.
Unlike self-turn candidates, a single "Call" action (Chi, Pon) results in multiple candidates—one for every legal discard after the call is made.
none candidate is created if a Pass action is available. This candidate uses "future-riichi" scoring (scoreAsRiichi: true) because the hand remains closed internal/domain/ai/call_candidates.go22-40callSwapTiles and filters them out internal/domain/ai/call_candidates.go94-97actionCandidate is generated internal/domain/ai/call_candidates.go100-118CalledKan (Daiminkan), no discard follows, so a single candidate with discardTile: ? is returned internal/domain/ai/call_candidates.go78-92none[callIndex].[tile] (e.g., 0.3p for a discard after the first legal call option).Sources: internal/domain/ai/call_candidates.go15-59 internal/domain/ai/call_candidates.go61-120
The following diagram illustrates how the ManueAgent transforms domain Action objects into evaluation-ready actionCandidate objects.
Sources: internal/domain/ai/self_turn_candidates.go13-79 internal/domain/ai/call_candidates.go15-59
Candidates perform early shanten analysis to optimize the subsequent Monte Carlo simulation.
ThrowableVector for a specific goal, that goal is filtered out during win estimation internal/domain/ai/win_goals.go55-60filteredWinEstimateGoals removes goals based on the candidate's state:
pruneToTenpai is true (Riichi), non-tenpai goals are removed internal/domain/ai/win_goals.go49-51When selecting the best candidate (chooseBestCandidate), the agent compares candidateScore (average rank, then expected points). If there is a tie and preferBlack is enabled, the agent chooses the non-red version of the tile by checking the red boolean on the actionCandidate internal/domain/ai/candidate.go43-74
Sources: internal/domain/ai/call_candidates.go61-120 internal/domain/ai/candidate.go61-74
Refresh this wiki