Advertisement
Guest User

GW2 PvP Division Simulation

a guest
Mar 12th, 2016
25
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
R 6.55 KB | None | 0 0
  1. # Model how many games it takes to advance through a given tier.
  2.  
  3. library(rmarkdown)
  4. library(ggplot2)
  5. library(plyr)
  6. library(tidyr)
  7. library(dplyr)
  8. library(data.table)
  9. library(parallel)
  10.  
  11. setwd('C:\\Users\\admin\\Documents\\GW2math')
  12. set.seed(420) # Set the random seed so results can be duplicated
  13. options(stringsAsFactors = FALSE)
  14.  
  15. # Rules/Specs
  16. rules <- data.frame(
  17.     div = c('Amber', 'Emerald', 'Sapphire', 'Ruby', 'Diamond', 'Legendary'),
  18.     pips = c(3, 4, 5, 5, 5, 5),
  19.     tiers = c(5, 5, 5, 6, 7, 5),
  20.     losePip = c(0, 1, 1, 1, 1, 1),
  21.     loseTier = c(0, 0, 0, 1, 1, 1),
  22.     color = c(  'darkorange', 'forestgreen', 'dodgerblue',
  23.                 'firebrick3', 'darkgrey', 'gray15'))
  24.  
  25. #Function starts here
  26. simulateRun <- function(div, winRate, simNo, maxGames = 500){
  27.  
  28.     div <- rules[rules$div == div,]
  29.  
  30.     # Initialize the variables
  31.     winStrk <- 0
  32.     lossStrk <- 0
  33.     pipNum <- 0
  34.     tierNum <- 1
  35.     totWins <- 0
  36.     totLosses <- 0
  37.     totGames <- 0
  38.  
  39.     while((pipNum < div$pips & tierNum == div$tiers) | tierNum < div$tiers){
  40.  
  41.         # Sanity checks
  42.         if(winStrk != 0 & lossStrk != 0){
  43.             stop('Failed a sanity check')
  44.         }
  45.  
  46.         # Roll to see if you won the game
  47.         winRoll <- runif(1)
  48.         wonGame <- ifelse(winRoll <= winRate, 1, 0)
  49.  
  50.         if(wonGame==1){ # Did you win?
  51.  
  52.             totWins <- totWins + 1 # Increment the win count
  53.             winStrk <- winStrk + 1 # Increment win streak
  54.  
  55.             # Add a bonus pip
  56.             pipBonus <- ifelse(winStrk >=3 | lossStrk >= 3, 1, 0)
  57.             lossStrk <- 0 # Reset the loss streak
  58.  
  59.             if(pipNum + 1 + pipBonus < div$pips){ # Didn't max out the tier
  60.                 pipNum <- pipNum + 1 + pipBonus # Just add the pips
  61.             } else if(pipNum + 1 + pipBonus == div$pips) {
  62.                 # Did max out the tier
  63.                 # Start at 0 pips in the new tier, add bonus if any
  64.                 pipNum <- 0
  65.                 tierNum <- tierNum + 1 # Increment the tier
  66.             } else if(pipNum + 1 + pipBonus > div$pips) {
  67.                 # Maxed out + 1
  68.                 pipNum <- 1
  69.                 tierNum <- tierNum + 1
  70.             }
  71.  
  72.         } else { # Did you lose?
  73.  
  74.             totLosses <- totLosses + 1 # Increment the total losses
  75.             lossStrk <- lossStrk + 1 # Increment loss streak
  76.             winStrk <- 0 # Reset win streak
  77.  
  78.             # Decrement the pip if you can lose pips,
  79.             # but only go down a tier if legal
  80.             if(!div$losePip){
  81.                 # Can't lose pips, do nothing
  82.             } else if(pipNum != 0){
  83.                 # Simple if you're not at the start of a tier
  84.                 pipNum <- pipNum - 1
  85.             } else if(pipNum == 0 & (tierNum == 1 | !div$loseTier)){
  86.                 # Can't go down a division, do nothing
  87.             } else if(pipNum == 0 & div$loseTier){
  88.                  # Go back to 1 missing pip on prior tier if possible
  89.                 pipNum <- div$pips - 1
  90.                 # Decrement the tier if possible
  91.                 tierNum <- tierNum - 1
  92.             } else {
  93.                 stop('Pips/Tiers are messed up')
  94.             }
  95.  
  96.         }
  97.  
  98.         # Increment the number of games played
  99.         totGames <- totGames + 1
  100.  
  101.          # Test to see if this division is maxed
  102.         if(tierNum > div$tiers){
  103.             return(data.frame(
  104.                 div = div$div,
  105.                 wr = winRate,
  106.                 simNo = simNo,
  107.                 totGames = totGames,
  108.                 totWins = totWins,
  109.                 totLosses = totLosses,
  110.                 complete = 1))
  111.         } else if(totGames >= maxGames){ # You died of old age
  112.             return(data.frame(
  113.                 div = div$div,
  114.                 wr = winRate,
  115.                 simNo = simNo,
  116.                 totGames = totGames,
  117.                 totWins = totWins,
  118.                 totLosses = totLosses,
  119.                 complete = 0))
  120.         }
  121.  
  122.     } # While loop ends here
  123.  
  124. }
  125.  
  126. # Simulate an assload of games.
  127. # The time it takes to simulate depends on the total number of games which
  128. # is a function of the number of simulations for each divison*winRate combo
  129. # but also how low the win rate starts out at, as it will take longer to reach
  130. # either the cap (maxGames) or complete the tier.
  131. # Benchmarks on a 4770K:
  132. # 10 sims * seq(0,1,10) = 6000 sims = 1,322,343 in 22.22 secs = 59511.39/s
  133. # 30 sims * seq(0.5,1,20) = 108000 sims = 7,026,476 in 119.9 secs = 58602.8/s
  134. nSim <- 20 # Number of simulations to run
  135. results <- expand.grid( # Create a set of pairs to run (simplifies clusterMap)
  136.     div = rules$div, # Unique combinations of division and...
  137.     wr = seq(0.50, 1, length.out=25),
  138.     simNo = 1:nSim) %>% # win rates...
  139.     arrange(div, wr, simNo) %>% data.table # Order and convert to a data.table
  140. setkey(results, div, wr, simNo)
  141. nrow(results) * nSim # Total number of simulations
  142.  
  143. # Export the data and functions
  144. stopCluster(cl) # Stop cluster if it exists
  145. cl <- makeCluster(8) # Create a cluster with 2x Physical cores
  146. clusterExport(cl, c('rules', 'results', 'simulateRun', '%>%', 'ldply'))
  147. simTimeStart <- Sys.time()
  148. simResults <- clusterMap(cl, function(div, wr, nSim){ # Simualte on each pair
  149.     lapply(1:nSim, function(x){ # Simulate nSims times
  150.         # Use the specified division/win rate
  151.         simulateRun(div = div, winRate = wr, simNo = x)
  152.     }) %>% ldply
  153. }, div = results$div, wr = results$wr, nSim = nSim) %>% ldply %>% data.table
  154. setkey(simResults, div, wr, simNo)
  155. simTimeEnd <- Sys.time()
  156. print(sprintf('Simulated %s games in %s minutes',
  157.     sum(simResults$totGames),
  158.     round(difftime(simTimeEnd, simTimeStart, units = 'mins'), 2)))
  159.  
  160. # Combine the two sets and calculate some summary statistics
  161. results <- results[simResults, nomatch=0] # Join the two sets
  162. glimpse(results)
  163. summary(results)
  164.  
  165. # Check that the number of minimum games is reasonable
  166. results %>%
  167.     group_by(div) %>%
  168.     filter(complete==1) %>%
  169.     summarise(minWins=min(totGames))
  170.  
  171. write.csv(results, paste0(
  172.     'Sim_results_',strftime(Sys.time(), '%m%d%y_%H%M%S'), '.csv'))
  173.  
  174. # Summarise the data by division and win rate
  175. resGrp <- results %>%
  176.     group_by(div, wr) %>%
  177.     summarise(
  178.         medGames = median(totGames),
  179.         maxGames = max(totGames),
  180.         minGames = min(totGames),
  181.         meanGames = mean(totGames),
  182.         sdGames = sd(totGames),
  183.         uclGames = mean(totGames)+1.96*sd(totGames),
  184.         LclGames = mean(totGames)-1.96*sd(totGames))
  185. resGrp
  186.  
  187. # Number of games by win rate
  188. win_game_Plot <- ggplot(resGrp,
  189.     aes(x = wr, y = medGames, fill = div, color = div, group = div)) +
  190.     geom_line(size = 2) +
  191.     facet_wrap(~div, scale='free') +
  192.     scale_color_manual(values = rules$color) +
  193.     ggtitle('Median Number of Games Needed to Rank Out of a Tier by Win Probability (Max 500 Tries)') +
  194.     xlab('Probability of Winning') +
  195.     ylab('Median Number of Games') +
  196.     theme_bw()
  197. win_game_Plot
  198.  
  199. # Stacked Area Chart
  200. stack_wins <- ggplot(resGrp,
  201.     aes(x = wr, y = medGames, fill = div, group = div)) +
  202.     geom_area(position = 'stack') +
  203.     ggtitle('Median Number of Games Needed to Finish All Divisions by Win Probability') +
  204.     xlab('Probability of Winning') +
  205.     ylab('Median Number of Games') +
  206.     scale_x_continuous(breaks = seq(0.45,1.0,0.05), limits = c(0.45,1)) +
  207.     scale_fill_manual(values = rules$color) +
  208.     theme_bw()
  209. stack_wins
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement