Skip to content

Instantly share code, notes, and snippets.

@dragon0
Created December 2, 2017 00:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dragon0/8d5ef67759aaede643a5d5997f8bc8bd to your computer and use it in GitHub Desktop.
Save dragon0/8d5ef67759aaede643a5d5997f8bc8bd to your computer and use it in GitHub Desktop.
Command-line dice roller
import scala.math.{round, ceil, random}
//val pattern = """(\d*)d(%|\d+)(([*/])(\d+))?([+-]\d+)?""".r
val fullPattern = """(\d*d(%|\d+))(r[hl<>]?\d+)?(k[hl<>]?\d+)?(s[hl<>]?\d+)?([*/]\d+)?([+-]\d+)?""".r
val dicePattern = """(\d*)d(%|\d+)""".r
val rerollPattern = """r([hl<>]?)(\d+)""".r
val keepPattern = """k([hl<>]?)(\d+)""".r
val scrapPattern = """s([hl<>]?)(\d+)""".r
val multiplierPattern = """([*/])(\d+)""".r
val bonusPattern = """([+-]\d+)""".r
val dieString = args(0)
def roll(sides: Long): Long = round(ceil(random * sides))
def roll(quantity: Int, sides: Long): Seq[Long] = {
(for( i <- 1 to quantity) yield roll(sides)) sortWith { _ > _ }
}
def roll(dieString: String):(Seq[Long], Seq[Long], Seq[Long], Double) =
dieString match {
case fullPattern(dice, _, reroll, keep, scrap, multiplier, bonus) => {
val (quantity, sides) = dice match {
case dicePattern("", "%") => (1, 100)
case dicePattern("", sides) => (1, Integer.parseInt(sides))
case dicePattern(quantity, "%") =>
(Integer.parseInt(quantity), 100)
case dicePattern(quantity, sides) =>
(Integer.parseInt(quantity), Integer.parseInt(sides))
}
val rolls = roll(quantity, sides)
val rerolls = (reroll match {
case null => rolls
case rerollPattern("", sn) => {
val n = Integer.parseInt(sn)
val (high, low) = ((rolls dropRight n), (rolls takeRight n))
high ++ roll(low.size, sides)
}
case rerollPattern("h", sn) => {
val n = Integer.parseInt(sn)
val (high, low) = rolls splitAt n
roll(n, sides) ++ low
}
case rerollPattern("l", sn) => {
val n = Integer.parseInt(sn)
val (high, low) = ((rolls dropRight n), (rolls takeRight n))
high ++ roll(low.size, sides)
}
case rerollPattern(">", sn) => {
val n = Integer.parseInt(sn)
val (high, low) = rolls partition { _ > n }
roll(high.size, sides) ++ low
}
case rerollPattern("<", sn) => {
val n = Integer.parseInt(sn)
val (low, high) = rolls partition { _ < n }
high ++ roll(low.size, sides)
}
}) sortWith { _ > _ }
val keptRolls = keep match {
case null =>
rerolls
case keepPattern("", n) =>
rerolls take (Integer.parseInt(n))
case keepPattern("h", n) =>
rerolls take (Integer.parseInt(n))
case keepPattern("l", n) =>
rerolls takeRight (Integer.parseInt(n))
case keepPattern(">", sn) =>
val n = Integer.parseInt(sn)
rerolls filter { _ > n }
case keepPattern("<", sn) =>
val n = Integer.parseInt(sn)
rerolls filter { _ < n }
}
val finalRolls = scrap match {
case null =>
keptRolls
case scrapPattern("", n) =>
keptRolls dropRight (Integer.parseInt(n))
case scrapPattern("h", n) =>
keptRolls drop (Integer.parseInt(n))
case scrapPattern("l", n) =>
keptRolls dropRight (Integer.parseInt(n))
case scrapPattern(">", sn) =>
val n = Integer.parseInt(sn)
keptRolls filterNot { _ > n }
case scrapPattern("<", sn) =>
val n = Integer.parseInt(sn)
keptRolls filterNot { _ < n }
}
val total = if(finalRolls.isEmpty) 0 else {
val sum = finalRolls reduce { _ + _ }
val multSum = multiplier match {
case null => sum
case multiplierPattern("*", mult) =>
sum * Integer.parseInt(mult)
case multiplierPattern("/", mult) =>
sum / Integer.parseInt(mult).toDouble
}
multSum + (bonus match {
case null => 0
case bonusPattern(n) => Integer.parseInt(n)
})
}
(rolls, rerolls, finalRolls, total)
}
}
require(args.size >= 1, "need 1 argument")
for(arg <- args) {
println(arg)
val (rolls, rerolls, finalRolls, total) = roll(arg)
println(rolls mkString ", ")
println(rerolls mkString ", ")
println(finalRolls mkString ", ")
printf(" = %.0f (%f)\n", total, total)
println()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment