/*
* Skytils - Hypixel Skyblock Quality of Life Mod
* Copyright (C) 2021 Skytils
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
package skytils.skytilsmod.utils
import java.text.NumberFormat
import java.util.*
import kotlin.math.pow
import kotlin.math.roundToInt
object NumberUtil {
@JvmField
val nf: NumberFormat = NumberFormat.getInstance(Locale.US)
private val suffixes = TreeMap().apply {
this[1000L] = "k"
this[1000000L] = "M"
this[1000000000L] = "B"
this[1000000000000L] = "T"
this[1000000000000000L] = "P"
this[1000000000000000000L] = "E"
}
/**
* This code was unmodified and taken under CC BY-SA 3.0 license
* @link https://stackoverflow.com/a/30661479
* @author assylias
*/
@JvmStatic
fun format(value: Number): String {
@Suppress("NAME_SHADOWING")
val value = value.toLong()
//Long.MIN_VALUE == -Long.MIN_VALUE so we need an adjustment here
if (value == Long.MIN_VALUE) return format(Long.MIN_VALUE + 1)
if (value < 0) return "-" + format(-value)
if (value < 1000) return value.toString() //deal with easy case
val (divideBy, suffix) = suffixes.floorEntry(value)
val truncated = value / (divideBy / 10) //the number part of the output times 10
val hasDecimal = truncated < 100 && truncated / 10.0 != (truncated / 10).toDouble()
return if (hasDecimal) (truncated / 10.0).toString() + suffix else (truncated / 10).toString() + suffix
}
@JvmStatic
fun unformat(value: String): Long {
val suffix = value.filter { !it.isDigit() }.lowercase()
val num = value.filter { it.isDigit() }.toLong()
return num * (suffixes.entries.find { it.value.lowercase() == suffix }?.key ?: 1)
}
/**
* This code was unmodified and taken under CC BY-SA 3.0 license
* @link https://stackoverflow.com/a/22186845
* @author jpdymond
*/
fun Double.roundToPrecision(precision: Int): Double {
val scale = 10.0.pow(precision).toInt()
return (this * scale).roundToInt().toDouble() / scale
}
/**
* This code was unmodified and taken under CC BY-SA 3.0 license
* @link https://stackoverflow.com/a/22186845
* @author jpdymond
*/
fun Float.roundToPrecision(precision: Int): Float {
val scale = 10.0.pow(precision).toInt()
return (this * scale).roundToInt().toFloat() / scale
}
fun Number.addSuffix(): String {
val long = this.toLong()
if (long in 11..13) return "${this}th"
return when (long % 10) {
1L -> "${this}st"
2L -> "${this}nd"
3L -> "${this}rd"
else -> "${this}th"
}
}
/**
* This code was converted to Kotlin and taken under CC BY-SA 3.0 license
* @link https://stackoverflow.com/a/9073310
*/
fun String.romanToDecimal(): Int {
var decimal = 0
var lastNumber = 0
val romanNumeral = this.uppercase()
for (x in romanNumeral.length - 1 downTo 0) {
when (romanNumeral[x]) {
'M' -> {
decimal = processDecimal(1000, lastNumber, decimal)
lastNumber = 1000
}
'D' -> {
decimal = processDecimal(500, lastNumber, decimal)
lastNumber = 500
}
'C' -> {
decimal = processDecimal(100, lastNumber, decimal)
lastNumber = 100
}
'L' -> {
decimal = processDecimal(50, lastNumber, decimal)
lastNumber = 50
}
'X' -> {
decimal = processDecimal(10, lastNumber, decimal)
lastNumber = 10
}
'V' -> {
decimal = processDecimal(5, lastNumber, decimal)
lastNumber = 5
}
'I' -> {
decimal = processDecimal(1, lastNumber, decimal)
lastNumber = 1
}
}
}
return decimal
}
private fun processDecimal(decimal: Int, lastNumber: Int, lastDecimal: Int): Int {
return if (lastNumber > decimal) {
lastDecimal - decimal
} else {
lastDecimal + decimal
}
}
}