const fixFloat = (number, x = 2) => { return parseFloat(number.toFixed(x)); } const HandicapCalc = function (data) { const { i, g, a, b, c, w, l } = data; const t = w + l; const calcTemplate = (handlers) => { if (i > 2 || i < 0) { return {}; } if (i === 2) { const z = g; const x = (b + 1) * (t + z) / (a * b - 1); const y = (a + 1) * (t + z) / (a * b - 1); return { x, y, z }; }; return handlers[i]?.() ?? {}; }; return { la_wh_wa() { return calcTemplate([ () => { const x = g; const z = (t + x) / (2 * c + 1); const y = (c + 1) * (t + x) / (c + 0.5) / b; return { x, y, z }; }, () => { const y = g; const z = ((a + 1) * t + (1 - a * b / 2) * y) / (a * c - 1); const x = ((c + 1) * t + (c - b / 2) * y) / (a * c - 1); return { x, y, z }; } ]); }, la_dr_wa() { return calcTemplate([ () => { const x = g; const z = (t + x) / c; const y = (t + x + z) / b; return { x, y, z }; }, () => { const y = g; const z = ((a + 1) * t + y) / (a * c - 1); const x = ((c + 1) * t + c * y) / (a * c - 1); return { x, y, z }; } ]); }, la_lh_wa() { return calcTemplate([ () => { const x = g; const z = (2 * b + 1) * (t + x) / (2 * b * c - 1); const y = (c + 1) * (t + x) / (b * c - 0.5); return { x, y, z }; }, () => { const y = g; const z = ((a + 1) * t + (a / 2 + 1) * y) / (a * c - 1); const x = ((c + 1) * t + (c + 0.5) * y) / (a * c - 1); return { x, y, z }; } ]); }, lh_dr_wa() { return calcTemplate([ () => { const x = g; const z = (t + x / 2) / c; const y = (t + x + z) / b; return { x, y, z }; }, () => { const y = g; const z = ((2 * a + 1) * t + y) / (2 * a * c - 1); const x = ((c + 1) * t + c * y) / (a * c - 0.5); return { x, y, z }; } ]); }, lh_lh_wa() { return calcTemplate([ () => { const x = g; const z = ((2 * b + 1) * t + (b + 1) * x) / (2 * b * c - 1); const y = ((c + 1) * t + (c + 0.5) * x) / (b * c - 0.5); }, () => { const y = g; const z = ((2 * a + 1) * t + (a + 1) * y) / (2 * a * c - 1); const x = ((c + 1) * t + (c + 0.5) * y) / (a * c - 0.5); return { x, y, z }; } ]); }, la_la_wa() { return calcTemplate([ () => { const x = g; const z = (b + 1) * (t + x) / (b * c - 1); const y = (c + 1) * (t + x) / (b * c - 1); return { x, y, z }; }, () => { const y = g; const z = (a + 1) * (t + y) / (a * c - 1); const x = (c + 1) * (t + y) / (a * c - 1); return { x, y, z }; } ]); } } } const calcExternalHandicap = (data) => { const { gold_side_inner: g, odds_side_a: a, odds_side_b: b, odds_side_c: c, inner_index: i, cross_type: t, win_target: w, loss_out_1 } = data; const l = loss_out_1 ?? 0; const calc = new HandicapCalc({ i, g, a, b, c, w, l }); const { x, y, z } = calc?.[t]() ?? {}; return { gold_side_a: fixFloat(x), gold_side_b: fixFloat(y), gold_side_c: fixFloat(z), inner_index: i, } } const calcGoldsWithWinTarget = (data) => { const { gold_side_inner, win_target, sol1, sol2 } = data; const { gold_side_a: goldA1, gold_side_b: goldB1, gold_side_c: goldC1, inner_index: inner_index_1 } = calcExternalHandicap({ ...sol1, gold_side_inner, win_target }); let loss_out_1 = 0, win_inner_1 = 0; switch (inner_index_1) { case 0: loss_out_1 = goldB1 + goldC1; win_inner_1 = gold_side_inner * (sol1.odds_side_a + 1); break; case 1: loss_out_1 = goldA1 + goldC1; win_inner_1 = gold_side_inner * (sol1.odds_side_b + 1); break; case 2: loss_out_1 = goldA1 + goldB1; win_inner_1 = gold_side_inner * (sol1.odds_side_c + 1) break; } const { gold_side_a: goldA2, gold_side_b: goldB2, gold_side_c: goldC2, inner_index: inner_index_2 } = calcExternalHandicap({ ...sol2, gold_side_inner, win_target, loss_out_1 }); let loss_out_2 = 0, win_inner_2 = 0, inner_base_key; switch (inner_index_2) { case 0: inner_base_key = 'goldA2'; loss_out_2 = gold_side_inner +goldB2 + goldC2 + loss_out_1; win_inner_2 = win_inner_1 * (sol2.odds_side_a + 1); break; case 1: inner_base_key = 'goldB2'; loss_out_2 = gold_side_inner + goldA2 + goldC2 + loss_out_1; win_inner_2 = win_inner_1 * (sol2.odds_side_b + 1); break; case 2: inner_base_key = 'goldC2'; loss_out_2 = gold_side_inner + goldA2 + goldB2 + loss_out_1; win_inner_2 = win_inner_1 * (sol2.odds_side_c + 1); break; } const win_inner = fixFloat(win_inner_2 - loss_out_2); const result = { goldA1, goldB1, goldC1, goldA2, goldB2, goldC2, win_inner, inner_index_1, inner_index_2, inner_base: gold_side_inner, } if (result[inner_base_key]) { result[inner_base_key] = win_inner_1; } return result; } const calcTotalProfit = (sol1, sol2, gold_side_inner) => { const winTarget1 = sol1.win_average; const winTarget2 = sol2.win_average; const winTarget = fixFloat(Math.min(winTarget1, winTarget2), 2); const win1 = calcGoldsWithWinTarget({ gold_side_inner, win_target: winTarget1, sol1, sol2 })?.win_inner; const win2 = calcGoldsWithWinTarget({ gold_side_inner, win_target: winTarget2, sol1, sol2 })?.win_inner; const win_inner = fixFloat(Math.max(win1, win2), 2); const start = Math.max(winTarget, win_inner); const end = Math.min(winTarget, win_inner); const result = []; for (let i = start; i > end; i--) { const win_target = i; const goldsInfo = calcGoldsWithWinTarget({ gold_side_inner, win_target, sol1, sol2 }); const win_diff = Math.abs(fixFloat(win_target - goldsInfo.win_inner)); const lastResult = result.at(-1); if (!lastResult?.win_diff || win_diff < lastResult.win_diff) { result.push({ win_target: fixFloat(win_target), win_diff, ...goldsInfo }); } else { break; } } return result.at(-1); } module.exports = calcTotalProfit;