mahjong_engine 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/qlty-coverage.yml +36 -0
- package/dist/BlockDivider.d.ts +11 -0
- package/dist/BlockDivider.d.ts.map +1 -0
- package/dist/BlockDivider.js +114 -0
- package/dist/BlockDivider.js.map +1 -0
- package/dist/BlockHais.d.ts +26 -0
- package/dist/BlockHais.d.ts.map +1 -0
- package/dist/BlockHais.js +77 -0
- package/dist/BlockHais.js.map +1 -0
- package/dist/BlockHaisList.d.ts +19 -0
- package/dist/BlockHaisList.d.ts.map +1 -0
- package/dist/BlockHaisList.js +85 -0
- package/dist/BlockHaisList.js.map +1 -0
- package/dist/Hai.d.ts +16 -0
- package/dist/Hai.d.ts.map +1 -0
- package/dist/Hai.js +71 -0
- package/dist/Hai.js.map +1 -0
- package/dist/Hais.d.ts +15 -0
- package/dist/Hais.d.ts.map +1 -0
- package/dist/Hais.js +44 -0
- package/dist/Hais.js.map +1 -0
- package/dist/IMentsu.d.ts +20 -0
- package/dist/IMentsu.d.ts.map +1 -0
- package/dist/IMentsu.js +3 -0
- package/dist/IMentsu.js.map +1 -0
- package/dist/MachiCalculator.d.ts +7 -0
- package/dist/MachiCalculator.d.ts.map +1 -0
- package/dist/MachiCalculator.js +25 -0
- package/dist/MachiCalculator.js.map +1 -0
- package/dist/MahjongConsts.d.ts +39 -0
- package/dist/MahjongConsts.d.ts.map +1 -0
- package/dist/MahjongConsts.js +54 -0
- package/dist/MahjongConsts.js.map +1 -0
- package/dist/Meld.d.ts +25 -0
- package/dist/Meld.d.ts.map +1 -0
- package/dist/Meld.js +72 -0
- package/dist/Meld.js.map +1 -0
- package/dist/Melds.d.ts +9 -0
- package/dist/Melds.d.ts.map +1 -0
- package/dist/Melds.js +18 -0
- package/dist/Melds.js.map +1 -0
- package/dist/MentsuAnalyzer.d.ts +11 -0
- package/dist/MentsuAnalyzer.d.ts.map +1 -0
- package/dist/MentsuAnalyzer.js +23 -0
- package/dist/MentsuAnalyzer.js.map +1 -0
- package/dist/PlayerContext.d.ts +28 -0
- package/dist/PlayerContext.d.ts.map +1 -0
- package/dist/PlayerContext.js +28 -0
- package/dist/PlayerContext.js.map +1 -0
- package/dist/PlayerHand.d.ts +12 -0
- package/dist/PlayerHand.d.ts.map +1 -0
- package/dist/PlayerHand.js +28 -0
- package/dist/PlayerHand.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/tensuu/FuCalculator.d.ts +15 -0
- package/dist/tensuu/FuCalculator.d.ts.map +1 -0
- package/dist/tensuu/FuCalculator.js +104 -0
- package/dist/tensuu/FuCalculator.js.map +1 -0
- package/dist/tensuu/FuDetail.d.ts +8 -0
- package/dist/tensuu/FuDetail.d.ts.map +1 -0
- package/dist/tensuu/FuDetail.js +15 -0
- package/dist/tensuu/FuDetail.js.map +1 -0
- package/dist/tensuu/ScoreResolver.d.ts +12 -0
- package/dist/tensuu/ScoreResolver.d.ts.map +1 -0
- package/dist/tensuu/ScoreResolver.js +33 -0
- package/dist/tensuu/ScoreResolver.js.map +1 -0
- package/dist/tensuu/ScoreResult.d.ts +11 -0
- package/dist/tensuu/ScoreResult.d.ts.map +1 -0
- package/dist/tensuu/ScoreResult.js +19 -0
- package/dist/tensuu/ScoreResult.js.map +1 -0
- package/dist/tensuu/TensuuCalculator.d.ts +13 -0
- package/dist/tensuu/TensuuCalculator.d.ts.map +1 -0
- package/dist/tensuu/TensuuCalculator.js +39 -0
- package/dist/tensuu/TensuuCalculator.js.map +1 -0
- package/dist/tensuu/TensuuResult.d.ts +15 -0
- package/dist/tensuu/TensuuResult.d.ts.map +1 -0
- package/dist/tensuu/TensuuResult.js +19 -0
- package/dist/tensuu/TensuuResult.js.map +1 -0
- package/dist/tileDefs.d.ts +42 -0
- package/dist/tileDefs.d.ts.map +1 -0
- package/dist/tileDefs.js +23 -0
- package/dist/tileDefs.js.map +1 -0
- package/dist/yaku/NormalYakuChecker.d.ts +7 -0
- package/dist/yaku/NormalYakuChecker.d.ts.map +1 -0
- package/dist/yaku/NormalYakuChecker.js +37 -0
- package/dist/yaku/NormalYakuChecker.js.map +1 -0
- package/dist/yaku/YakuChecker.d.ts +7 -0
- package/dist/yaku/YakuChecker.d.ts.map +1 -0
- package/dist/yaku/YakuChecker.js +27 -0
- package/dist/yaku/YakuChecker.js.map +1 -0
- package/dist/yaku/YakuCheckerBase.d.ts +33 -0
- package/dist/yaku/YakuCheckerBase.d.ts.map +1 -0
- package/dist/yaku/YakuCheckerBase.js +154 -0
- package/dist/yaku/YakuCheckerBase.js.map +1 -0
- package/dist/yaku/YakuContext.d.ts +14 -0
- package/dist/yaku/YakuContext.d.ts.map +1 -0
- package/dist/yaku/YakuContext.js +21 -0
- package/dist/yaku/YakuContext.js.map +1 -0
- package/dist/yaku/YakumanChecker.d.ts +7 -0
- package/dist/yaku/YakumanChecker.d.ts.map +1 -0
- package/dist/yaku/YakumanChecker.js +36 -0
- package/dist/yaku/YakumanChecker.js.map +1 -0
- package/dist/yaku/index.d.ts +6 -0
- package/dist/yaku/index.d.ts.map +1 -0
- package/dist/yaku/index.js +79 -0
- package/dist/yaku/index.js.map +1 -0
- package/dist/yaku/normal/ChinitsuChecker.d.ts +9 -0
- package/dist/yaku/normal/ChinitsuChecker.d.ts.map +1 -0
- package/dist/yaku/normal/ChinitsuChecker.js +24 -0
- package/dist/yaku/normal/ChinitsuChecker.js.map +1 -0
- package/dist/yaku/normal/ChitoitsuChecker.d.ts +8 -0
- package/dist/yaku/normal/ChitoitsuChecker.d.ts.map +1 -0
- package/dist/yaku/normal/ChitoitsuChecker.js +20 -0
- package/dist/yaku/normal/ChitoitsuChecker.js.map +1 -0
- package/dist/yaku/normal/DoukouChecker.d.ts +8 -0
- package/dist/yaku/normal/DoukouChecker.d.ts.map +1 -0
- package/dist/yaku/normal/DoukouChecker.js +17 -0
- package/dist/yaku/normal/DoukouChecker.js.map +1 -0
- package/dist/yaku/normal/HonchanChecker.d.ts +8 -0
- package/dist/yaku/normal/HonchanChecker.d.ts.map +1 -0
- package/dist/yaku/normal/HonchanChecker.js +22 -0
- package/dist/yaku/normal/HonchanChecker.js.map +1 -0
- package/dist/yaku/normal/HonitsuChecker.d.ts +8 -0
- package/dist/yaku/normal/HonitsuChecker.d.ts.map +1 -0
- package/dist/yaku/normal/HonitsuChecker.js +20 -0
- package/dist/yaku/normal/HonitsuChecker.js.map +1 -0
- package/dist/yaku/normal/HonrotoChecker.d.ts +8 -0
- package/dist/yaku/normal/HonrotoChecker.d.ts.map +1 -0
- package/dist/yaku/normal/HonrotoChecker.js +21 -0
- package/dist/yaku/normal/HonrotoChecker.js.map +1 -0
- package/dist/yaku/normal/IipekoChecker.d.ts +8 -0
- package/dist/yaku/normal/IipekoChecker.d.ts.map +1 -0
- package/dist/yaku/normal/IipekoChecker.js +18 -0
- package/dist/yaku/normal/IipekoChecker.js.map +1 -0
- package/dist/yaku/normal/IttsuuChecker.d.ts +8 -0
- package/dist/yaku/normal/IttsuuChecker.d.ts.map +1 -0
- package/dist/yaku/normal/IttsuuChecker.js +25 -0
- package/dist/yaku/normal/IttsuuChecker.js.map +1 -0
- package/dist/yaku/normal/JunchanChecker.d.ts +8 -0
- package/dist/yaku/normal/JunchanChecker.d.ts.map +1 -0
- package/dist/yaku/normal/JunchanChecker.js +19 -0
- package/dist/yaku/normal/JunchanChecker.js.map +1 -0
- package/dist/yaku/normal/KazehaiChecker.d.ts +11 -0
- package/dist/yaku/normal/KazehaiChecker.d.ts.map +1 -0
- package/dist/yaku/normal/KazehaiChecker.js +24 -0
- package/dist/yaku/normal/KazehaiChecker.js.map +1 -0
- package/dist/yaku/normal/MenzenTsumoChecker.d.ts +8 -0
- package/dist/yaku/normal/MenzenTsumoChecker.d.ts.map +1 -0
- package/dist/yaku/normal/MenzenTsumoChecker.js +16 -0
- package/dist/yaku/normal/MenzenTsumoChecker.js.map +1 -0
- package/dist/yaku/normal/PinfuChecker.d.ts +8 -0
- package/dist/yaku/normal/PinfuChecker.d.ts.map +1 -0
- package/dist/yaku/normal/PinfuChecker.js +30 -0
- package/dist/yaku/normal/PinfuChecker.js.map +1 -0
- package/dist/yaku/normal/RenpuuhaiChecker.d.ts +8 -0
- package/dist/yaku/normal/RenpuuhaiChecker.d.ts.map +1 -0
- package/dist/yaku/normal/RenpuuhaiChecker.js +22 -0
- package/dist/yaku/normal/RenpuuhaiChecker.js.map +1 -0
- package/dist/yaku/normal/RyanpekoChecker.d.ts +8 -0
- package/dist/yaku/normal/RyanpekoChecker.d.ts.map +1 -0
- package/dist/yaku/normal/RyanpekoChecker.js +18 -0
- package/dist/yaku/normal/RyanpekoChecker.js.map +1 -0
- package/dist/yaku/normal/SanankoChecker.d.ts +8 -0
- package/dist/yaku/normal/SanankoChecker.d.ts.map +1 -0
- package/dist/yaku/normal/SanankoChecker.js +17 -0
- package/dist/yaku/normal/SanankoChecker.js.map +1 -0
- package/dist/yaku/normal/SankantsuChecker.d.ts +8 -0
- package/dist/yaku/normal/SankantsuChecker.d.ts.map +1 -0
- package/dist/yaku/normal/SankantsuChecker.js +17 -0
- package/dist/yaku/normal/SankantsuChecker.js.map +1 -0
- package/dist/yaku/normal/SanshokuChecker.d.ts +8 -0
- package/dist/yaku/normal/SanshokuChecker.d.ts.map +1 -0
- package/dist/yaku/normal/SanshokuChecker.js +17 -0
- package/dist/yaku/normal/SanshokuChecker.js.map +1 -0
- package/dist/yaku/normal/ShosangenChecker.d.ts +8 -0
- package/dist/yaku/normal/ShosangenChecker.d.ts.map +1 -0
- package/dist/yaku/normal/ShosangenChecker.js +20 -0
- package/dist/yaku/normal/ShosangenChecker.js.map +1 -0
- package/dist/yaku/normal/TanyaoChecker.d.ts +8 -0
- package/dist/yaku/normal/TanyaoChecker.d.ts.map +1 -0
- package/dist/yaku/normal/TanyaoChecker.js +18 -0
- package/dist/yaku/normal/TanyaoChecker.js.map +1 -0
- package/dist/yaku/normal/ToitoiChecker.d.ts +8 -0
- package/dist/yaku/normal/ToitoiChecker.d.ts.map +1 -0
- package/dist/yaku/normal/ToitoiChecker.js +17 -0
- package/dist/yaku/normal/ToitoiChecker.js.map +1 -0
- package/dist/yaku/normal/YakuhaiChecker.d.ts +9 -0
- package/dist/yaku/normal/YakuhaiChecker.d.ts.map +1 -0
- package/dist/yaku/normal/YakuhaiChecker.js +22 -0
- package/dist/yaku/normal/YakuhaiChecker.js.map +1 -0
- package/dist/yaku/yakuman/ChinrotoChecker.d.ts +6 -0
- package/dist/yaku/yakuman/ChinrotoChecker.d.ts.map +1 -0
- package/dist/yaku/yakuman/ChinrotoChecker.js +13 -0
- package/dist/yaku/yakuman/ChinrotoChecker.js.map +1 -0
- package/dist/yaku/yakuman/Churen9Checker.d.ts +10 -0
- package/dist/yaku/yakuman/Churen9Checker.d.ts.map +1 -0
- package/dist/yaku/yakuman/Churen9Checker.js +17 -0
- package/dist/yaku/yakuman/Churen9Checker.js.map +1 -0
- package/dist/yaku/yakuman/ChurenChecker.d.ts +7 -0
- package/dist/yaku/yakuman/ChurenChecker.d.ts.map +1 -0
- package/dist/yaku/yakuman/ChurenChecker.js +33 -0
- package/dist/yaku/yakuman/ChurenChecker.js.map +1 -0
- package/dist/yaku/yakuman/DaisangenChecker.d.ts +6 -0
- package/dist/yaku/yakuman/DaisangenChecker.d.ts.map +1 -0
- package/dist/yaku/yakuman/DaisangenChecker.js +15 -0
- package/dist/yaku/yakuman/DaisangenChecker.js.map +1 -0
- package/dist/yaku/yakuman/DaisushiChecker.d.ts +8 -0
- package/dist/yaku/yakuman/DaisushiChecker.d.ts.map +1 -0
- package/dist/yaku/yakuman/DaisushiChecker.js +20 -0
- package/dist/yaku/yakuman/DaisushiChecker.js.map +1 -0
- package/dist/yaku/yakuman/ExtendedYakumanChecker.d.ts +9 -0
- package/dist/yaku/yakuman/ExtendedYakumanChecker.d.ts.map +1 -0
- package/dist/yaku/yakuman/ExtendedYakumanChecker.js +18 -0
- package/dist/yaku/yakuman/ExtendedYakumanChecker.js.map +1 -0
- package/dist/yaku/yakuman/Kokushi13Checker.d.ts +10 -0
- package/dist/yaku/yakuman/Kokushi13Checker.d.ts.map +1 -0
- package/dist/yaku/yakuman/Kokushi13Checker.js +17 -0
- package/dist/yaku/yakuman/Kokushi13Checker.js.map +1 -0
- package/dist/yaku/yakuman/KokushiChecker.d.ts +7 -0
- package/dist/yaku/yakuman/KokushiChecker.d.ts.map +1 -0
- package/dist/yaku/yakuman/KokushiChecker.js +18 -0
- package/dist/yaku/yakuman/KokushiChecker.js.map +1 -0
- package/dist/yaku/yakuman/RyuisoChecker.d.ts +6 -0
- package/dist/yaku/yakuman/RyuisoChecker.d.ts.map +1 -0
- package/dist/yaku/yakuman/RyuisoChecker.js +17 -0
- package/dist/yaku/yakuman/RyuisoChecker.js.map +1 -0
- package/dist/yaku/yakuman/ShosushiChecker.d.ts +6 -0
- package/dist/yaku/yakuman/ShosushiChecker.d.ts.map +1 -0
- package/dist/yaku/yakuman/ShosushiChecker.js +15 -0
- package/dist/yaku/yakuman/ShosushiChecker.js.map +1 -0
- package/dist/yaku/yakuman/SuankoChecker.d.ts +7 -0
- package/dist/yaku/yakuman/SuankoChecker.d.ts.map +1 -0
- package/dist/yaku/yakuman/SuankoChecker.js +17 -0
- package/dist/yaku/yakuman/SuankoChecker.js.map +1 -0
- package/dist/yaku/yakuman/SuankoTankiChecker.d.ts +8 -0
- package/dist/yaku/yakuman/SuankoTankiChecker.d.ts.map +1 -0
- package/dist/yaku/yakuman/SuankoTankiChecker.js +28 -0
- package/dist/yaku/yakuman/SuankoTankiChecker.js.map +1 -0
- package/dist/yaku/yakuman/SukantsuChecker.d.ts +6 -0
- package/dist/yaku/yakuman/SukantsuChecker.d.ts.map +1 -0
- package/dist/yaku/yakuman/SukantsuChecker.js +12 -0
- package/dist/yaku/yakuman/SukantsuChecker.js.map +1 -0
- package/dist/yaku/yakuman/TsuisoChecker.d.ts +6 -0
- package/dist/yaku/yakuman/TsuisoChecker.d.ts.map +1 -0
- package/dist/yaku/yakuman/TsuisoChecker.js +13 -0
- package/dist/yaku/yakuman/TsuisoChecker.js.map +1 -0
- package/jest.config.js +8 -0
- package/modules/BlockDivider.ts +129 -0
- package/modules/BlockHais.ts +92 -0
- package/modules/BlockHaisList.ts +96 -0
- package/modules/Hai.ts +67 -0
- package/modules/Hais.ts +49 -0
- package/modules/IMentsu.ts +20 -0
- package/modules/MachiCalculator.ts +25 -0
- package/modules/MahjongConsts.ts +46 -0
- package/modules/Meld.ts +85 -0
- package/modules/Melds.ts +19 -0
- package/modules/MentsuAnalyzer.ts +37 -0
- package/modules/PlayerContext.ts +39 -0
- package/modules/PlayerHand.ts +32 -0
- package/modules/index.ts +11 -0
- package/modules/tensuu/FuCalculator.ts +118 -0
- package/modules/tensuu/FuDetail.ts +13 -0
- package/modules/tensuu/ScoreResolver.ts +35 -0
- package/modules/tensuu/ScoreResult.ts +24 -0
- package/modules/tensuu/TensuuCalculator.ts +40 -0
- package/modules/tensuu/TensuuResult.ts +21 -0
- package/modules/tileDefs.ts +24 -0
- package/modules/yaku/NormalYakuChecker.ts +31 -0
- package/modules/yaku/YakuChecker.ts +29 -0
- package/modules/yaku/YakuCheckerBase.ts +180 -0
- package/modules/yaku/YakuContext.ts +25 -0
- package/modules/yaku/YakumanChecker.ts +34 -0
- package/modules/yaku/index.ts +83 -0
- package/modules/yaku/normal/ChinitsuChecker.ts +25 -0
- package/modules/yaku/normal/ChitoitsuChecker.ts +20 -0
- package/modules/yaku/normal/DoukouChecker.ts +16 -0
- package/modules/yaku/normal/HonchanChecker.ts +24 -0
- package/modules/yaku/normal/HonitsuChecker.ts +20 -0
- package/modules/yaku/normal/HonrotoChecker.ts +23 -0
- package/modules/yaku/normal/IipekoChecker.ts +17 -0
- package/modules/yaku/normal/IttsuuChecker.ts +32 -0
- package/modules/yaku/normal/JunchanChecker.ts +20 -0
- package/modules/yaku/normal/KazehaiChecker.ts +25 -0
- package/modules/yaku/normal/MenzenTsumoChecker.ts +15 -0
- package/modules/yaku/normal/PinfuChecker.ts +26 -0
- package/modules/yaku/normal/RenpuuhaiChecker.ts +21 -0
- package/modules/yaku/normal/RyanpekoChecker.ts +17 -0
- package/modules/yaku/normal/SanankoChecker.ts +17 -0
- package/modules/yaku/normal/SankantsuChecker.ts +16 -0
- package/modules/yaku/normal/SanshokuChecker.ts +16 -0
- package/modules/yaku/normal/ShosangenChecker.ts +21 -0
- package/modules/yaku/normal/TanyaoChecker.ts +18 -0
- package/modules/yaku/normal/ToitoiChecker.ts +17 -0
- package/modules/yaku/normal/YakuhaiChecker.ts +22 -0
- package/modules/yaku/yakuman/ChinrotoChecker.ts +11 -0
- package/modules/yaku/yakuman/Churen9Checker.ts +16 -0
- package/modules/yaku/yakuman/ChurenChecker.ts +31 -0
- package/modules/yaku/yakuman/DaisangenChecker.ts +14 -0
- package/modules/yaku/yakuman/DaisushiChecker.ts +21 -0
- package/modules/yaku/yakuman/ExtendedYakumanChecker.ts +18 -0
- package/modules/yaku/yakuman/Kokushi13Checker.ts +16 -0
- package/modules/yaku/yakuman/KokushiChecker.ts +15 -0
- package/modules/yaku/yakuman/RyuisoChecker.ts +16 -0
- package/modules/yaku/yakuman/ShosushiChecker.ts +13 -0
- package/modules/yaku/yakuman/SuankoChecker.ts +14 -0
- package/modules/yaku/yakuman/SuankoTankiChecker.ts +28 -0
- package/modules/yaku/yakuman/SukantsuChecker.ts +9 -0
- package/modules/yaku/yakuman/TsuisoChecker.ts +10 -0
- package/package.json +28 -0
- package/tests/fu.test.ts +44 -0
- package/tests/machi/chinitsu.ts +137 -0
- package/tests/machi/chitoitsu.ts +12 -0
- package/tests/machi/kokushi.ts +22 -0
- package/tests/machi/maisuu.ts +77 -0
- package/tests/machi.test.ts +100 -0
- package/tests/machiType.test.ts +93 -0
- package/tests/score.test.ts +27 -0
- package/tests/tehaiCaseRunner.ts +57 -0
- package/tests/tensuu/fu.ts +272 -0
- package/tests/tensuu/score.ts +46 -0
- package/tests/tensuu/tensuuNum.ts +292 -0
- package/tests/tensuuFromNum.test.ts +15 -0
- package/tests/testConsts.ts +42 -0
- package/tests/toBlock.test.ts +155 -0
- package/tests/yaku/normal.ts +1046 -0
- package/tests/yaku/yakuman.ts +367 -0
- package/tests/yaku.test.ts +28 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export class TensuuResult{
|
|
2
|
+
public readonly base: number;
|
|
3
|
+
public readonly ronOya: number;
|
|
4
|
+
public readonly ronKo: number;
|
|
5
|
+
public readonly tsumoOya: number;
|
|
6
|
+
public readonly tsumoKo: {oya: number, ko: number};
|
|
7
|
+
|
|
8
|
+
constructor(
|
|
9
|
+
base: number,
|
|
10
|
+
ronOya: number,
|
|
11
|
+
ronKo: number,
|
|
12
|
+
tsumoOya: number,
|
|
13
|
+
tsumoKo: {oya: number, ko: number}
|
|
14
|
+
){
|
|
15
|
+
this.base = base;
|
|
16
|
+
this.ronOya = ronOya;
|
|
17
|
+
this.ronKo = ronKo;
|
|
18
|
+
this.tsumoOya = tsumoOya;
|
|
19
|
+
this.tsumoKo = tsumoKo;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//牌を数値として定義
|
|
2
|
+
export const TILE = {
|
|
3
|
+
MANZU: [1,2,3,4,5,6,7,8,9],
|
|
4
|
+
PINZU: [10,11,12,13,14,15,16,17,18],
|
|
5
|
+
SOUZU: [19,20,21,22,23,24,25,26,27],
|
|
6
|
+
JIHAI: [28,29,30,31,32,33,34],
|
|
7
|
+
|
|
8
|
+
WIND: {
|
|
9
|
+
EAST: { id: 28, name: "東" },
|
|
10
|
+
SOUTH: { id: 29, name: "南" },
|
|
11
|
+
WEST: { id: 30, name: "西" },
|
|
12
|
+
NORTH: { id: 31, name: "北" }
|
|
13
|
+
},
|
|
14
|
+
DRAGON: {
|
|
15
|
+
WHITE: { id: 32, name: "白" },
|
|
16
|
+
GREEN: { id: 33, name: "發" },
|
|
17
|
+
RED: { id: 34, name: "中" }
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
BACK: 100,
|
|
21
|
+
} as const;
|
|
22
|
+
|
|
23
|
+
export type Wind = typeof TILE.WIND[keyof typeof TILE.WIND];
|
|
24
|
+
export type Dragon = typeof TILE.DRAGON[keyof typeof TILE.DRAGON];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { WinEvent } from '../MahjongConsts';
|
|
2
|
+
import { YakuContext } from './YakuContext';
|
|
3
|
+
import { NormalYakuCheckers } from './index';
|
|
4
|
+
|
|
5
|
+
export class NormalYakuChecker{
|
|
6
|
+
protected readonly context: YakuContext;
|
|
7
|
+
|
|
8
|
+
constructor(context: YakuContext){
|
|
9
|
+
this.context = context;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//役判定
|
|
13
|
+
check(): Map<string, number> {
|
|
14
|
+
const yaku_map: Map<string, number> = new Map();
|
|
15
|
+
for(const Checker of NormalYakuCheckers) {
|
|
16
|
+
const checker = Checker(this.context);
|
|
17
|
+
if(checker.check()) yaku_map.set(checker.getName(), checker.getHan());
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if(this.context.ctx.riichi) yaku_map.set("立直", 1);
|
|
21
|
+
if(this.context.ctx.daburii) yaku_map.set("ダブル立直", 2);
|
|
22
|
+
if(this.context.ctx.ippatsu) yaku_map.set("一発", 1);
|
|
23
|
+
if(this.context.ctx.event === WinEvent.RINSHAN) yaku_map.set("嶺上開花", 1);
|
|
24
|
+
if(this.context.ctx.event === WinEvent.CHANKAN) yaku_map.set("槍槓", 1);
|
|
25
|
+
if(this.context.ctx.event === WinEvent.HAITEI) yaku_map.set("海底摸月", 1);
|
|
26
|
+
if(this.context.ctx.event === WinEvent.HOUTEI) yaku_map.set("河底撈魚", 1);
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
return yaku_map;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { PlayerHand } from '../PlayerHand';
|
|
2
|
+
import { PlayerContext } from '../PlayerContext';
|
|
3
|
+
import { YakumanChecker } from './YakumanChecker';
|
|
4
|
+
import { BlockHaisList } from '../BlockHaisList';
|
|
5
|
+
import { YakuContext } from './YakuContext';
|
|
6
|
+
import { NormalYakuChecker } from './NormalYakuChecker';
|
|
7
|
+
|
|
8
|
+
export class YakuChecker {
|
|
9
|
+
private context: YakuContext
|
|
10
|
+
|
|
11
|
+
constructor(context: YakuContext){
|
|
12
|
+
this.context = context;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
check(): Map<string, number> {
|
|
16
|
+
//手牌と鳴き(カンを考慮して鳴き一つを3と数える)が計14枚かどうか確認する
|
|
17
|
+
const tehai_num = this.context.hais.length;
|
|
18
|
+
const furo_num = this.context.melds.length;
|
|
19
|
+
if(tehai_num + furo_num * 3 !== 14) return new Map<string, number>();
|
|
20
|
+
|
|
21
|
+
const yakuman_map = new YakumanChecker(this.context).check();
|
|
22
|
+
if(yakuman_map.size === 0){
|
|
23
|
+
return new NormalYakuChecker(this.context).check();
|
|
24
|
+
}
|
|
25
|
+
else{
|
|
26
|
+
return yakuman_map;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { Hai } from '../Hai';
|
|
2
|
+
import { YakuContext } from './YakuContext';
|
|
3
|
+
import { BlockHaisList } from '../BlockHaisList';
|
|
4
|
+
import { MachiCalculator } from '../MachiCalculator';
|
|
5
|
+
import { IMentsu } from '../IMentsu';
|
|
6
|
+
import { BlockType, MeldType, HaiType } from '../MahjongConsts';
|
|
7
|
+
import { MentsuAnalyzer } from '../MentsuAnalyzer';
|
|
8
|
+
|
|
9
|
+
export abstract class YakuCheckerBase {
|
|
10
|
+
protected readonly context: YakuContext;
|
|
11
|
+
protected hanMenzen: number;
|
|
12
|
+
protected hanFuro: number;
|
|
13
|
+
protected abstract yakuName: string;
|
|
14
|
+
protected isYakuman: boolean;
|
|
15
|
+
|
|
16
|
+
constructor(context: YakuContext){
|
|
17
|
+
this.context = context;
|
|
18
|
+
this.hanMenzen = 13;
|
|
19
|
+
this.hanFuro = 13;
|
|
20
|
+
this.isYakuman = false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
protected abstract isSatisfied(): boolean;
|
|
24
|
+
|
|
25
|
+
public check(): boolean {
|
|
26
|
+
return this.isSatisfied();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public getHan(): number {
|
|
30
|
+
return this.isMenzen() ? this.hanMenzen : this.hanFuro;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public getName(): string {
|
|
34
|
+
return this.yakuName;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
//グループ内にマンズ、ピンズ、ソーズすべてが含まれているかどうかを調べる
|
|
38
|
+
protected hasThreeTypesInGroups(groups: Map<string, IMentsu[]>): boolean {
|
|
39
|
+
for(const group of groups.values()){
|
|
40
|
+
const types = new Set(group.map(m => m.minHai.type));
|
|
41
|
+
if(types.has(HaiType.MANZU) && types.has(HaiType.PINZU) && types.has(HaiType.SOUZU)) return true;
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//三色関係の判定
|
|
47
|
+
protected checkSanshoku(
|
|
48
|
+
filter: (m: IMentsu) => boolean
|
|
49
|
+
): boolean {
|
|
50
|
+
const groups = this.getGroupsMentsu(filter, (m) => `${m.minHai.num}-${m.maxHai.num}`);
|
|
51
|
+
return this.hasThreeTypesInGroups(groups);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
//アガリ牌を除いた手牌の待ちの数を計算する
|
|
55
|
+
protected calculateMachiCount(): number {
|
|
56
|
+
const haisWithoutAgari = this.getHaisWithoutAgariHai();
|
|
57
|
+
const machi = new MachiCalculator(haisWithoutAgari).calculate();
|
|
58
|
+
return machi.length;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
//手牌と鳴き牌を含めた牌のコピー配列を作成
|
|
62
|
+
protected getAllTiles(): Hai[] {
|
|
63
|
+
return this.context.hand.getAllTiles();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
//全く同じ順子のグループ数を数える
|
|
67
|
+
protected countSameShuntsuGroups(): number {
|
|
68
|
+
const groups = this.getGroupsMentsu(
|
|
69
|
+
(m) => m.isShuntsu(),
|
|
70
|
+
(m) => `${m.minHai.getId()}-${m.maxHai.getId()}`
|
|
71
|
+
);
|
|
72
|
+
let count = 0;
|
|
73
|
+
for(const group of groups.values()){
|
|
74
|
+
if(group.length >= 2){
|
|
75
|
+
count += Math.floor(group.length / 2);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return count;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
//面子ごとにグループを作成する
|
|
82
|
+
protected getGroupsMentsu(
|
|
83
|
+
filter: (m: IMentsu) => boolean,
|
|
84
|
+
keySelector: (m: IMentsu) => string
|
|
85
|
+
): Map<string, IMentsu[]> {
|
|
86
|
+
const mentsuList: IMentsu[] = new MentsuAnalyzer(this.context.block.getBlockHais(), this.context.melds).getAll();
|
|
87
|
+
const filteredMentsu = mentsuList.filter(filter);
|
|
88
|
+
const groups = new Map<string, IMentsu[]>();
|
|
89
|
+
for(const mentsu of filteredMentsu){
|
|
90
|
+
const key = keySelector(mentsu);
|
|
91
|
+
if(!groups.has(key)){
|
|
92
|
+
groups.set(key, []);
|
|
93
|
+
}
|
|
94
|
+
groups.get(key)?.push(mentsu);
|
|
95
|
+
}
|
|
96
|
+
return groups;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
//指定された牌の数を手牌と鳴き牌から数える
|
|
100
|
+
protected countTargetBlocks(blockedhaislist: BlockHaisList, target: number[]) {
|
|
101
|
+
const targetNums = new Set(target);
|
|
102
|
+
const foundTargets = new Set<number>();
|
|
103
|
+
let mentsuCount = 0;
|
|
104
|
+
let jantoCount = 0;
|
|
105
|
+
for(const blockhais of blockedhaislist){
|
|
106
|
+
const id = blockhais.getHais()[0].getId();
|
|
107
|
+
if(targetNums.has(id)){
|
|
108
|
+
foundTargets.add(id);
|
|
109
|
+
if(blockhais.getType() === BlockType.KOTSU) mentsuCount++;
|
|
110
|
+
if(blockhais.getType() === BlockType.JANTO) jantoCount++;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
for(const meld of this.context.melds){
|
|
114
|
+
const id = meld.getHais()[0].getId();
|
|
115
|
+
if(targetNums.has(id)){
|
|
116
|
+
//ポン、カンであれば面子としてカウント
|
|
117
|
+
if(meld.getType() !== MeldType.CHI){
|
|
118
|
+
foundTargets.add(id);
|
|
119
|
+
mentsuCount++;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return {foundTargets, mentsuCount, jantoCount};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
//暗刻の数を数える
|
|
128
|
+
protected countAnko(): number {
|
|
129
|
+
let ankoCount = 0;
|
|
130
|
+
for(const blockhais of this.context.block){
|
|
131
|
+
if(blockhais.getType() === BlockType.KOTSU){
|
|
132
|
+
//ロンであり刻子にアガリ牌が含まれている場合暗刻として認めない
|
|
133
|
+
if(!this.context.ctx.isTsumo && blockhais.getHais().some(h => h.getId() == this.context.ctx.agariHai.getId())) continue;
|
|
134
|
+
ankoCount++;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
for(const meld of this.context.melds){
|
|
138
|
+
if(meld.getType() === MeldType.ANKAN) ankoCount++;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return ankoCount;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
//刻子の数を数える
|
|
145
|
+
protected countKotsu(): number {
|
|
146
|
+
let kotsuCount = 0;
|
|
147
|
+
const allMentsu: IMentsu[] = [...this.context.block, ...this.context.melds];
|
|
148
|
+
|
|
149
|
+
allMentsu.forEach(mentsu => {
|
|
150
|
+
if(mentsu.isKotsuOrKantsu()) kotsuCount++;
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
return kotsuCount;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
//槓子の数を数える
|
|
157
|
+
protected countKantsu(): number {
|
|
158
|
+
let kantsuCount = 0;
|
|
159
|
+
for(const meld of this.context.melds){
|
|
160
|
+
if(meld.getType() === MeldType.ANKAN || meld.getType() === MeldType.MINKAN) kantsuCount++;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return kantsuCount;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
//面前かどうか
|
|
167
|
+
protected isMenzen(): boolean {
|
|
168
|
+
return this.context.hand.isMenzen();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
//アガリ牌を除いた手牌のコピーを作成
|
|
172
|
+
protected getHaisWithoutAgariHai(): Hai[] {
|
|
173
|
+
const hais = this.context.hais.map(h => h.clone());
|
|
174
|
+
const agariId = this.context.ctx.agariHai.getId();
|
|
175
|
+
const index = this.context.hais.findIndex(h => h.getId() === agariId);
|
|
176
|
+
hais.splice(index, 1);
|
|
177
|
+
|
|
178
|
+
return hais;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Hai } from '../Hai';
|
|
2
|
+
import { Meld } from '../Meld';
|
|
3
|
+
import { PlayerHand } from '../PlayerHand';
|
|
4
|
+
import { PlayerContext } from '../PlayerContext';
|
|
5
|
+
import { BlockHaisList } from '../BlockHaisList';
|
|
6
|
+
|
|
7
|
+
export class YakuContext {
|
|
8
|
+
readonly hand: PlayerHand;
|
|
9
|
+
readonly block: BlockHaisList;
|
|
10
|
+
readonly ctx: PlayerContext;
|
|
11
|
+
|
|
12
|
+
constructor(hand: PlayerHand, ctx: PlayerContext, block: BlockHaisList){
|
|
13
|
+
this.hand = hand;
|
|
14
|
+
this.ctx = ctx;
|
|
15
|
+
this.block = block;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get hais(): Hai[]{
|
|
19
|
+
return this.hand.getTehai();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get melds(): Meld[]{
|
|
23
|
+
return this.hand.getFuro();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { WinEvent } from '../MahjongConsts';
|
|
2
|
+
import { YakuContext } from './YakuContext';
|
|
3
|
+
import { YakumanCheckers } from './index';
|
|
4
|
+
|
|
5
|
+
export class YakumanChecker{
|
|
6
|
+
protected readonly context: YakuContext;
|
|
7
|
+
|
|
8
|
+
constructor(context: YakuContext){
|
|
9
|
+
this.context = context;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//役判定
|
|
13
|
+
check(): Map<string, number> {
|
|
14
|
+
const excludes = [
|
|
15
|
+
{ main: "純正九蓮宝燈", sub: "九蓮宝燈"},
|
|
16
|
+
{ main: "四暗刻単騎", sub: "四暗刻"},
|
|
17
|
+
{ main: "国士無双13面待ち", sub: "国士無双"},
|
|
18
|
+
];
|
|
19
|
+
const yaku_map: Map<string, number> = new Map();
|
|
20
|
+
for(const Checker of YakumanCheckers) {
|
|
21
|
+
const checker = Checker(this.context);
|
|
22
|
+
if(checker.check()) yaku_map.set(checker.getName(), checker.getHan());
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
for(const { main, sub } of excludes) {
|
|
26
|
+
if(yaku_map.has(main)) yaku_map.delete(sub);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if(this.context.ctx.event === WinEvent.TENHO) yaku_map.set("天和", 13);
|
|
30
|
+
if(this.context.ctx.event === WinEvent.CHIHO) yaku_map.set("地和", 13);
|
|
31
|
+
|
|
32
|
+
return yaku_map;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { YakuCheckerBase } from './YakuCheckerBase';
|
|
2
|
+
import { YakuContext } from './YakuContext';
|
|
3
|
+
import { TsuisoChecker } from './yakuman/TsuisoChecker';
|
|
4
|
+
import { ChinrotoChecker } from './yakuman/ChinrotoChecker';
|
|
5
|
+
import { RyuisoChecker } from './yakuman/RyuisoChecker';
|
|
6
|
+
import { SukantsuChecker } from './yakuman/SukantsuChecker';
|
|
7
|
+
import { ChurenChecker } from './yakuman/ChurenChecker';
|
|
8
|
+
import { Churen9Checker } from './yakuman/Churen9Checker';
|
|
9
|
+
import { SuankoChecker } from './yakuman/SuankoChecker';
|
|
10
|
+
import { SuankoTankiChecker } from './yakuman/SuankoTankiChecker';
|
|
11
|
+
import { KokushiChecker } from './yakuman/KokushiChecker';
|
|
12
|
+
import { Kokushi13Checker } from './yakuman/Kokushi13Checker';
|
|
13
|
+
import { DaisushiChecker } from './yakuman/DaisushiChecker';
|
|
14
|
+
import { ShosushiChecker } from './yakuman/ShosushiChecker';
|
|
15
|
+
import { DaisangenChecker } from './yakuman/DaisangenChecker';
|
|
16
|
+
|
|
17
|
+
import { ChinitsuChecker } from './normal/ChinitsuChecker';
|
|
18
|
+
import { HonitsuChecker } from './normal/HonitsuChecker';
|
|
19
|
+
import { JunchanChecker } from './normal/JunchanChecker';
|
|
20
|
+
import { HonchanChecker } from './normal/HonchanChecker';
|
|
21
|
+
import { HonrotoChecker } from './normal/HonrotoChecker';
|
|
22
|
+
import { RyanpekoChecker } from './normal/RyanpekoChecker';
|
|
23
|
+
import { ChitoitsuChecker } from './normal/ChitoitsuChecker';
|
|
24
|
+
import { SanankoChecker } from './normal/SanankoChecker';
|
|
25
|
+
import { ToitoiChecker } from './normal/ToitoiChecker';
|
|
26
|
+
import { IipekoChecker } from './normal/IipekoChecker';
|
|
27
|
+
import { ShosangenChecker } from './normal/ShosangenChecker';
|
|
28
|
+
import { SanshokuChecker } from './normal/SanshokuChecker';
|
|
29
|
+
import { DoukouChecker } from './normal/DoukouChecker';
|
|
30
|
+
import { IttsuuChecker } from './normal/IttsuuChecker';
|
|
31
|
+
import { TanyaoChecker } from './normal/TanyaoChecker';
|
|
32
|
+
import { SankantsuChecker } from './normal/SankantsuChecker';
|
|
33
|
+
import { MenzenTsumoChecker } from './normal/MenzenTsumoChecker';
|
|
34
|
+
import { PinfuChecker } from './normal/PinfuChecker';
|
|
35
|
+
import { RenpuuhaiChecker } from './normal/RenpuuhaiChecker';
|
|
36
|
+
import { YakuhaiChecker } from './normal/YakuhaiChecker';
|
|
37
|
+
import { KazehaiChecker } from './normal/KazehaiChecker';
|
|
38
|
+
|
|
39
|
+
export type YakuCheckerFactory =
|
|
40
|
+
(context: YakuContext) => YakuCheckerBase;
|
|
41
|
+
|
|
42
|
+
export const YakumanCheckers: YakuCheckerFactory[] = [
|
|
43
|
+
ctx => new TsuisoChecker(ctx),
|
|
44
|
+
ctx => new ChinrotoChecker(ctx),
|
|
45
|
+
ctx => new RyuisoChecker(ctx),
|
|
46
|
+
ctx => new SukantsuChecker(ctx),
|
|
47
|
+
ctx => new ChurenChecker(ctx),
|
|
48
|
+
ctx => new Churen9Checker(ctx),
|
|
49
|
+
ctx => new SuankoChecker(ctx),
|
|
50
|
+
ctx => new SuankoTankiChecker(ctx),
|
|
51
|
+
ctx => new KokushiChecker(ctx),
|
|
52
|
+
ctx => new Kokushi13Checker(ctx),
|
|
53
|
+
ctx => new DaisushiChecker(ctx),
|
|
54
|
+
ctx => new ShosushiChecker(ctx),
|
|
55
|
+
ctx => new DaisangenChecker(ctx),
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
export const NormalYakuCheckers: YakuCheckerFactory[] = [
|
|
59
|
+
ctx => new ChinitsuChecker(ctx),
|
|
60
|
+
ctx => new HonitsuChecker(ctx),
|
|
61
|
+
ctx => new JunchanChecker(ctx),
|
|
62
|
+
ctx => new HonchanChecker(ctx),
|
|
63
|
+
ctx => new HonrotoChecker(ctx),
|
|
64
|
+
ctx => new RyanpekoChecker(ctx),
|
|
65
|
+
ctx => new ChitoitsuChecker(ctx),
|
|
66
|
+
ctx => new SanankoChecker(ctx),
|
|
67
|
+
ctx => new ToitoiChecker(ctx),
|
|
68
|
+
ctx => new IipekoChecker(ctx),
|
|
69
|
+
ctx => new ShosangenChecker(ctx),
|
|
70
|
+
ctx => new SanshokuChecker(ctx),
|
|
71
|
+
ctx => new DoukouChecker(ctx),
|
|
72
|
+
ctx => new IttsuuChecker(ctx),
|
|
73
|
+
ctx => new TanyaoChecker(ctx),
|
|
74
|
+
ctx => new SankantsuChecker(ctx),
|
|
75
|
+
ctx => new MenzenTsumoChecker(ctx),
|
|
76
|
+
ctx => new PinfuChecker(ctx),
|
|
77
|
+
ctx => new RenpuuhaiChecker(ctx),
|
|
78
|
+
ctx => new KazehaiChecker(ctx, "自風牌", ctx.ctx.playerWind, ctx.ctx.roundWind),
|
|
79
|
+
ctx => new KazehaiChecker(ctx, "場風牌", ctx.ctx.roundWind, ctx.ctx.playerWind),
|
|
80
|
+
ctx => new YakuhaiChecker(ctx, 32, "白"),
|
|
81
|
+
ctx => new YakuhaiChecker(ctx, 33, "發"),
|
|
82
|
+
ctx => new YakuhaiChecker(ctx, 34, "中"),
|
|
83
|
+
];
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { YakuContext } from '../YakuContext';
|
|
2
|
+
import { YakuCheckerBase } from '../YakuCheckerBase';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export class ChinitsuChecker extends YakuCheckerBase{
|
|
6
|
+
protected yakuName: string = "清一色";
|
|
7
|
+
|
|
8
|
+
constructor(context: YakuContext){
|
|
9
|
+
super(context);
|
|
10
|
+
this.hanMenzen = 6;
|
|
11
|
+
this.hanFuro = 5;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
protected isSatisfied(): boolean {
|
|
15
|
+
const allTiles = this.getAllTiles();
|
|
16
|
+
if(allTiles.length === 0) return false;
|
|
17
|
+
const suitType = allTiles[0].type;
|
|
18
|
+
|
|
19
|
+
return allTiles.every(h => h.type === suitType);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public isChinitsu(): boolean {
|
|
23
|
+
return this.isSatisfied();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { YakuContext } from '../YakuContext';
|
|
2
|
+
import { YakuCheckerBase } from '../YakuCheckerBase';
|
|
3
|
+
import { BlockType } from '../../MahjongConsts';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export class ChitoitsuChecker extends YakuCheckerBase{
|
|
7
|
+
protected yakuName: string = "七対子";
|
|
8
|
+
|
|
9
|
+
constructor(context: YakuContext){
|
|
10
|
+
super(context);
|
|
11
|
+
this.hanMenzen = 2;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
protected isSatisfied(): boolean {
|
|
15
|
+
if(!this.isMenzen()) return false;
|
|
16
|
+
|
|
17
|
+
return this.context.block.getBlockHais().length === 7
|
|
18
|
+
&& this.context.block.getBlockHais().every(block => block.getType() === BlockType.CHITOI);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { YakuContext } from '../YakuContext';
|
|
2
|
+
import { YakuCheckerBase } from '../YakuCheckerBase';
|
|
3
|
+
|
|
4
|
+
export class DoukouChecker extends YakuCheckerBase{
|
|
5
|
+
protected yakuName: string = "三色同刻";
|
|
6
|
+
|
|
7
|
+
constructor(context: YakuContext){
|
|
8
|
+
super(context);
|
|
9
|
+
this.hanMenzen = 2;
|
|
10
|
+
this.hanFuro = 2;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
protected isSatisfied(): boolean {
|
|
14
|
+
return this.checkSanshoku((m) => m.isKotsuOrKantsu());
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { YakuContext } from '../YakuContext';
|
|
2
|
+
import { YakuCheckerBase } from '../YakuCheckerBase';
|
|
3
|
+
import { IMentsu } from '../../IMentsu';
|
|
4
|
+
import { MentsuAnalyzer } from '../../MentsuAnalyzer';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export class HonchanChecker extends YakuCheckerBase{
|
|
8
|
+
protected yakuName: string = "混全帯么九";
|
|
9
|
+
|
|
10
|
+
constructor(context: YakuContext){
|
|
11
|
+
super(context);
|
|
12
|
+
this.hanMenzen = 2;
|
|
13
|
+
this.hanFuro = 1;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
protected isSatisfied(): boolean {
|
|
17
|
+
const allMentsu: IMentsu[] = new MentsuAnalyzer(this.context.block.getBlockHais(), this.context.melds).getAll();
|
|
18
|
+
const allYaochu = allMentsu.every(mentsu => (mentsu.hasRoutouHai() || mentsu.hasJihai()));
|
|
19
|
+
const hasShuntsu = allMentsu.some(mentsu => mentsu.isShuntsu());
|
|
20
|
+
const hasJihai = allMentsu.some(mentsu => mentsu.hasJihai());
|
|
21
|
+
|
|
22
|
+
return allYaochu && hasShuntsu && hasJihai;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { YakuContext } from '../YakuContext';
|
|
2
|
+
import { YakuCheckerBase } from '../YakuCheckerBase';
|
|
3
|
+
import { HaiType } from '../../MahjongConsts';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export class HonitsuChecker extends YakuCheckerBase{
|
|
7
|
+
protected yakuName: string = "混一色";
|
|
8
|
+
|
|
9
|
+
constructor(context: YakuContext){
|
|
10
|
+
super(context);
|
|
11
|
+
this.hanMenzen = 3;
|
|
12
|
+
this.hanFuro = 2;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
protected isSatisfied(): boolean {
|
|
16
|
+
const allTiles = this.getAllTiles();
|
|
17
|
+
const suits = new Set(allTiles.map(h => h.type));
|
|
18
|
+
return suits.size === 2 && suits.has(HaiType.JIHAI);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { YakuContext } from '../YakuContext';
|
|
2
|
+
import { YakuCheckerBase } from '../YakuCheckerBase';
|
|
3
|
+
import { IMentsu } from '../../IMentsu';
|
|
4
|
+
import { MentsuAnalyzer } from '../../MentsuAnalyzer';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export class HonrotoChecker extends YakuCheckerBase{
|
|
8
|
+
protected yakuName: string = "混老頭";
|
|
9
|
+
|
|
10
|
+
constructor(context: YakuContext){
|
|
11
|
+
super(context);
|
|
12
|
+
this.hanMenzen = 2;
|
|
13
|
+
this.hanFuro = 2;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
protected isSatisfied(): boolean {
|
|
17
|
+
const allMentsu: IMentsu[] = new MentsuAnalyzer(this.context.block.getBlockHais(), this.context.melds).getAll();
|
|
18
|
+
const allYaochu = allMentsu.every(mentsu => (mentsu.hasRoutouHai() || mentsu.hasJihai()));
|
|
19
|
+
const allNotShuntsu = allMentsu.every(mentsu => !mentsu.isShuntsu());
|
|
20
|
+
|
|
21
|
+
return allYaochu && allNotShuntsu;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { YakuContext } from '../YakuContext';
|
|
2
|
+
import { YakuCheckerBase } from '../YakuCheckerBase';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export class IipekoChecker extends YakuCheckerBase{
|
|
6
|
+
protected yakuName: string = "一盃口";
|
|
7
|
+
|
|
8
|
+
constructor(context: YakuContext){
|
|
9
|
+
super(context);
|
|
10
|
+
this.hanMenzen = 1;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
protected isSatisfied(): boolean {
|
|
14
|
+
if(!this.isMenzen()) return false;
|
|
15
|
+
return this.countSameShuntsuGroups() === 1;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { YakuContext } from '../YakuContext';
|
|
2
|
+
import { YakuCheckerBase } from '../YakuCheckerBase';
|
|
3
|
+
import { HaiType } from '../../MahjongConsts';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export class IttsuuChecker extends YakuCheckerBase{
|
|
8
|
+
protected yakuName: string = "一気通貫";
|
|
9
|
+
|
|
10
|
+
constructor(context: YakuContext){
|
|
11
|
+
super(context);
|
|
12
|
+
this.hanMenzen = 2;
|
|
13
|
+
this.hanFuro = 1;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
protected isSatisfied(): boolean {
|
|
17
|
+
const shuntsuGroups = this.getGroupsMentsu(
|
|
18
|
+
(m) => m.isShuntsu(),
|
|
19
|
+
(m) => m.minHai.type.toString()
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
for(const group of shuntsuGroups.values()){
|
|
23
|
+
const hai123 = group.some(m => m.minHai.num === 1 && m.maxHai.num === 3);
|
|
24
|
+
const hai456 = group.some(m => m.minHai.num === 4 && m.maxHai.num === 6);
|
|
25
|
+
const hai789 = group.some(m => m.minHai.num === 7 && m.maxHai.num === 9);
|
|
26
|
+
|
|
27
|
+
if(hai123 && hai456 && hai789) return true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { YakuContext } from '../YakuContext';
|
|
2
|
+
import { YakuCheckerBase } from '../YakuCheckerBase';
|
|
3
|
+
import { IMentsu } from '../../IMentsu';
|
|
4
|
+
import { MentsuAnalyzer } from '../../MentsuAnalyzer';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export class JunchanChecker extends YakuCheckerBase{
|
|
8
|
+
protected yakuName: string = "純全帯么九";
|
|
9
|
+
|
|
10
|
+
constructor(context: YakuContext){
|
|
11
|
+
super(context);
|
|
12
|
+
this.hanMenzen = 3;
|
|
13
|
+
this.hanFuro = 2;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
protected isSatisfied(): boolean {
|
|
17
|
+
const allMentsu: IMentsu[] = new MentsuAnalyzer(this.context.block.getBlockHais(), this.context.melds).getAll();
|
|
18
|
+
return allMentsu.every(mentsu => mentsu.hasRoutouHai());
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { YakuContext } from '../YakuContext';
|
|
2
|
+
import { YakuCheckerBase } from '../YakuCheckerBase';
|
|
3
|
+
import { MentsuAnalyzer } from '../../MentsuAnalyzer';
|
|
4
|
+
import { Wind } from '../../tileDefs';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export class KazehaiChecker extends YakuCheckerBase{
|
|
8
|
+
protected yakuName: string;
|
|
9
|
+
private requiredWind: Wind;
|
|
10
|
+
private forbiddenWind: Wind;
|
|
11
|
+
|
|
12
|
+
constructor(context: YakuContext, yakuName: string, requiredWind: Wind, forbiddenWind: Wind){
|
|
13
|
+
super(context);
|
|
14
|
+
this.hanMenzen = 1;
|
|
15
|
+
this.hanFuro = 1;
|
|
16
|
+
this.requiredWind = requiredWind;
|
|
17
|
+
this.forbiddenWind = forbiddenWind;
|
|
18
|
+
this.yakuName = `${yakuName}:${requiredWind.name}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
protected isSatisfied(): boolean {
|
|
22
|
+
const analyzer = new MentsuAnalyzer(this.context.block.getBlockHais(), this.context.melds);
|
|
23
|
+
return analyzer.hasSingleWindMentsu(m => m.isKotsuOrKantsu(), this.requiredWind, this.forbiddenWind);
|
|
24
|
+
}
|
|
25
|
+
}
|