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.