import { CoroutineV2 } from "../../CatanEngine/CoroutineV2/CoroutineV2"; import { RandomEx } from "./RandomEx"; export module NumberEx { /** * 數字滾動 * @param startNum * @param endNum * @param callbackfn * @param chabgeRate */ export function* ChangeScore(startNum: number, endNum: number, callbackfn: (num: number) => void, sec: number) { let fps = 30; let waitTime = 0.03; let changeRate = sec * fps; // -1為了讓changeRate數字能混亂點 changeRate = changeRate - 1 <= 0 ? changeRate : changeRate - 1; changeRate = 1 / changeRate; let diff = endNum - startNum; let isIncrease = endNum >= startNum; let tempScore = startNum; let counter = 0; //let randomRate = 0; while (true) { if (endNum != tempScore) { /*if (counter % 2 == 0) { if (isIncrease) { randomRate = RandomEx.GetFloat(0, diff * changeRate).ExToNumFloorDecimal(2); } else { randomRate = RandomEx.GetFloat(0, -diff * changeRate).ExToNumFloorDecimal(2); } } else { randomRate = -randomRate; }*/ tempScore += diff * changeRate //+ randomRate; // 遞增 if (isIncrease && tempScore > endNum) { tempScore = endNum; } // 遞減 if (!isIncrease && tempScore < endNum) { tempScore = endNum; } callbackfn(tempScore.ExToInt()); // yield null; counter++; yield CoroutineV2.WaitTime(waitTime); } else { callbackfn(endNum); break; } } } /** * 數字跳動 * @param minNum 起始數字 * @param maxNum 最終數字 * @param callbackfn callbackfn * @param sec 時間 */ export function* BeatScore(minNum: number, maxNum: number, endNum: number, callbackfn: (num: number) => void, sec: number): IterableIterator { let fps: number = 13; let waitTime: number = 0.07; let changeRate: number = sec * fps; // -1為了讓changeRate數字能混亂點 changeRate = changeRate - 1 <= 0 ? changeRate : changeRate - 1; changeRate = 1 / changeRate; let diff: number = maxNum - minNum; let isIncrease: boolean = maxNum >= minNum; let tempScore: number = minNum; let counter: number = 0; let randomRate: number = 0; let lastNum: number = minNum; let nowNum: number = minNum; while (true) { if (maxNum !== tempScore) { if (counter % 2 === 0) { if (isIncrease) { randomRate = RandomEx.GetFloat(0, diff * changeRate).ExToNumFloorDecimal(2); } else { randomRate = RandomEx.GetFloat(0, -diff * changeRate).ExToNumFloorDecimal(2); } } else { randomRate = -randomRate; } tempScore += diff * changeRate + randomRate; // 遞增 if (isIncrease && tempScore > maxNum) { tempScore = maxNum; } // 遞減 if (!isIncrease && tempScore < maxNum) { tempScore = maxNum; } while (nowNum === lastNum) { nowNum = RandomEx.GetInt(minNum, maxNum + 1); } lastNum = nowNum; callbackfn(nowNum); // yield null; counter++; yield CoroutineV2.WaitTime(waitTime); } else { callbackfn(endNum); break; } } } /** * 检测数字是否越界,如果越界给出提示 * @param {*number} num 输入数 */ function checkBoundary(num: number) { if (_boundaryCheckingState) { if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) { console.warn(`${num} is beyond boundary when transfer to integer, the results may not be accurate`); } } } /** * 精确乘法 */ export function times(num1: number, num2: number, ...others: number[]): number { if (others.length > 0) { return times(times(num1, num2), others[0], ...others.slice(1)); } const num1Changed = num1.Float2Fixed(); const num2Changed = num2.Float2Fixed(); const baseNum = num1.DigitLength() + num2.DigitLength(); const leftValue = num1Changed * num2Changed; checkBoundary(leftValue); return leftValue / Math.pow(10, baseNum); } /** * 精确加法 */ export function plus(num1: number, num2: number, ...others: number[]): number { if (others.length > 0) { return plus(plus(num1, num2), others[0], ...others.slice(1)); } const baseNum = Math.pow(10, Math.max(num1.DigitLength(), num2.DigitLength())); return (times(num1, baseNum) + times(num2, baseNum)) / baseNum; } /** * 精确减法 */ export function minus(num1: number, num2: number, ...others: number[]): number { if (others.length > 0) { return minus(minus(num1, num2), others[0], ...others.slice(1)); } const baseNum = Math.pow(10, Math.max(num1.DigitLength(), num2.DigitLength())); return (times(num1, baseNum) - times(num2, baseNum)) / baseNum; } /** * 精确除法 */ export function divide(num1: number, num2: number, ...others: number[]): number { if (others.length > 0) { return divide(divide(num1, num2), others[0], ...others.slice(1)); } const num1Changed = num1.Float2Fixed(); const num2Changed = num2.Float2Fixed(); checkBoundary(num1Changed); checkBoundary(num2Changed); return times((num1Changed / num2Changed), Math.pow(10, num2.DigitLength() - num1.DigitLength())); } /** * 四舍五入 */ export function round(num: number, ratio: number): number { const base = Math.pow(10, ratio); return divide(Math.round(times(num, base)), base); } let _boundaryCheckingState = false; /** * 是否进行边界检查 * @param flag 标记开关,true 为开启,false 为关闭 */ function enableBoundaryChecking(flag = true) { _boundaryCheckingState = flag; } }