MathUtils.ts 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /** @format */
  2. // ---------Math-----------
  3. interface Math {
  4. /**
  5. * 返回[min,max]闭区间随机整数
  6. * @param min 最小值
  7. * @param max 最大值
  8. * @param seed 随机种子
  9. */
  10. randomRangeInt(min: number, max: number, seed?: number): number
  11. /**
  12. * 返回[min,max]闭区间随机浮点数
  13. * @param min 最小值
  14. * @param max 最大值
  15. * @param seed 随机种子
  16. */
  17. randomRangeFloat(min: number, max: number, seed?: number): number
  18. /**
  19. * 返回[min,max]闭区间随机整数数组
  20. * @param min 最小值
  21. * @param max 最大值
  22. * @param count 数量
  23. * @param seed 随机种子
  24. */
  25. randomRangeIntArr(min: number, max: number, count: number, seed?: number): number[]
  26. /**
  27. * 返回余数
  28. * @param x 除数
  29. * @param y 被除数
  30. */
  31. fMod(x: number, y: number): number
  32. /**
  33. * 返回正态分布随机数
  34. * @param mean 基数
  35. * @param stdDev 标准差
  36. */
  37. getNumberInNormalDistribution(mean, stdDev)
  38. randomNormalDistribution()
  39. /**
  40. * 给一个数添加前导0
  41. * @param num 数字
  42. * @param length 包含数字的位数
  43. */
  44. addPreZero(num: number, length: number)
  45. /**
  46. * 给定圆心坐标和圆的半径,获得一个圆内的随机点
  47. * @param pos 圆心
  48. * @param radius 半径
  49. */
  50. getCirclesRandPos(pos: cc.Vec2, radius: number)
  51. /**
  52. * 获取一个概率是否成功
  53. * @param val 0 - 1
  54. */
  55. getProb(val: number, seed?: number)
  56. /**
  57. * 判断阿拉伯数字转换成中文
  58. * @param num 阿拉伯数字
  59. * @return 对应中文
  60. */
  61. toBigTextNum(num: Number): string
  62. // 判断一个整数是否在安全的范围
  63. isSafeInteger(n: number)
  64. /**
  65. * 将数字转换为带有 K、M、B 等后缀的字符串
  66. * @param num 数字
  67. * @return 对应字符串
  68. */
  69. toKMBNum(num: Number): string
  70. /**
  71. * 限制数字再指定范围内,如果超出范围,则返回边界值
  72. * @param value
  73. * @param min
  74. * @param max
  75. */
  76. clampValue(value: number, min: number, max: number): number
  77. /**
  78. * 获取目标数二进制最后一位开始某个位置的数字是0还是1的布尔值
  79. * @param target
  80. * @param index
  81. */
  82. getBitBool(target: number, index: number): boolean
  83. /*
  84. * 是否开启伪随机
  85. */
  86. isSeededRandom: boolean
  87. /*
  88. * 随机种子
  89. */
  90. seed: number
  91. }
  92. Math.isSeededRandom = false
  93. Math.seed = Date.now()
  94. Math.randomRangeInt = (min: number, max: number, seed: number): number => {
  95. let rand = Math.random()
  96. if (seed || Math.isSeededRandom) {
  97. rand = createRandom(seed)
  98. }
  99. if (rand === 1) {
  100. rand -= Number.EPSILON
  101. }
  102. return min + Math.floor(rand * (max - min + 1))
  103. }
  104. Math.randomRangeFloat = (min: number, max: number, seed: number): number => {
  105. let rand = Math.random()
  106. if (seed || Math.isSeededRandom) {
  107. rand = createRandom(seed)
  108. }
  109. return min + rand * (max - min)
  110. }
  111. Math.randomRangeIntArr = (min: number, max: number, count: number, seed: number): number[] => {
  112. if (count > max - min + 1) {
  113. return []
  114. }
  115. let tempArr = []
  116. for (let i = min; i <= max; i++) {
  117. tempArr.push(i)
  118. }
  119. let newArrList = []
  120. for (let i = 0; i < count; i++) {
  121. let baseRandom = Math.random()
  122. if (seed || Math.isSeededRandom) {
  123. baseRandom = createRandom(seed)
  124. }
  125. let random = Math.floor(baseRandom * tempArr.length)
  126. let value = tempArr[random]
  127. tempArr.splice(random, 1)
  128. newArrList.push(value)
  129. }
  130. return newArrList
  131. }
  132. Math.fMod = (x: number, y: number): number => {
  133. const temp = Math.floor(x / y)
  134. return x - temp * y
  135. }
  136. Math.getNumberInNormalDistribution = (mean, stdDev) => mean + Math.randomNormalDistribution() * stdDev
  137. Math.randomNormalDistribution = () => {
  138. let u = 0.0
  139. let v = 0.0
  140. let w = 0.0
  141. let c = 0.0
  142. do {
  143. // 获得两个(-1,1)的独立随机变量
  144. u = Math.random() * 2 - 1.0
  145. v = Math.random() * 2 - 1.0
  146. w = u * u + v * v
  147. } while (w == 0.0 || w >= 1.0)
  148. // 这里就是 Box-Muller转换
  149. c = Math.sqrt((-2 * Math.log(w)) / w)
  150. // 返回2个标准正态分布的随机数,封装进一个数组返回
  151. // 当然,因为这个函数运行较快,也可以扔掉一个
  152. // return [u*c,v*c];
  153. return u * c
  154. }
  155. Math.addPreZero = (num: number, length: number) => {
  156. let numstr = num.toString()
  157. const l = numstr.length
  158. if (numstr.length >= length) {
  159. return numstr
  160. }
  161. for (let i = 0; i < length - l; i++) {
  162. numstr = `0${numstr}`
  163. }
  164. return numstr
  165. }
  166. Math.getCirclesRandPos = (pos: cc.Vec2, radius: number) => {
  167. const r = radius * Math.sqrt(Math.random())
  168. const theta = Math.random() * 2 * Math.PI
  169. return cc.v2(pos.x + r * Math.cos(theta), pos.y + r * Math.sin(theta))
  170. }
  171. Math.getProb = (val: number, seed: number) => {
  172. if (val == 0) {
  173. return false
  174. }
  175. const probability = val * 100 || 1
  176. let rand = Math.random()
  177. if (seed || Math.isSeededRandom) {
  178. rand = createRandom(seed)
  179. }
  180. const odds = Math.floor(rand * 100)
  181. if (probability === 1 && val != 0.01) {
  182. return true
  183. }
  184. if (odds < probability) {
  185. return true
  186. }
  187. return false
  188. }
  189. Math.toBigTextNum = (num: number) => {
  190. const chnNumChar = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
  191. const chnUnitSection = ['', '万', '亿', '万亿', '亿亿']
  192. const chnUnitChar = ['', '十', '百', '千']
  193. const SectionToChinese = section => {
  194. let strIns = ''
  195. let chnStr = ''
  196. let unitPos = 0
  197. let zero = true
  198. while (section > 0) {
  199. const v = section % 10
  200. if (v === 0) {
  201. if (!zero) {
  202. zero = true
  203. chnStr = chnNumChar[v] + chnStr
  204. }
  205. } else {
  206. zero = false
  207. strIns = chnNumChar[v]
  208. strIns += chnUnitChar[unitPos]
  209. chnStr = strIns + chnStr
  210. }
  211. unitPos++
  212. section = Math.floor(section / 10)
  213. }
  214. return chnStr
  215. }
  216. let unitPos = 0
  217. let strIns = ''
  218. let chnStr = ''
  219. let needZero = false
  220. if (num === 0) {
  221. return chnNumChar[0]
  222. }
  223. while (num > 0) {
  224. const section = num % 10000
  225. if (needZero) {
  226. chnStr = chnNumChar[0] + chnStr
  227. }
  228. strIns = SectionToChinese(section)
  229. strIns += section !== 0 ? chnUnitSection[unitPos] : chnUnitSection[0]
  230. chnStr = strIns + chnStr
  231. needZero = section < 1000 && section > 0
  232. num = Math.floor(num / 10000)
  233. unitPos++
  234. }
  235. return chnStr
  236. }
  237. Math.isSafeInteger = n =>
  238. typeof n === 'number' && // 判断是否是一个数字类型
  239. Math.round(n) === n && // 判断是否是整数,Math.round()方法用于取整
  240. Number.MIN_SAFE_INTEGER <= n && // 判断是否大于最小整数
  241. n <= Number.MAX_SAFE_INTEGER // 判断是否小于最大整数
  242. let createRandom = seed => {
  243. if (!seed) {
  244. Math.seed += 1
  245. seed = Math.seed
  246. }
  247. let x = Math.sin(seed) * 10000
  248. return x - Math.floor(x)
  249. }
  250. Math.toKMBNum = (num: number): string => {
  251. const suffixes = ['', 'K', 'M', 'B', 'T']
  252. let suffixIndex = 0
  253. let origin = num
  254. while (num >= 1000 && suffixIndex < suffixes.length - 1) {
  255. num /= 1000
  256. suffixIndex++
  257. }
  258. return origin < 1000 ? String(num.toFixed(0)) : num.toFixed(2) + suffixes[suffixIndex]
  259. }
  260. Math.clampValue = (value: number, min: number, max: number): number => {
  261. return value < min ? min : value > max ? max : value
  262. }
  263. Math.getBitBool = (target: number, index: number): boolean => {
  264. return (target & (1 << index)) !== 0
  265. }