fork download
  1. function parseMixedNumber(input) {
  2. const units = { '億': 100000000, '万': 10000 };
  3. let total = 0;
  4. let matched = false;
  5.  
  6. for (let unit in units) {
  7. const regex = new RegExp('(\\d+(?:\\.\\d+)?)' + unit);
  8. const match = input.match(regex);
  9. if (match) {
  10. total += parseFloat(match[1]) * units[unit];
  11. input = input.replace(match[0], '');
  12. matched = true;
  13. }
  14. }
  15.  
  16. if (input.match(/[一二三四五六七八九〇十百千万億]/)) {
  17. total += kanjiToNumber(input);
  18. matched = true;
  19. } else if (input.trim().length > 0) {
  20. total += parseFloat(input);
  21. matched = true;
  22. }
  23.  
  24. return matched ? total : NaN;
  25. }
  26.  
  27. function kanjiToNumber(kanji) {
  28. const nums = { '〇': 0, '一': 1, '二': 2, '三': 3, '四': 4, '五': 5, '六': 6, '七': 7, '八': 8, '九': 9 };
  29. const units = { '十': 10, '百': 100, '千': 1000 };
  30. const bigUnits = { '万': 10000, '億': 100000000 };
  31. let total = 0;
  32.  
  33. const parseSection = (str) => {
  34. let n = 0, temp = 0;
  35. for (let c of str) {
  36. if (nums[c] !== undefined) {
  37. temp = nums[c];
  38. } else if (units[c]) {
  39. n += (temp || 1) * units[c];
  40. temp = 0;
  41. }
  42. }
  43. return n + temp;
  44. };
  45.  
  46. let tmp = kanji;
  47. for (let unit in bigUnits) {
  48. const idx = tmp.indexOf(unit);
  49. if (idx !== -1) {
  50. const left = tmp.slice(0, idx);
  51. total += parseSection(left) * bigUnits[unit];
  52. tmp = tmp.slice(idx + 1);
  53. }
  54. }
  55.  
  56. total += parseSection(tmp);
  57. return total;
  58. }
  59.  
  60. function formatNumber(num) {
  61. if (num >= 100000000) return (num / 100000000).toFixed(2).replace(/\.00$/, '') + "億";
  62. if (num >= 10000) return (num / 10000).toFixed(2).replace(/\.00$/, '') + "万";
  63. return num.toLocaleString();
  64. }
  65.  
  66. function calculateDamage(params) {
  67. const hp = parseMixedNumber(params.hp);
  68. let damage = parseMixedNumber(params.damage);
  69. const originalDamage = damage;
  70. const reductionRate = parseFloat(params.reduction) / 100 || 0;
  71. const aPercent = parseFloat(params.aPercent) / 100 || 0;
  72. const blockRate = parseFloat(params.blockRate) / 100 || 0;
  73.  
  74. if (isNaN(hp) || isNaN(damage)) {
  75. return {
  76. error: "HPまたはダメージが無効です。"
  77. };
  78. }
  79.  
  80. damage = damage * (1 - reductionRate);
  81. const threshold = hp * aPercent;
  82. const excess = Math.max(0, damage - threshold);
  83. const blockedDamage = excess * (1 - blockRate);
  84. const nonBlockedDamage = damage - excess;
  85. const totalDamage = nonBlockedDamage + blockedDamage;
  86. const resultHP = hp - totalDamage;
  87.  
  88. const attackCount = totalDamage > 0 ? (hp / totalDamage) : Infinity;
  89. const attackCountDisplay = attackCount === Infinity ? "∞" : attackCount.toFixed(3);
  90. const finalBlockRate = (1 - (totalDamage / originalDamage)) * 100;
  91. const finalBlockRateDisplay = isFinite(finalBlockRate) ? finalBlockRate.toFixed(2) + "%" : "0%";
  92.  
  93. return {
  94. result: `受けたダメージ: ${formatNumber(totalDamage)}\n残りHP: ${formatNumber(resultHP)}\n` +
  95. `最終遮断率: ${finalBlockRateDisplay}\nこのダメージでHPを0以下にするには 約 ${attackCountDisplay} 回攻撃が必要`,
  96. formula: `計算詳細:
  97. 最大HP: ${formatNumber(hp)}
  98. 受けるダメージ(初期): ${formatNumber(originalDamage)}
  99. 被ダメージ減少: ${(reductionRate * 100).toFixed(1)}% → ${formatNumber(damage)}
  100. 遮断発動ライン: ${formatNumber(threshold)}(${(aPercent * 100).toFixed(1)}%
  101. 超過ダメージ: ${formatNumber(excess)}
  102. 遮断率: ${(blockRate * 100).toFixed(1)}%
  103. 遮断後の超過ダメージ: ${formatNumber(blockedDamage)}
  104. 非遮断ダメージ: ${formatNumber(nonBlockedDamage)}
  105. 合計ダメージ: ${formatNumber(totalDamage)}
  106. 最終遮断率(元のダメージと比較): ${finalBlockRateDisplay}
  107. 残りHP: ${formatNumber(hp)} - ${formatNumber(totalDamage)} = ${formatNumber(resultHP)}
  108. HPを0以下にするのに必要な攻撃回数: 約 ${attackCountDisplay} 回`
  109. };
  110. }
Success #stdin #stdout 0.04s 18976KB
stdin
Standard input is empty
stdout
Standard output is empty