commit 6ec0094fb4b4966f17cdf9930853bf3d12ec3b9b Author: Joel Therrien Date: Mon Mar 18 20:56:07 2019 -0700 Initial commit diff --git a/.Rbuildignore b/.Rbuildignore new file mode 100644 index 0000000..91114bf --- /dev/null +++ b/.Rbuildignore @@ -0,0 +1,2 @@ +^.*\.Rproj$ +^\.Rproj\.user$ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4b65d5a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.Rproj +.Rproj.user diff --git a/DESCRIPTION b/DESCRIPTION new file mode 100644 index 0000000..7dc308d --- /dev/null +++ b/DESCRIPTION @@ -0,0 +1,14 @@ +Package: DndDice +Type: Package +Title: What the Package Does (Title Case) +Version: 0.1.0 +Author: Who wrote it +Maintainer: The package maintainer +Description: More about what it does (maybe more than one line) + Use four spaces when indenting paragraphs within the Description. +License: What license is it under? +Encoding: UTF-8 +LazyData: true +Imports: + ggplot2 (>= 3.1.0) +RoxygenNote: 6.1.1 diff --git a/NAMESPACE b/NAMESPACE new file mode 100644 index 0000000..aa077f8 --- /dev/null +++ b/NAMESPACE @@ -0,0 +1,24 @@ +# Generated by roxygen2: do not edit by hand + +S3method("*",Die) +S3method("+",Die) +S3method("<",Die) +S3method("<=",Die) +S3method("==",Die) +S3method(">",Die) +S3method(">=",Die) +S3method(mean,Die) +S3method(plot,Die) +S3method(print,Die) +S3method(summary,Die) +export(advantage) +export(d10) +export(d12) +export(d20) +export(d4) +export(d6) +export(d8) +export(disadvantage) +export(makeDie) +export(roll) +import(ggplot2) diff --git a/R/disadvantage_advantage.R b/R/disadvantage_advantage.R new file mode 100644 index 0000000..d4212b0 --- /dev/null +++ b/R/disadvantage_advantage.R @@ -0,0 +1,102 @@ + +#' +#' Disadvantage +#' +#' Disadvantage a die roll, which means that when both die are rolled, the result +#' is the lower number. +#' +#' @param x A die to roll. +#' @param y A die to roll. If not specified, then x is disadvantaged against itself. +#' @return A die representing the minimum of both die +#' @examples +#' disadvantage(d20,d20) +#' +#' @export +disadvantage <- function(x, y=NULL){ + if(is.null(y)){ + y = x + } + + minX = min(x$numbers) + minY = min(y$numbers) + + maxX = max(x$numbers) + maxY = max(y$numbers) + + range_z_min = pmin(minX, minY) + range_z_max = pmin(maxX, maxY) + + z_numbers = c() + probabilities = c() + for(num in range_z_min:range_z_max){ + prob_x_eq_num = getProbabilitiy(x, num) + prob_y_eq_num = getProbabilitiy(y, num) + + y_geq_nums = y$numbers[y$numbers >= num] # >= not a mistake + x_ge_nums = x$numbers[x$numbers > num] + + prob_y_geq_nums = sum(getProbabilitiy(y, y_geq_nums)) + prob_x_ge_nums = sum(getProbabilitiy(x, x_ge_nums)) + + prob_num = prob_x_eq_num*prob_y_geq_nums + prob_x_ge_nums*prob_y_eq_num + if(prob_num > 0){ + z_numbers = c(z_numbers, num) + probabilities = c(probabilities, prob_num) + } + } + + z = makeDie(z_numbers, probabilities) + return(z) + +} + +#' +#' Advantage +#' +#' Advantage a die roll, which means that when both die are rolled, the result +#' is the higher number. +#' +#' @param x A die to roll. +#' @param y A die to roll. If not specified, then x is advantaged against itself. +#' @return A die representing the maximum of both die +#' @examples +#' advantage(d20,d20) +#' +#' @export +advantage <- function(x, y=NULL){ + if(is.null(y)){ + y = x + } + + minX = min(x$numbers) + minY = min(y$numbers) + + maxX = max(x$numbers) + maxY = max(y$numbers) + + range_z_min = pmax(minX, minY) + range_z_max = pmax(maxX, maxY) + + z_numbers = c() + probabilities = c() + for(num in range_z_min:range_z_max){ + prob_x_eq_num = getProbabilitiy(x, num) + prob_y_eq_num = getProbabilitiy(y, num) + + y_leq_nums = y$numbers[y$numbers <= num] # <= not a mistake + x_le_nums = x$numbers[x$numbers < num] + + prob_y_leq_nums = sum(getProbabilitiy(y, y_leq_nums)) + prob_x_le_nums = sum(getProbabilitiy(x, x_le_nums)) + + prob_num = prob_x_eq_num*prob_y_leq_nums + prob_x_le_nums*prob_y_eq_num + if(prob_num > 0){ + z_numbers = c(z_numbers, num) + probabilities = c(probabilities, prob_num) + } + } + + z = makeDie(z_numbers, probabilities) + return(z) + +} diff --git a/R/internal_functions.R b/R/internal_functions.R new file mode 100644 index 0000000..2953faa --- /dev/null +++ b/R/internal_functions.R @@ -0,0 +1,69 @@ +getProbabilitiy <- function(x, numbers){ + positions = match(numbers, x$numbers) + probs = x$probs[positions] + + probs[is.na(probs)] = 0 + + return(probs) +} + + +sumTwoDie <- function(x, y){ + range_z_min = min(x$numbers) + min(y$numbers) + range_z_max = max(x$numbers) + max(y$numbers) + + z_numbers = c() + probabilities = c() + for(num in range_z_min:range_z_max){ + prob_num = sum(x$probs * getProbabilitiy(y, num - x$numbers)) + if(prob_num > 0){ + z_numbers = c(z_numbers, num) + probabilities = c(probabilities, prob_num) + } + } + + z = makeDie(z_numbers, probabilities) + return(z) +} + +# comparerFun(x, y); which both x & y as Die, or one of them as numeric +compareDie <- function(x, y, comparerFun){ + if(class(x) == "Die" & class(y) == "Die"){ + jointProbs = expand.grid(x$probs, y$probs) + jointProbs = jointProbs[,1]*jointProbs[,2] + + jointNumbers = expand.grid(x$numbers, y$numbers) + matchResults = comparerFun(jointNumbers[,1], jointNumbers[,2]) + probTrue = sum(jointProbs[matchResults]) + + z = makeDie(c(F,T), probs=c(1-probTrue, probTrue)) + return(z) + } + + if(class(x) %in% c("numeric", "integer")){ + die = y + constant = x + + xNumbers = constant + yNumbers = die$numbers + + } else if(class(y) %in% c("numeric", "integer")){ + die = x + constant = y + + xNumbers = die$numbers + yNumbers = constant + + } else{ + stop("Can only compare two die or a die and a number") + } + + if(length(constant) != 1){ + stop("Length of constant must be 1") + } + + matchResults = comparerFun(xNumbers, yNumbers) + probTrue = sum(die$probs[matchResults]) + + z = makeDie(c(F,T), probs=c(1-probTrue, probTrue)) +} diff --git a/R/makeDie.R b/R/makeDie.R new file mode 100644 index 0000000..1838de0 --- /dev/null +++ b/R/makeDie.R @@ -0,0 +1,25 @@ +#' +#' Create a custom die. +#' +#' @param numbers A vector of the numbers that the die can roll on +#' @param probs A vecor of the probabilities for the numbers that the die can +#' roll on. By default the probabilities are assumed to be equal. +#' @return A \code{Die} object containing a vector of numbers the die can roll +#' on, as well as a vector of probabilities. It also has a text label set. +#' @seealso \code{\link{mean.Die}}, \code{\link{plot.Die}}, +#' \code{\link{summary.Die}}, and \code{\link{print.Die}}. +#' @examples +#' stealth <- makeDie(1:20+3) +#' summary(stealth) +#' +#' @export +makeDie <- function(numbers, probs=NULL){ + if(is.null(probs)){ + probs = rep(1 / length(numbers), times=length(numbers)) + } + + die = list(numbers=numbers, probs=probs) + class(die) <- "Die" + + return(die) +} diff --git a/R/mean_print_summary_plot.R b/R/mean_print_summary_plot.R new file mode 100644 index 0000000..e21204e --- /dev/null +++ b/R/mean_print_summary_plot.R @@ -0,0 +1,65 @@ + +#' +#' Calculate the mean of a die. +#' +#' Calculate the mean. +#' +#' @param x A die +#' @return The expected value of the die. +#' @examples +#' mean(d20) +#' +#' @export +mean.Die <- function(x){ + return(sum(x$numbers*x$probs)) +} + +#' +#' Print a die. +#' +#' Rolls a die a single time. +#' +#' @param x A die to roll. +#' @param ... Other parameters to pass to \code{\link{roll}} +#' @examples +#' print(d20) +#' +#' @export +print.Die <- function(x, ...){ + print(roll(x, ...)) +} + + +#' +#' Print a die's summary. +#' +#' Return the probabilities of a die for different rolls. +#' +#' @param x A die +#' @return A vector of named probabilities for each outcome of the die. +#' @examples +#' summary(advantage(d20,d20)) +#' @export +summary.Die <- function(x){ + probs <- x$probs + names(probs) <- x$numbers + return(probs) +} + +#' +#' Plot a die's summary. +#' +#' Plot the probabilities of a die for different rolls. +#' +#' @param x A die +#' @return A ggplot2 plot. +#' @examples +#' plot(advantage(d20,d20)) +#' +#' @export +plot.Die <- function(x){ + data = data.frame(Number=x$numbers, Probability=x$probs) + plt = ggplot(data, aes(x=Number, y=Probability)) + geom_col() + + return(plt) +} diff --git a/R/operators.R b/R/operators.R new file mode 100644 index 0000000..a216fc0 --- /dev/null +++ b/R/operators.R @@ -0,0 +1,89 @@ + +#' @export +'+.Die' <- function(x, y){ + if(class(x) == "Die" & class(y) == "Die"){ + return(sumTwoDie(x, y)) + } + + if(class(x) %in% c("numeric", "integer")){ + die = y + constant = x + } else if(class(y) %in% c("numeric", "integer")){ + die = x + constant = y + } else{ + stop("Can only add two die or a die and a number") + } + + + if(length(constant) != 1){ + stop("Length of constant must be 1") + } + + die$numbers <- die$numbers + constant + + return(die) + +} + + +#' @export +'>.Die' <- function(x,y){ + return(compareDie(x, y, `>`)) +} + +#' @export +'>=.Die' <- function(x,y){ + return(compareDie(x, y, `>=`)) +} + +#' @export +'<.Die' <- function(x,y){ + return(compareDie(x, y, `<`)) +} + +#' @export +'<=.Die' <- function(x,y){ + return(compareDie(x, y, `<=`)) +} + +#' @export +'==.Die' <- function(x,y){ + return(compareDie(x, y, `==`)) +} + + +#' @export +'*.Die' <- function(x, y){ + # At least one of the types should be numeric or integer + if(!(class(x) %in% c("numeric", "integer")) & !(class(y) %in% c("numeric", "integer"))){ + stop("At least one type must be numeric") + } + + if(class(x) == "Die"){ + die = x + times = y + } + else{ + die = y + times = x + } + + times = as.integer(round(times)) + + if(times < 1){ + stop("Cannot multiply a die by less than 1") + } + + if(times == 1){ + return(die) + } + + result = die + for(i in 2:times){ + result = result + die + } + + return(result) + +} diff --git a/R/roll.R b/R/roll.R new file mode 100644 index 0000000..f4ec0d8 --- /dev/null +++ b/R/roll.R @@ -0,0 +1,16 @@ +#' +#' Roll a die. +#' +#' Description. +#' +#' @param x A die to roll. +#' @param times How many times the die should be rolled. +#' @return A numeric vector representing the die rolls. +#' @examples +#' roll(d20) +#' roll(d20, times=10) +#' +#' @export +roll <- function(x, times=1){ + return(sample(x$numbers, size=times, replace=TRUE, prob=x$probs)) +} diff --git a/R/z_build_in_dice.R b/R/z_build_in_dice.R new file mode 100644 index 0000000..6ee41f0 --- /dev/null +++ b/R/z_build_in_dice.R @@ -0,0 +1,40 @@ +#' Built in Dice +#' +#' Built in dice available to use. You can create your own using +#' \code{\link{makeDie}} +#' +#' @format +#' +#' @name BuiltInDice +NULL + + +#' @rdname BuiltInDice +#' @examples roll(d4) +#' @export +d4 = makeDie(1:4) + +#' @rdname BuiltInDice +#' @examples roll(d6) +#' @export +d6 = makeDie(1:6) + +#' @rdname BuiltInDice +#' @examples roll(d8) +#' @export +d8 = makeDie(1:8) + +#' @rdname BuiltInDice +#' @examples roll(d10) +#' @export +d10 = makeDie(1:10) + +#' @rdname BuiltInDice +#' @examples roll(d12) +#' @export +d12 = makeDie(1:12) + +#' @rdname BuiltInDice +#' @examples roll(d20) +#' @export +d20 = makeDie(1:20) diff --git a/R/zzz.R b/R/zzz.R new file mode 100644 index 0000000..d0bfb23 --- /dev/null +++ b/R/zzz.R @@ -0,0 +1,2 @@ +#' @import ggplot2 +NULL diff --git a/man/BuiltInDice.Rd b/man/BuiltInDice.Rd new file mode 100644 index 0000000..9956946 --- /dev/null +++ b/man/BuiltInDice.Rd @@ -0,0 +1,39 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/z_build_in_dice.R +\docType{data} +\name{BuiltInDice} +\alias{BuiltInDice} +\alias{d4} +\alias{d6} +\alias{d8} +\alias{d10} +\alias{d12} +\alias{d20} +\title{Built in Dice} +\format{} +\usage{ +d4 + +d6 + +d8 + +d10 + +d12 + +d20 +} +\description{ +Built in dice available to use. You can create your own using +\code{\link{makeDie}} +} +\examples{ +roll(d4) +roll(d6) +roll(d8) +roll(d10) +roll(d12) +roll(d20) +} +\keyword{datasets} diff --git a/man/advantage.Rd b/man/advantage.Rd new file mode 100644 index 0000000..610183b --- /dev/null +++ b/man/advantage.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/disadvantage_advantage.R +\name{advantage} +\alias{advantage} +\title{Advantage} +\usage{ +advantage(x, y = NULL) +} +\arguments{ +\item{x}{A die to roll.} + +\item{y}{A die to roll. If not specified, then x is advantaged against itself.} +} +\value{ +A die representing the maximum of both die +} +\description{ +Advantage a die roll, which means that when both die are rolled, the result +is the higher number. +} +\examples{ +advantage(d20,d20) + +} diff --git a/man/disadvantage.Rd b/man/disadvantage.Rd new file mode 100644 index 0000000..cccca1c --- /dev/null +++ b/man/disadvantage.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/disadvantage_advantage.R +\name{disadvantage} +\alias{disadvantage} +\title{Disadvantage} +\usage{ +disadvantage(x, y = NULL) +} +\arguments{ +\item{x}{A die to roll.} + +\item{y}{A die to roll. If not specified, then x is disadvantaged against itself.} +} +\value{ +A die representing the minimum of both die +} +\description{ +Disadvantage a die roll, which means that when both die are rolled, the result +is the lower number. +} +\examples{ +disadvantage(d20,d20) + +} diff --git a/man/makeDie.Rd b/man/makeDie.Rd new file mode 100644 index 0000000..66b9337 --- /dev/null +++ b/man/makeDie.Rd @@ -0,0 +1,30 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/makeDie.R +\name{makeDie} +\alias{makeDie} +\title{Create a custom die.} +\usage{ +makeDie(numbers, probs = NULL) +} +\arguments{ +\item{numbers}{A vector of the numbers that the die can roll on} + +\item{probs}{A vecor of the probabilities for the numbers that the die can +roll on. By default the probabilities are assumed to be equal.} +} +\value{ +A \code{Die} object containing a vector of numbers the die can roll + on, as well as a vector of probabilities. It also has a text label set. +} +\description{ +Create a custom die. +} +\examples{ +stealth <- makeDie(1:20+3) +summary(stealth) + +} +\seealso{ +\code{\link{mean.Die}}, \code{\link{plot.Die}}, + \code{\link{summary.Die}}, and \code{\link{print.Die}}. +} diff --git a/man/mean.Die.Rd b/man/mean.Die.Rd new file mode 100644 index 0000000..6f565ac --- /dev/null +++ b/man/mean.Die.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/mean_print_summary_plot.R +\name{mean.Die} +\alias{mean.Die} +\title{Calculate the mean of a die.} +\usage{ +\method{mean}{Die}(x) +} +\arguments{ +\item{x}{A die} +} +\value{ +The expected value of the die. +} +\description{ +Calculate the mean. +} +\examples{ +mean(d20) + +} diff --git a/man/plot.Die.Rd b/man/plot.Die.Rd new file mode 100644 index 0000000..049eaeb --- /dev/null +++ b/man/plot.Die.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/mean_print_summary_plot.R +\name{plot.Die} +\alias{plot.Die} +\title{Plot a die's summary.} +\usage{ +\method{plot}{Die}(x) +} +\arguments{ +\item{x}{A die} +} +\value{ +A ggplot2 plot. +} +\description{ +Plot the probabilities of a die for different rolls. +} +\examples{ +plot(advantage(d20,d20)) + +} diff --git a/man/print.Die.Rd b/man/print.Die.Rd new file mode 100644 index 0000000..57ff842 --- /dev/null +++ b/man/print.Die.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/mean_print_summary_plot.R +\name{print.Die} +\alias{print.Die} +\title{Print a die.} +\usage{ +\method{print}{Die}(x, ...) +} +\arguments{ +\item{x}{A die to roll.} + +\item{...}{Other parameters to pass to \code{\link{roll}}} +} +\description{ +Rolls a die a single time. +} +\examples{ +print(d20) + +} diff --git a/man/roll.Rd b/man/roll.Rd new file mode 100644 index 0000000..b2bed22 --- /dev/null +++ b/man/roll.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/roll.R +\name{roll} +\alias{roll} +\title{Roll a die.} +\usage{ +roll(x, times = 1) +} +\arguments{ +\item{x}{A die to roll.} + +\item{times}{How many times the die should be rolled.} +} +\value{ +A numeric vector representing the die rolls. +} +\description{ +Description. +} +\examples{ +roll(d20) +roll(d20, times=10) + +} diff --git a/man/summary.Die.Rd b/man/summary.Die.Rd new file mode 100644 index 0000000..195df08 --- /dev/null +++ b/man/summary.Die.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/mean_print_summary_plot.R +\name{summary.Die} +\alias{summary.Die} +\title{Print a die's summary.} +\usage{ +\method{summary}{Die}(x) +} +\arguments{ +\item{x}{A die} +} +\value{ +A vector of named probabilities for each outcome of the die. +} +\description{ +Return the probabilities of a die for different rolls. +} +\examples{ +summary(advantage(d20,d20)) +}