+# S-290 PingPong Ball
+#
+# The following R program was designed for use in cold calling in a
+# class room environment. It takes a list of options, selects one at
+# random and returns it, and then adjusts the weights so that the
+# selected option is relatively less likely to be selected in the next
+# draw.
+#
+# The software was written by Benjamin Mako Hill <mako@atdot.cc> and
+# is released into the public domain.
+
+# replace this line with a list of the names from which we want to sample
+member.names <- c("Alonso", "Alejandro", "Andres", "Becky",
+ "Deborah", "Lauren", "Mako", "Nikhit", "North",
+ "Steve")
+
+# set the default weight: after being selected the likelihood of the
+# selected value being chosen will be reduced to 1 over this value
+pp.weight <- 2
+
+# create a variable which we'll use to keep track of who has been selected
+reset.weights <- function () {
+ w <- rep(1, length(member.names))
+ names(w) <- member.names
+ assign("w", w, envir=.GlobalEnv)
+}
+
+# only run this if you want to create new we
+if (!exists("w")) reset.weights()
+
+get.ping.pong.ball <- function () {
+ # create the "jar" according to the weights
+ weighted.names <- c(sapply(member.names,
+ function (x) {rep(x, w[x])}), recursive=TRUE)
+ # select something out of it
+ selected <- sample(weighted.names, 1)
+
+ # adjust the weights for the next run based on what was selected
+ w[!names(w) == selected] <- w[!names(w) == selected] * pp.weight
+
+ # if we can reduce the weights by a lowest common denom, do it
+ if (all((w %% pp.weight) == 0)) w <- w / pp.weight
+
+ # save the variable in the global namespace so we can return to it next time
+ assign("w", w, envir=.GlobalEnv)
+
+ # clean up the output and return the value
+ names(selected) <- NULL
+ return(selected)
+}
+
+# run this function to get a person selected
+get.ping.pong.ball()
+
+# run the following function to reset the weights
+reset.weights()