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.
Files changed (332) hide show
  1. package/.github/workflows/qlty-coverage.yml +36 -0
  2. package/dist/BlockDivider.d.ts +11 -0
  3. package/dist/BlockDivider.d.ts.map +1 -0
  4. package/dist/BlockDivider.js +114 -0
  5. package/dist/BlockDivider.js.map +1 -0
  6. package/dist/BlockHais.d.ts +26 -0
  7. package/dist/BlockHais.d.ts.map +1 -0
  8. package/dist/BlockHais.js +77 -0
  9. package/dist/BlockHais.js.map +1 -0
  10. package/dist/BlockHaisList.d.ts +19 -0
  11. package/dist/BlockHaisList.d.ts.map +1 -0
  12. package/dist/BlockHaisList.js +85 -0
  13. package/dist/BlockHaisList.js.map +1 -0
  14. package/dist/Hai.d.ts +16 -0
  15. package/dist/Hai.d.ts.map +1 -0
  16. package/dist/Hai.js +71 -0
  17. package/dist/Hai.js.map +1 -0
  18. package/dist/Hais.d.ts +15 -0
  19. package/dist/Hais.d.ts.map +1 -0
  20. package/dist/Hais.js +44 -0
  21. package/dist/Hais.js.map +1 -0
  22. package/dist/IMentsu.d.ts +20 -0
  23. package/dist/IMentsu.d.ts.map +1 -0
  24. package/dist/IMentsu.js +3 -0
  25. package/dist/IMentsu.js.map +1 -0
  26. package/dist/MachiCalculator.d.ts +7 -0
  27. package/dist/MachiCalculator.d.ts.map +1 -0
  28. package/dist/MachiCalculator.js +25 -0
  29. package/dist/MachiCalculator.js.map +1 -0
  30. package/dist/MahjongConsts.d.ts +39 -0
  31. package/dist/MahjongConsts.d.ts.map +1 -0
  32. package/dist/MahjongConsts.js +54 -0
  33. package/dist/MahjongConsts.js.map +1 -0
  34. package/dist/Meld.d.ts +25 -0
  35. package/dist/Meld.d.ts.map +1 -0
  36. package/dist/Meld.js +72 -0
  37. package/dist/Meld.js.map +1 -0
  38. package/dist/Melds.d.ts +9 -0
  39. package/dist/Melds.d.ts.map +1 -0
  40. package/dist/Melds.js +18 -0
  41. package/dist/Melds.js.map +1 -0
  42. package/dist/MentsuAnalyzer.d.ts +11 -0
  43. package/dist/MentsuAnalyzer.d.ts.map +1 -0
  44. package/dist/MentsuAnalyzer.js +23 -0
  45. package/dist/MentsuAnalyzer.js.map +1 -0
  46. package/dist/PlayerContext.d.ts +28 -0
  47. package/dist/PlayerContext.d.ts.map +1 -0
  48. package/dist/PlayerContext.js +28 -0
  49. package/dist/PlayerContext.js.map +1 -0
  50. package/dist/PlayerHand.d.ts +12 -0
  51. package/dist/PlayerHand.d.ts.map +1 -0
  52. package/dist/PlayerHand.js +28 -0
  53. package/dist/PlayerHand.js.map +1 -0
  54. package/dist/index.d.ts +12 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +26 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/tensuu/FuCalculator.d.ts +15 -0
  59. package/dist/tensuu/FuCalculator.d.ts.map +1 -0
  60. package/dist/tensuu/FuCalculator.js +104 -0
  61. package/dist/tensuu/FuCalculator.js.map +1 -0
  62. package/dist/tensuu/FuDetail.d.ts +8 -0
  63. package/dist/tensuu/FuDetail.d.ts.map +1 -0
  64. package/dist/tensuu/FuDetail.js +15 -0
  65. package/dist/tensuu/FuDetail.js.map +1 -0
  66. package/dist/tensuu/ScoreResolver.d.ts +12 -0
  67. package/dist/tensuu/ScoreResolver.d.ts.map +1 -0
  68. package/dist/tensuu/ScoreResolver.js +33 -0
  69. package/dist/tensuu/ScoreResolver.js.map +1 -0
  70. package/dist/tensuu/ScoreResult.d.ts +11 -0
  71. package/dist/tensuu/ScoreResult.d.ts.map +1 -0
  72. package/dist/tensuu/ScoreResult.js +19 -0
  73. package/dist/tensuu/ScoreResult.js.map +1 -0
  74. package/dist/tensuu/TensuuCalculator.d.ts +13 -0
  75. package/dist/tensuu/TensuuCalculator.d.ts.map +1 -0
  76. package/dist/tensuu/TensuuCalculator.js +39 -0
  77. package/dist/tensuu/TensuuCalculator.js.map +1 -0
  78. package/dist/tensuu/TensuuResult.d.ts +15 -0
  79. package/dist/tensuu/TensuuResult.d.ts.map +1 -0
  80. package/dist/tensuu/TensuuResult.js +19 -0
  81. package/dist/tensuu/TensuuResult.js.map +1 -0
  82. package/dist/tileDefs.d.ts +42 -0
  83. package/dist/tileDefs.d.ts.map +1 -0
  84. package/dist/tileDefs.js +23 -0
  85. package/dist/tileDefs.js.map +1 -0
  86. package/dist/yaku/NormalYakuChecker.d.ts +7 -0
  87. package/dist/yaku/NormalYakuChecker.d.ts.map +1 -0
  88. package/dist/yaku/NormalYakuChecker.js +37 -0
  89. package/dist/yaku/NormalYakuChecker.js.map +1 -0
  90. package/dist/yaku/YakuChecker.d.ts +7 -0
  91. package/dist/yaku/YakuChecker.d.ts.map +1 -0
  92. package/dist/yaku/YakuChecker.js +27 -0
  93. package/dist/yaku/YakuChecker.js.map +1 -0
  94. package/dist/yaku/YakuCheckerBase.d.ts +33 -0
  95. package/dist/yaku/YakuCheckerBase.d.ts.map +1 -0
  96. package/dist/yaku/YakuCheckerBase.js +154 -0
  97. package/dist/yaku/YakuCheckerBase.js.map +1 -0
  98. package/dist/yaku/YakuContext.d.ts +14 -0
  99. package/dist/yaku/YakuContext.d.ts.map +1 -0
  100. package/dist/yaku/YakuContext.js +21 -0
  101. package/dist/yaku/YakuContext.js.map +1 -0
  102. package/dist/yaku/YakumanChecker.d.ts +7 -0
  103. package/dist/yaku/YakumanChecker.d.ts.map +1 -0
  104. package/dist/yaku/YakumanChecker.js +36 -0
  105. package/dist/yaku/YakumanChecker.js.map +1 -0
  106. package/dist/yaku/index.d.ts +6 -0
  107. package/dist/yaku/index.d.ts.map +1 -0
  108. package/dist/yaku/index.js +79 -0
  109. package/dist/yaku/index.js.map +1 -0
  110. package/dist/yaku/normal/ChinitsuChecker.d.ts +9 -0
  111. package/dist/yaku/normal/ChinitsuChecker.d.ts.map +1 -0
  112. package/dist/yaku/normal/ChinitsuChecker.js +24 -0
  113. package/dist/yaku/normal/ChinitsuChecker.js.map +1 -0
  114. package/dist/yaku/normal/ChitoitsuChecker.d.ts +8 -0
  115. package/dist/yaku/normal/ChitoitsuChecker.d.ts.map +1 -0
  116. package/dist/yaku/normal/ChitoitsuChecker.js +20 -0
  117. package/dist/yaku/normal/ChitoitsuChecker.js.map +1 -0
  118. package/dist/yaku/normal/DoukouChecker.d.ts +8 -0
  119. package/dist/yaku/normal/DoukouChecker.d.ts.map +1 -0
  120. package/dist/yaku/normal/DoukouChecker.js +17 -0
  121. package/dist/yaku/normal/DoukouChecker.js.map +1 -0
  122. package/dist/yaku/normal/HonchanChecker.d.ts +8 -0
  123. package/dist/yaku/normal/HonchanChecker.d.ts.map +1 -0
  124. package/dist/yaku/normal/HonchanChecker.js +22 -0
  125. package/dist/yaku/normal/HonchanChecker.js.map +1 -0
  126. package/dist/yaku/normal/HonitsuChecker.d.ts +8 -0
  127. package/dist/yaku/normal/HonitsuChecker.d.ts.map +1 -0
  128. package/dist/yaku/normal/HonitsuChecker.js +20 -0
  129. package/dist/yaku/normal/HonitsuChecker.js.map +1 -0
  130. package/dist/yaku/normal/HonrotoChecker.d.ts +8 -0
  131. package/dist/yaku/normal/HonrotoChecker.d.ts.map +1 -0
  132. package/dist/yaku/normal/HonrotoChecker.js +21 -0
  133. package/dist/yaku/normal/HonrotoChecker.js.map +1 -0
  134. package/dist/yaku/normal/IipekoChecker.d.ts +8 -0
  135. package/dist/yaku/normal/IipekoChecker.d.ts.map +1 -0
  136. package/dist/yaku/normal/IipekoChecker.js +18 -0
  137. package/dist/yaku/normal/IipekoChecker.js.map +1 -0
  138. package/dist/yaku/normal/IttsuuChecker.d.ts +8 -0
  139. package/dist/yaku/normal/IttsuuChecker.d.ts.map +1 -0
  140. package/dist/yaku/normal/IttsuuChecker.js +25 -0
  141. package/dist/yaku/normal/IttsuuChecker.js.map +1 -0
  142. package/dist/yaku/normal/JunchanChecker.d.ts +8 -0
  143. package/dist/yaku/normal/JunchanChecker.d.ts.map +1 -0
  144. package/dist/yaku/normal/JunchanChecker.js +19 -0
  145. package/dist/yaku/normal/JunchanChecker.js.map +1 -0
  146. package/dist/yaku/normal/KazehaiChecker.d.ts +11 -0
  147. package/dist/yaku/normal/KazehaiChecker.d.ts.map +1 -0
  148. package/dist/yaku/normal/KazehaiChecker.js +24 -0
  149. package/dist/yaku/normal/KazehaiChecker.js.map +1 -0
  150. package/dist/yaku/normal/MenzenTsumoChecker.d.ts +8 -0
  151. package/dist/yaku/normal/MenzenTsumoChecker.d.ts.map +1 -0
  152. package/dist/yaku/normal/MenzenTsumoChecker.js +16 -0
  153. package/dist/yaku/normal/MenzenTsumoChecker.js.map +1 -0
  154. package/dist/yaku/normal/PinfuChecker.d.ts +8 -0
  155. package/dist/yaku/normal/PinfuChecker.d.ts.map +1 -0
  156. package/dist/yaku/normal/PinfuChecker.js +30 -0
  157. package/dist/yaku/normal/PinfuChecker.js.map +1 -0
  158. package/dist/yaku/normal/RenpuuhaiChecker.d.ts +8 -0
  159. package/dist/yaku/normal/RenpuuhaiChecker.d.ts.map +1 -0
  160. package/dist/yaku/normal/RenpuuhaiChecker.js +22 -0
  161. package/dist/yaku/normal/RenpuuhaiChecker.js.map +1 -0
  162. package/dist/yaku/normal/RyanpekoChecker.d.ts +8 -0
  163. package/dist/yaku/normal/RyanpekoChecker.d.ts.map +1 -0
  164. package/dist/yaku/normal/RyanpekoChecker.js +18 -0
  165. package/dist/yaku/normal/RyanpekoChecker.js.map +1 -0
  166. package/dist/yaku/normal/SanankoChecker.d.ts +8 -0
  167. package/dist/yaku/normal/SanankoChecker.d.ts.map +1 -0
  168. package/dist/yaku/normal/SanankoChecker.js +17 -0
  169. package/dist/yaku/normal/SanankoChecker.js.map +1 -0
  170. package/dist/yaku/normal/SankantsuChecker.d.ts +8 -0
  171. package/dist/yaku/normal/SankantsuChecker.d.ts.map +1 -0
  172. package/dist/yaku/normal/SankantsuChecker.js +17 -0
  173. package/dist/yaku/normal/SankantsuChecker.js.map +1 -0
  174. package/dist/yaku/normal/SanshokuChecker.d.ts +8 -0
  175. package/dist/yaku/normal/SanshokuChecker.d.ts.map +1 -0
  176. package/dist/yaku/normal/SanshokuChecker.js +17 -0
  177. package/dist/yaku/normal/SanshokuChecker.js.map +1 -0
  178. package/dist/yaku/normal/ShosangenChecker.d.ts +8 -0
  179. package/dist/yaku/normal/ShosangenChecker.d.ts.map +1 -0
  180. package/dist/yaku/normal/ShosangenChecker.js +20 -0
  181. package/dist/yaku/normal/ShosangenChecker.js.map +1 -0
  182. package/dist/yaku/normal/TanyaoChecker.d.ts +8 -0
  183. package/dist/yaku/normal/TanyaoChecker.d.ts.map +1 -0
  184. package/dist/yaku/normal/TanyaoChecker.js +18 -0
  185. package/dist/yaku/normal/TanyaoChecker.js.map +1 -0
  186. package/dist/yaku/normal/ToitoiChecker.d.ts +8 -0
  187. package/dist/yaku/normal/ToitoiChecker.d.ts.map +1 -0
  188. package/dist/yaku/normal/ToitoiChecker.js +17 -0
  189. package/dist/yaku/normal/ToitoiChecker.js.map +1 -0
  190. package/dist/yaku/normal/YakuhaiChecker.d.ts +9 -0
  191. package/dist/yaku/normal/YakuhaiChecker.d.ts.map +1 -0
  192. package/dist/yaku/normal/YakuhaiChecker.js +22 -0
  193. package/dist/yaku/normal/YakuhaiChecker.js.map +1 -0
  194. package/dist/yaku/yakuman/ChinrotoChecker.d.ts +6 -0
  195. package/dist/yaku/yakuman/ChinrotoChecker.d.ts.map +1 -0
  196. package/dist/yaku/yakuman/ChinrotoChecker.js +13 -0
  197. package/dist/yaku/yakuman/ChinrotoChecker.js.map +1 -0
  198. package/dist/yaku/yakuman/Churen9Checker.d.ts +10 -0
  199. package/dist/yaku/yakuman/Churen9Checker.d.ts.map +1 -0
  200. package/dist/yaku/yakuman/Churen9Checker.js +17 -0
  201. package/dist/yaku/yakuman/Churen9Checker.js.map +1 -0
  202. package/dist/yaku/yakuman/ChurenChecker.d.ts +7 -0
  203. package/dist/yaku/yakuman/ChurenChecker.d.ts.map +1 -0
  204. package/dist/yaku/yakuman/ChurenChecker.js +33 -0
  205. package/dist/yaku/yakuman/ChurenChecker.js.map +1 -0
  206. package/dist/yaku/yakuman/DaisangenChecker.d.ts +6 -0
  207. package/dist/yaku/yakuman/DaisangenChecker.d.ts.map +1 -0
  208. package/dist/yaku/yakuman/DaisangenChecker.js +15 -0
  209. package/dist/yaku/yakuman/DaisangenChecker.js.map +1 -0
  210. package/dist/yaku/yakuman/DaisushiChecker.d.ts +8 -0
  211. package/dist/yaku/yakuman/DaisushiChecker.d.ts.map +1 -0
  212. package/dist/yaku/yakuman/DaisushiChecker.js +20 -0
  213. package/dist/yaku/yakuman/DaisushiChecker.js.map +1 -0
  214. package/dist/yaku/yakuman/ExtendedYakumanChecker.d.ts +9 -0
  215. package/dist/yaku/yakuman/ExtendedYakumanChecker.d.ts.map +1 -0
  216. package/dist/yaku/yakuman/ExtendedYakumanChecker.js +18 -0
  217. package/dist/yaku/yakuman/ExtendedYakumanChecker.js.map +1 -0
  218. package/dist/yaku/yakuman/Kokushi13Checker.d.ts +10 -0
  219. package/dist/yaku/yakuman/Kokushi13Checker.d.ts.map +1 -0
  220. package/dist/yaku/yakuman/Kokushi13Checker.js +17 -0
  221. package/dist/yaku/yakuman/Kokushi13Checker.js.map +1 -0
  222. package/dist/yaku/yakuman/KokushiChecker.d.ts +7 -0
  223. package/dist/yaku/yakuman/KokushiChecker.d.ts.map +1 -0
  224. package/dist/yaku/yakuman/KokushiChecker.js +18 -0
  225. package/dist/yaku/yakuman/KokushiChecker.js.map +1 -0
  226. package/dist/yaku/yakuman/RyuisoChecker.d.ts +6 -0
  227. package/dist/yaku/yakuman/RyuisoChecker.d.ts.map +1 -0
  228. package/dist/yaku/yakuman/RyuisoChecker.js +17 -0
  229. package/dist/yaku/yakuman/RyuisoChecker.js.map +1 -0
  230. package/dist/yaku/yakuman/ShosushiChecker.d.ts +6 -0
  231. package/dist/yaku/yakuman/ShosushiChecker.d.ts.map +1 -0
  232. package/dist/yaku/yakuman/ShosushiChecker.js +15 -0
  233. package/dist/yaku/yakuman/ShosushiChecker.js.map +1 -0
  234. package/dist/yaku/yakuman/SuankoChecker.d.ts +7 -0
  235. package/dist/yaku/yakuman/SuankoChecker.d.ts.map +1 -0
  236. package/dist/yaku/yakuman/SuankoChecker.js +17 -0
  237. package/dist/yaku/yakuman/SuankoChecker.js.map +1 -0
  238. package/dist/yaku/yakuman/SuankoTankiChecker.d.ts +8 -0
  239. package/dist/yaku/yakuman/SuankoTankiChecker.d.ts.map +1 -0
  240. package/dist/yaku/yakuman/SuankoTankiChecker.js +28 -0
  241. package/dist/yaku/yakuman/SuankoTankiChecker.js.map +1 -0
  242. package/dist/yaku/yakuman/SukantsuChecker.d.ts +6 -0
  243. package/dist/yaku/yakuman/SukantsuChecker.d.ts.map +1 -0
  244. package/dist/yaku/yakuman/SukantsuChecker.js +12 -0
  245. package/dist/yaku/yakuman/SukantsuChecker.js.map +1 -0
  246. package/dist/yaku/yakuman/TsuisoChecker.d.ts +6 -0
  247. package/dist/yaku/yakuman/TsuisoChecker.d.ts.map +1 -0
  248. package/dist/yaku/yakuman/TsuisoChecker.js +13 -0
  249. package/dist/yaku/yakuman/TsuisoChecker.js.map +1 -0
  250. package/jest.config.js +8 -0
  251. package/modules/BlockDivider.ts +129 -0
  252. package/modules/BlockHais.ts +92 -0
  253. package/modules/BlockHaisList.ts +96 -0
  254. package/modules/Hai.ts +67 -0
  255. package/modules/Hais.ts +49 -0
  256. package/modules/IMentsu.ts +20 -0
  257. package/modules/MachiCalculator.ts +25 -0
  258. package/modules/MahjongConsts.ts +46 -0
  259. package/modules/Meld.ts +85 -0
  260. package/modules/Melds.ts +19 -0
  261. package/modules/MentsuAnalyzer.ts +37 -0
  262. package/modules/PlayerContext.ts +39 -0
  263. package/modules/PlayerHand.ts +32 -0
  264. package/modules/index.ts +11 -0
  265. package/modules/tensuu/FuCalculator.ts +118 -0
  266. package/modules/tensuu/FuDetail.ts +13 -0
  267. package/modules/tensuu/ScoreResolver.ts +35 -0
  268. package/modules/tensuu/ScoreResult.ts +24 -0
  269. package/modules/tensuu/TensuuCalculator.ts +40 -0
  270. package/modules/tensuu/TensuuResult.ts +21 -0
  271. package/modules/tileDefs.ts +24 -0
  272. package/modules/yaku/NormalYakuChecker.ts +31 -0
  273. package/modules/yaku/YakuChecker.ts +29 -0
  274. package/modules/yaku/YakuCheckerBase.ts +180 -0
  275. package/modules/yaku/YakuContext.ts +25 -0
  276. package/modules/yaku/YakumanChecker.ts +34 -0
  277. package/modules/yaku/index.ts +83 -0
  278. package/modules/yaku/normal/ChinitsuChecker.ts +25 -0
  279. package/modules/yaku/normal/ChitoitsuChecker.ts +20 -0
  280. package/modules/yaku/normal/DoukouChecker.ts +16 -0
  281. package/modules/yaku/normal/HonchanChecker.ts +24 -0
  282. package/modules/yaku/normal/HonitsuChecker.ts +20 -0
  283. package/modules/yaku/normal/HonrotoChecker.ts +23 -0
  284. package/modules/yaku/normal/IipekoChecker.ts +17 -0
  285. package/modules/yaku/normal/IttsuuChecker.ts +32 -0
  286. package/modules/yaku/normal/JunchanChecker.ts +20 -0
  287. package/modules/yaku/normal/KazehaiChecker.ts +25 -0
  288. package/modules/yaku/normal/MenzenTsumoChecker.ts +15 -0
  289. package/modules/yaku/normal/PinfuChecker.ts +26 -0
  290. package/modules/yaku/normal/RenpuuhaiChecker.ts +21 -0
  291. package/modules/yaku/normal/RyanpekoChecker.ts +17 -0
  292. package/modules/yaku/normal/SanankoChecker.ts +17 -0
  293. package/modules/yaku/normal/SankantsuChecker.ts +16 -0
  294. package/modules/yaku/normal/SanshokuChecker.ts +16 -0
  295. package/modules/yaku/normal/ShosangenChecker.ts +21 -0
  296. package/modules/yaku/normal/TanyaoChecker.ts +18 -0
  297. package/modules/yaku/normal/ToitoiChecker.ts +17 -0
  298. package/modules/yaku/normal/YakuhaiChecker.ts +22 -0
  299. package/modules/yaku/yakuman/ChinrotoChecker.ts +11 -0
  300. package/modules/yaku/yakuman/Churen9Checker.ts +16 -0
  301. package/modules/yaku/yakuman/ChurenChecker.ts +31 -0
  302. package/modules/yaku/yakuman/DaisangenChecker.ts +14 -0
  303. package/modules/yaku/yakuman/DaisushiChecker.ts +21 -0
  304. package/modules/yaku/yakuman/ExtendedYakumanChecker.ts +18 -0
  305. package/modules/yaku/yakuman/Kokushi13Checker.ts +16 -0
  306. package/modules/yaku/yakuman/KokushiChecker.ts +15 -0
  307. package/modules/yaku/yakuman/RyuisoChecker.ts +16 -0
  308. package/modules/yaku/yakuman/ShosushiChecker.ts +13 -0
  309. package/modules/yaku/yakuman/SuankoChecker.ts +14 -0
  310. package/modules/yaku/yakuman/SuankoTankiChecker.ts +28 -0
  311. package/modules/yaku/yakuman/SukantsuChecker.ts +9 -0
  312. package/modules/yaku/yakuman/TsuisoChecker.ts +10 -0
  313. package/package.json +28 -0
  314. package/tests/fu.test.ts +44 -0
  315. package/tests/machi/chinitsu.ts +137 -0
  316. package/tests/machi/chitoitsu.ts +12 -0
  317. package/tests/machi/kokushi.ts +22 -0
  318. package/tests/machi/maisuu.ts +77 -0
  319. package/tests/machi.test.ts +100 -0
  320. package/tests/machiType.test.ts +93 -0
  321. package/tests/score.test.ts +27 -0
  322. package/tests/tehaiCaseRunner.ts +57 -0
  323. package/tests/tensuu/fu.ts +272 -0
  324. package/tests/tensuu/score.ts +46 -0
  325. package/tests/tensuu/tensuuNum.ts +292 -0
  326. package/tests/tensuuFromNum.test.ts +15 -0
  327. package/tests/testConsts.ts +42 -0
  328. package/tests/toBlock.test.ts +155 -0
  329. package/tests/yaku/normal.ts +1046 -0
  330. package/tests/yaku/yakuman.ts +367 -0
  331. package/tests/yaku.test.ts +28 -0
  332. package/tsconfig.json +23 -0
