NAME
Game::Mahjong::Fans - the eighty-one scoring elements, as data with a checker each
VERSION
Version 0.01
SYNOPSIS
my @splits = Game::Mahjong::Decompose::decompose($hand, $winning);
my $found = Game::Mahjong::Fans::check_all($splits[0], {
by => 'self', prevailing => 0, seat => 1, winning => $winning,
waits => \@waits, flowers => 2,
});
# { mixed_triple_chow => [ { sets => [0, 1, 2] } ], self_drawn => [ {} ], ... }
Game::Mahjong::Fans::by_key('all_pungs')->points; # 6
Game::Mahjong::Fans::COUNT; # 81
DESCRIPTION
The rulebook's 3.8.1 table and Appendix 1, one row per fan: the number, the key, the name, the points, the rulebook's sentence, what the fan does not combine with, what it inevitably implies, and a checker. The checkers find instances; combining them under the five principles is Game::Mahjong::Score's work.
The context
A checker that depends on how the hand was won reads a context hash:
by 'self' | 'discard' | 'rob'
prevailing the prevalent wind, 0 east to 3 north
seat the seat wind, 0 to 3
winning the kind won on (Nine Gates reads it)
waits the kinds the thirteen were waiting on (the wait fans need one)
last_of_wall the winning tile was the last of the wall
replacement 'kong' | 'flower' | undef, for a win on a replacement tile
last_tile the winning tile was the last of its kind visible to all
flowers how many bonus tiles the winner has exposed
Instances, not booleans
A checker returns every instance it finds, each naming the sets it used, so a hand with two pungs of terminals scores the fan twice and the scorer can apply account-once to the chow fans. A fan that names no set (a flush, a wait, the self-draw) returns an instance with no sets.
Readings the rulebook's English forces
A pung of the prevalent or the seat wind scores its own fan and is not also a Pung of Terminals or Honours; a dragon pung is never one (the sentence says "Ones, Nines, or Winds"). A win on a flower replacement is self-drawn and not Out with Replacement Tile. The two-kong fan is a ladder: two melded 4, one of each 6 (its own sentence), two concealed 8. Fan 16 is printed "Four Shifted Chows" in Appendix 1 and "Four Pure Shifted Chows" in 3.8.1; the table uses the latter. Chicken Hand has no checker: the scorer applies it when nothing else scored.
FUNCTIONS
view
my $v = view($split, $ctx);
The precomputed view of one split the checkers read: the sets with their suit, base rank and exposure, the chows, pungs (kongs included), kongs and knitted sequences, the pair, the elements (sets plus pair, or the seven pairs), every tile with multiplicity, the counts, the suits, the honours, the wait.
check_all
Every fan's instances for a split, keyed by fan key; fans with none are absent.
all, by_key, by_n, keys_of
The rows.
COUNT, @GRADES, %PER_GRADE
81; the twelve grades; how many fans each grade holds in 3.8.1.
SEE ALSO
Game::Mahjong::Fan, Game::Mahjong::Decompose, Game::Mahjong::Score
AUTHOR
LNATION <email@lnation.org>
LICENSE AND COPYRIGHT
This software is Copyright (c) 2026 by LNATION <email@lnation.org>.
This is free software, licensed under the Artistic License 2.0.