package/modules/Hai.ts ADDED
@@ -0,0 +1,67 @@
1
+ import { HaiType } from "./MahjongConsts";
2
+ import { TILE } from "./tileDefs";
3
+
4
+ export class Hai{
5
+ private readonly id: number;
6
+
7
+ constructor(id: number){
8
+ this.id = id;
9
+ }
10
+
11
+ get type(): HaiType{
12
+ if((TILE.MANZU as readonly number[]).includes(this.id)) return HaiType.MANZU;
13
+ if((TILE.PINZU as readonly number[]).includes(this.id)) return HaiType.PINZU;
14
+ if((TILE.SOUZU as readonly number[]).includes(this.id)) return HaiType.SOUZU;
15
+ if((TILE.JIHAI as readonly number[]).includes(this.id)) return HaiType.JIHAI;
16
+ return HaiType.BACK;
17
+ }
18
+
19
+ get num(): number{
20
+ if(this.type == HaiType.MANZU) return this.id;
21
+ if(this.type == HaiType.PINZU) return this.id - 9;
22
+ if(this.type == HaiType.SOUZU) return this.id - 18;
23
+ if(this.type == HaiType.JIHAI) return this.id;
24
+ return TILE.BACK;
25
+ }
26
+
27
+ get imageUrl(): string{
28
+ //萬子
29
+ if(this.type === HaiType.MANZU) return `m_${this.num}.png`;
30
+ //筒子
31
+ if(this.type === HaiType.PINZU) return `p_${this.num}.png`;
32
+ //索子
33
+ if(this.type === HaiType.SOUZU) return `s_${this.num}.png`;
34
+ //字牌
35
+ if(this.type === HaiType.JIHAI) return `j_${this.num - 27}.png`;
36
+
37
+ return `back.png`;
38
+ }
39
+
40
+ isRoutouHai(): boolean {
41
+ return (this.num === 1 || this.num === 9) && this.isNumberHai();
42
+ }
43
+
44
+ isNumberHai(): boolean {
45
+ return this.type === HaiType.MANZU || this.type === HaiType.PINZU || this.type === HaiType.SOUZU;
46
+ }
47
+
48
+ isJihai(): boolean {
49
+ return this.type === HaiType.JIHAI;
50
+ }
51
+
52
+ isYaochuHai(): boolean {
53
+ return this.isRoutouHai() || this.isJihai();
54
+ }
55
+
56
+ isChuchanHai(): boolean {
57
+ return !this.isYaochuHai();
58
+ }
59
+
60
+ getId(): number {
61
+ return this.id;
62
+ }
63
+
64
+ clone(): Hai {
65
+ return new Hai(this.id);
66
+ }
67
+ }
@@ -0,0 +1,49 @@
1
+ import {Hai} from './Hai';
2
+
3
+ export class Hais{
4
+ private readonly hais: Hai[];
5
+
6
+ constructor(ids: number[] = []){
7
+ this.hais = ids.map(id => new Hai(id));
8
+ }
9
+
10
+ [Symbol.iterator]() { return this.hais[Symbol.iterator](); }
11
+
12
+ //末尾に追加
13
+ push(id: number){
14
+ this.hais.push(new Hai(id));
15
+ }
16
+
17
+ //末尾を取り除く
18
+ pop(): Hai | undefined {
19
+ return this.hais.pop()
20
+ }
21
+
22
+ //任意の牌を取り除く
23
+ remove(id: number) {
24
+ const index = this.hais.findIndex(h => h.getId() === id);
25
+ if(index !== -1) this.hais.splice(index, 1);
26
+ }
27
+
28
+ //牌を昇順に並び替える
29
+ sort() {
30
+ this.hais.sort((a, b) => a.getId() - b.getId());
31
+ }
32
+
33
+ //指定された牌がいくつあるか数える
34
+ count(id: number): number {
35
+ return this.hais.filter(h => h.getId() === id).length;
36
+ }
37
+
38
+ getHais(): Hai[] {
39
+ return this.hais;
40
+ }
41
+
42
+ get ids(): number[] {
43
+ return this.hais.map(h => h.getId());
44
+ }
45
+
46
+ get length(): number {
47
+ return this.hais.length;
48
+ }
49
+ }
@@ -0,0 +1,20 @@
1
+ import { BlockType, MeldType } from "./MahjongConsts";
2
+ import { Hai } from "./Hai";
3
+ import { Wind } from "./tileDefs";
4
+
5
+ export interface IMentsu {
6
+ getType(): BlockType | MeldType;
7
+ getHais(): Hai[];
8
+ hasRoutouHai(): boolean;
9
+ hasJihai(): boolean;
10
+ isShuntsu(): boolean;
11
+ isKotsuOrKantsu(): boolean;
12
+ isDragon(): boolean;
13
+ isSingleWind(playerWind: Wind): boolean;
14
+ isDoubleWind(playerWind: Wind, roundWind: Wind): boolean
15
+ isYakuhai(playerWind: Wind, roundWind: Wind): boolean
16
+ containsHai(...haiIds: number[]): boolean;
17
+ clone(): IMentsu;
18
+ get minHai(): Hai;
19
+ get maxHai(): Hai;
20
+ }
@@ -0,0 +1,25 @@
1
+ import { Hai } from './Hai';
2
+ import { BlockDivider } from './BlockDivider';
3
+ import { PAI_TYPE_NUM } from './MahjongConsts';
4
+
5
+ export class MachiCalculator{
6
+ private readonly hais: Hai[];
7
+
8
+ constructor(hais: Hai[]){
9
+ this.hais = hais.map(h => h.clone()).sort((a, b) => a.getId() - b.getId());
10
+ }
11
+
12
+ calculate(): number[] {
13
+ const machi: number[] = [];
14
+
15
+ for(let i = 1; i <= PAI_TYPE_NUM; i++){
16
+ const testhais = [...this.hais, new Hai(i)];
17
+ const divided = new BlockDivider(testhais).divide();
18
+ if(divided.length > 0){
19
+ machi.push(i);
20
+ }
21
+ }
22
+
23
+ return machi;
24
+ }
25
+ }
@@ -0,0 +1,46 @@
1
+ //手配の数
2
+ export const TEHAI_NUMBER: number = 14;
3
+ //牌の種類数
4
+ export const PAI_TYPE_NUM: number = 34;
5
+
6
+ //鳴きのタイプ
7
+ export enum MeldType{
8
+ CHI = "chi",
9
+ PON = "pon",
10
+ ANKAN = "ankan",
11
+ MINKAN = "minkan"
12
+ }
13
+ //牌のタイプ
14
+ export enum HaiType{
15
+ MANZU,
16
+ PINZU,
17
+ SOUZU,
18
+ JIHAI,
19
+ BACK
20
+ }
21
+ //ブロックのタイプ
22
+ export enum BlockType{
23
+ JANTO = "janto",
24
+ KOTSU = "kotsu",
25
+ SHUNTSU = "shuntsu",
26
+ CHITOI = "chitoi",
27
+ KOKUSHI = "kokushi"
28
+ }
29
+ //待ちのタイプ
30
+ export enum MachiType{
31
+ TANKI,
32
+ SHANPON,
33
+ RYANMEN,
34
+ KANCHAN,
35
+ PENCHAN,
36
+ }
37
+ //アガリ時に付随する条件式の役
38
+ export enum WinEvent{
39
+ NONE,
40
+ TENHO,
41
+ CHIHO,
42
+ RINSHAN,
43
+ CHANKAN,
44
+ HAITEI,
45
+ HOUTEI
46
+ }
@@ -0,0 +1,85 @@
1
+ import { Hai } from './Hai';
2
+ import { MeldType } from './MahjongConsts';
3
+ import { IMentsu } from './IMentsu';
4
+ import { TILE, Wind } from "./tileDefs";
5
+
6
+ export class Meld implements IMentsu {
7
+ private readonly hais: Hai[];
8
+ private readonly type: MeldType;
9
+
10
+ constructor(hais: Hai[], type: MeldType){
11
+ this.hais = hais;
12
+ this.type = type;
13
+ }
14
+
15
+ static from(haiId: number, type: MeldType): Meld {
16
+ const hai = new Hai(haiId);
17
+ if(type === MeldType.PON){
18
+ return new Meld([hai.clone(), hai.clone(), hai.clone()], type);
19
+ }
20
+ if(type === MeldType.CHI){
21
+ return new Meld([hai.clone(), new Hai(haiId + 1), new Hai(haiId + 2)], type);
22
+ }
23
+ else
24
+ return new Meld([hai.clone(), hai.clone(), hai.clone(), hai.clone()], type);
25
+ }
26
+
27
+ getHais(): Hai[] {
28
+ return this.hais;
29
+ }
30
+
31
+ getType(): MeldType {
32
+ return this.type;
33
+ }
34
+
35
+ hasRoutouHai(): boolean {
36
+ return this.hais.some(h => h.isRoutouHai());
37
+ }
38
+
39
+ hasJihai(): boolean {
40
+ return this.hais.some(h => h.isJihai());
41
+ }
42
+
43
+ isShuntsu(): boolean {
44
+ return this.type === MeldType.CHI;
45
+ }
46
+
47
+ isKotsuOrKantsu(): boolean {
48
+ return this.type === MeldType.PON || this.type === MeldType.ANKAN || this.type === MeldType.MINKAN;
49
+ }
50
+
51
+ isDragon(): boolean {
52
+ return this.containsHai(TILE.DRAGON.WHITE.id, TILE.DRAGON.GREEN.id, TILE.DRAGON.RED.id);
53
+ }
54
+
55
+ isSingleWind(targetWind: Wind): boolean {
56
+ return this.containsHai(targetWind.id);
57
+ }
58
+
59
+ isDoubleWind(playerWind: Wind, roundWind: Wind): boolean {
60
+ return this.isSingleWind(playerWind) && this.isSingleWind(roundWind);
61
+ }
62
+
63
+ isYakuhai(playerWind: Wind, roundWind: Wind): boolean {
64
+ return this.isDragon() ||
65
+ this.isSingleWind(playerWind) ||
66
+ this.isSingleWind(roundWind) ||
67
+ this.isDoubleWind(playerWind, roundWind);
68
+ }
69
+
70
+ containsHai(...haiIds: number[]): boolean {
71
+ return this.hais.some(h => haiIds.includes(h.getId()));
72
+ }
73
+
74
+ clone(): Meld {
75
+ return new Meld(this.hais.map(h => h.clone()), this.type);
76
+ }
77
+
78
+ get minHai(): Hai {
79
+ return this.hais.reduce((min, h) => h.num < min.num ? h : min);
80
+ }
81
+
82
+ get maxHai(): Hai {
83
+ return this.hais.reduce((max, h) => h.num > max.num ? h : max);
84
+ }
85
+ }
@@ -0,0 +1,19 @@
1
+ import {Meld} from "./Meld";
2
+
3
+ export class Melds {
4
+ private readonly melds: Meld[] = [];
5
+
6
+ constructor(melds: Meld[] = []) {
7
+ this.melds = melds;
8
+ }
9
+
10
+ [Symbol.iterator]() { return this.melds[Symbol.iterator](); }
11
+
12
+ add(meld: Meld){
13
+ this.melds.push(meld);
14
+ }
15
+
16
+ get length() {
17
+ return this.melds.length;
18
+ }
19
+ }
@@ -0,0 +1,37 @@
1
+ import { IMentsu } from './IMentsu';
2
+ import { Wind } from './tileDefs';
3
+
4
+ export class MentsuAnalyzer {
5
+ private readonly allMentsu: IMentsu[];
6
+ constructor(block: IMentsu[], melds: IMentsu[]){
7
+ this.allMentsu = [...block, ...melds];
8
+ }
9
+
10
+ getAll(): IMentsu[]{
11
+ return this.allMentsu;
12
+ }
13
+
14
+ hasSingleWindMentsu(
15
+ filter: (m: IMentsu) => boolean,
16
+ requiredWind: Wind,
17
+ forbiddenWind: Wind
18
+ ): boolean {
19
+ return this.allMentsu.some(m => filter(m) && m.isSingleWind(requiredWind) && !m.isSingleWind(forbiddenWind));
20
+ }
21
+
22
+ hasDoubleWindMentsu(
23
+ filter: (m: IMentsu) => boolean,
24
+ playerWind: Wind,
25
+ roundWind: Wind
26
+ ): boolean {
27
+ return this.allMentsu.some(m => filter(m) && m.isDoubleWind(playerWind, roundWind));
28
+ }
29
+
30
+ hasYakuhaiMentsu(
31
+ filter: (m: IMentsu) => boolean,
32
+ playerWind: Wind,
33
+ roundWind: Wind
34
+ ): boolean {
35
+ return this.allMentsu.some(m => filter(m) && m.isYakuhai(playerWind, roundWind));
36
+ }
37
+ }
@@ -0,0 +1,39 @@
1
+ import { Hai } from "./Hai";
2
+ import { WinEvent } from "./MahjongConsts";
3
+ import { Wind } from "./tileDefs";
4
+
5
+ interface UserOptions {
6
+ agariHai: Hai
7
+ isTsumo: boolean;
8
+ playerWind: Wind;
9
+ roundWind: Wind;
10
+ event?: WinEvent;
11
+ riichi?: boolean;
12
+ daburii?: boolean;
13
+ ippatsu?: boolean;
14
+ kuitan?: boolean;
15
+ }
16
+
17
+ export class PlayerContext{
18
+ agariHai: Hai;
19
+ isTsumo: boolean;
20
+ playerWind: Wind;
21
+ roundWind: Wind;
22
+ event: WinEvent;
23
+ riichi: boolean;
24
+ daburii: boolean;
25
+ ippatsu: boolean;
26
+ kuitan: boolean;
27
+
28
+ constructor(options: UserOptions) {
29
+ this.agariHai = options.agariHai;
30
+ this.isTsumo = options.isTsumo;
31
+ this.playerWind = options.playerWind;
32
+ this.roundWind = options.roundWind;
33
+ this.event = options.event ?? WinEvent.NONE;
34
+ this.riichi = options.riichi ?? false;
35
+ this.daburii = options.daburii ?? false;
36
+ this.ippatsu = options.ippatsu ?? false;
37
+ this.kuitan = options.kuitan ?? false;
38
+ }
39
+ }
@@ -0,0 +1,32 @@
1
+ import { Hai } from './Hai';
2
+ import { Meld } from './Meld';
3
+ import { MeldType } from './MahjongConsts';
4
+
5
+ export class PlayerHand {
6
+ private readonly tehai: Hai[];
7
+ private readonly furo: Meld[];
8
+
9
+ constructor(tehai: Hai[], furo: Meld[]){
10
+ this.tehai = tehai;
11
+ this.furo = furo;
12
+ }
13
+
14
+ getTehai(): Hai[] {
15
+ return this.tehai;
16
+ }
17
+
18
+ getFuro(): Meld[] {
19
+ return this.furo;
20
+ }
21
+
22
+ isMenzen(){
23
+ return this.furo.every(meld => meld.getType() === MeldType.ANKAN);
24
+ }
25
+
26
+ getAllTiles(): Hai[] {
27
+ const hais = this.tehai.map(h => h.clone());
28
+ const meldHais = this.furo.flatMap(m => m.getHais().map(h => h.clone()));
29
+ return [...hais, ...meldHais];
30
+ }
31
+
32
+ }
@@ -0,0 +1,11 @@
1
+ export { Hai } from './Hai.js';
2
+ export { Hais } from './Hais.js';
3
+ export { Melds } from './Melds.js';
4
+ export { BlockDivider } from './BlockDivider.js';
5
+ export { PlayerHand } from './PlayerHand.js';
6
+ export { PlayerContext } from './PlayerContext.js';
7
+ export { ScoreResolver } from './tensuu/ScoreResolver.js';
8
+ export { YakuContext } from './yaku/YakuContext.js';
9
+ export { YakuChecker } from './yaku/YakuChecker.js';
10
+ export { TILE } from './tileDefs.js';
11
+ export { ScoreResult } from './tensuu/ScoreResult.js';
@@ -0,0 +1,118 @@
1
+ import { BlockHais } from '../BlockHais';
2
+ import { BlockType, MachiType, MeldType } from '../MahjongConsts';
3
+ import { MentsuAnalyzer } from '../MentsuAnalyzer';
4
+ import { YakuContext } from '../yaku/YakuContext';
5
+ import { FuDetail } from './FuDetail';
6
+
7
+ type MentsuFuSpec = {
8
+ yaochu: {name: string, fu: number};
9
+ chuchan: {name: string, fu: number};
10
+ };
11
+
12
+ const MENTSU_FU_TABLE: Record<string, MentsuFuSpec> = {
13
+ [BlockType.KOTSU]: {
14
+ yaochu: {name: "么九牌暗刻", fu: 8},
15
+ chuchan: {name: "中張牌暗刻", fu: 4}
16
+ },
17
+ [MeldType.PON]: {
18
+ yaochu: {name: "么九牌明刻", fu: 4},
19
+ chuchan: {name: "中張牌明刻", fu: 2}
20
+ },
21
+ [MeldType.MINKAN]: {
22
+ yaochu: {name: "么九牌明槓", fu: 16},
23
+ chuchan: {name: "中張牌明槓", fu: 8}
24
+ },
25
+ [MeldType.ANKAN]: {
26
+ yaochu: {name: "么九牌暗槓", fu: 32},
27
+ chuchan: {name: "中張牌暗槓", fu: 16}
28
+ }
29
+ } as const;
30
+
31
+ export class FuCalculator{
32
+ private readonly context: YakuContext;
33
+ private readonly yaku: Map<string, number>;
34
+
35
+ constructor(context: YakuContext, yaku: Map<string, number>){
36
+ this.context = context;
37
+ this.yaku = yaku;
38
+ }
39
+
40
+ private calcSpecialFu(): FuDetail | null{
41
+ if(this.yaku.has("平和") && this.context.ctx.isTsumo) return new FuDetail("平和ツモ", 20);
42
+ if(this.yaku.has("七対子")) return new FuDetail("七対子", 25);
43
+
44
+ return null;
45
+ }
46
+
47
+ private calcBaseFu(): FuDetail[]{
48
+ const baseFu: FuDetail[] = [new FuDetail("符底", 20)];
49
+ const isTsumo = this.context.ctx.isTsumo;
50
+
51
+ if(isTsumo) baseFu.push(new FuDetail("ツモ", 2));
52
+ if(!isTsumo && this.context.hand.isMenzen()) baseFu.push(new FuDetail("面前ロン", 10));
53
+
54
+ return baseFu;
55
+ }
56
+
57
+ private calcMachuFu(): FuDetail[]{
58
+ const machiFu: FuDetail[] = [];
59
+ const machiType = this.calcMachiType();
60
+ if(machiType.has(MachiType.TANKI)) machiFu.push(new FuDetail("単騎待ち", 2));
61
+ else if(machiType.has(MachiType.KANCHAN)) machiFu.push(new FuDetail("嵌張待ち", 2));
62
+ else if(machiType.has(MachiType.PENCHAN)) machiFu.push(new FuDetail("辺張待ち", 2));
63
+
64
+ return machiFu;
65
+ }
66
+
67
+ private calcJantoFu(analyzer: MentsuAnalyzer): FuDetail[]{
68
+ const JantoFu: FuDetail[] = [];
69
+ const pw = this.context.ctx.playerWind;
70
+ const rw = this.context.ctx.roundWind;
71
+ const hasYakuhaiJanto = analyzer.hasYakuhaiMentsu(m => m instanceof BlockHais && m.isJanto(), pw, rw);
72
+
73
+ if(!hasYakuhaiJanto) return JantoFu;
74
+
75
+ for(const m of analyzer.getAll()){
76
+ if(m.getType() === BlockType.JANTO){
77
+ JantoFu.push(new FuDetail("役牌雀頭", 2, m));
78
+ }
79
+ }
80
+
81
+ return JantoFu;
82
+ }
83
+
84
+ private calcMentsuFu(analyzer: MentsuAnalyzer): FuDetail[]{
85
+ const MentsuFu: FuDetail[] = [];
86
+
87
+ for(const m of analyzer.getAll()){
88
+ const table = MENTSU_FU_TABLE[m.getType()];
89
+ if(!table) continue;
90
+
91
+ const key = m.minHai.isYaochuHai() ? "yaochu" : "chuchan";
92
+ const spec = table[key];
93
+
94
+ MentsuFu.push(new FuDetail(spec.name, spec.fu, m));
95
+ }
96
+
97
+ return MentsuFu;
98
+ }
99
+
100
+ calcFu(): FuDetail[]{
101
+ const special = this.calcSpecialFu();
102
+ if(special) return [special];
103
+
104
+ const analyzer = new MentsuAnalyzer(this.context.block.getBlockHais(), this.context.melds);
105
+
106
+ return [
107
+ ...this.calcBaseFu(),
108
+ ...this.calcMachuFu(),
109
+ ...this.calcJantoFu(analyzer),
110
+ ...this.calcMentsuFu(analyzer),
111
+ ];
112
+ }
113
+
114
+ private calcMachiType(): Set<MachiType>{
115
+ const agariHaiId = this.context.ctx.agariHai.getId();
116
+ return this.context.block.calcMachiType(agariHaiId);
117
+ }
118
+ }
@@ -0,0 +1,13 @@
1
+ import { IMentsu } from "../IMentsu";
2
+
3
+ export class FuDetail{
4
+ readonly name: string;
5
+ readonly fu: number;
6
+ readonly mentsu?: IMentsu;
7
+
8
+ constructor(name: string, fu: number, mentsu?: IMentsu){
9
+ this.name = name;
10
+ this.fu = fu;
11
+ this.mentsu = mentsu;
12
+ }
13
+ }
@@ -0,0 +1,35 @@
1
+ import { YakuContext } from '../yaku/YakuContext';
2
+ import { TensuuCalculator } from './TensuuCalculator';
3
+ import { FuCalculator } from './FuCalculator';
4
+ import { FuDetail } from './FuDetail';
5
+ import { ScoreResult } from './ScoreResult';
6
+
7
+ export class ScoreResolver{
8
+ private readonly context: YakuContext;
9
+ private readonly yaku: Map<string, number>;
10
+ constructor(context: YakuContext, yaku: Map<string, number>){
11
+ this.context = context;
12
+ this.yaku = yaku;
13
+ }
14
+
15
+ private calcHonsuu(): number{
16
+ return [...this.yaku.values()].reduce((sum, val) => sum + val, 0);
17
+ }
18
+
19
+ private countFusuu(detail: FuDetail[]): number{
20
+ return detail.reduce((sum, val) => sum + val.fu, 0);
21
+ }
22
+
23
+ private ceilFusuu(fu: number): number{
24
+ return fu === 25 ? 25 : Math.ceil(fu / 10) * 10;
25
+ }
26
+
27
+ resolve(){
28
+ const han = this.calcHonsuu();
29
+ const fuDetail = new FuCalculator(this.context, this.yaku).calcFu();
30
+ const fuBasic = this.countFusuu(fuDetail);
31
+ const fuCeiled = this.ceilFusuu(fuBasic);
32
+ const tensuu = TensuuCalculator.calcTensuu(han, fuCeiled);
33
+ return new ScoreResult(han, fuBasic, fuCeiled, tensuu, fuDetail);
34
+ }
35
+ }
@@ -0,0 +1,24 @@
1
+ import { FuDetail } from "./FuDetail";
2
+ import { TensuuResult } from "./TensuuResult";
3
+
4
+ export class ScoreResult{
5
+ public readonly han: number;
6
+ public readonly fuBasic: number;
7
+ public readonly fuCeiled: number;
8
+ public readonly tensuu: TensuuResult;
9
+ public readonly fuDetail: FuDetail[];
10
+
11
+ constructor(
12
+ han: number,
13
+ fuBasic: number,
14
+ fuCeiled: number,
15
+ tensuu: TensuuResult,
16
+ fuDetail: FuDetail[]
17
+ ){
18
+ this.han = han;
19
+ this.fuBasic = fuBasic;
20
+ this.fuCeiled = fuCeiled;
21
+ this.tensuu = tensuu;
22
+ this.fuDetail = fuDetail;
23
+ }
24
+ }
@@ -0,0 +1,40 @@
1
+ import { TensuuResult } from './TensuuResult';
2
+
3
+ export class TensuuCalculator{
4
+ static readonly BASE_LIMITS = [
5
+ {han: 26, base: 16000 },
6
+ {han: 13, base: 8000 },
7
+ {han: 11, base: 6000 },
8
+ {han: 8, base: 4000 },
9
+ {han: 6, base: 3000 },
10
+ {han: 5, base: 2000 },
11
+ ];
12
+
13
+ static calcBaseTensuu(han: number, fu: number): number{
14
+ return Math.min(fu * Math.pow(2, han + 2), 2000);
15
+ }
16
+
17
+ static calcRonTensuu(base: number, multi: number): number{
18
+ return Math.ceil(base * multi / 100) * 100;
19
+ }
20
+
21
+ static calcdividedTensuu(ronTensuu: number, divide: number){
22
+ return Math.ceil(Math.floor(ronTensuu / divide) / 100) * 100;
23
+ }
24
+
25
+ static calcTensuuFromBase(base: number): TensuuResult{
26
+ const ronOya = this.calcRonTensuu(base, 6);
27
+ const ronKo = this.calcRonTensuu(base, 4);
28
+ const tsumoOya = this.calcdividedTensuu(ronOya, 3);
29
+ const tsumoKo = {oya: this.calcdividedTensuu(ronKo, 2), ko: this.calcdividedTensuu(ronKo, 4)};
30
+
31
+ return new TensuuResult(base, ronOya, ronKo, tsumoOya, tsumoKo);
32
+ }
33
+
34
+ static calcTensuu(han: number, fu: number): TensuuResult{
35
+ for(const limit of this.BASE_LIMITS){
36
+ if(han >= limit.han) return this.calcTensuuFromBase(limit.base);
37
+ }
38
+ return this.calcTensuuFromBase(this.calcBaseTensuu(han, fu));
39
+ }
40
+ }