一般来说,如果您正在使用 R 进行编码并考虑使用 for 循环,那么可能有更好的方法来执行此操作。我认为这是一个很好的例子。此外,虽然 Ha Nguyen 的解决方案对于您在问题中遇到的用例是正确的,但很难一概而论。这是因为你的数据结构不是tidy。它不整洁,因为您的列名包含数据:数字足以表明内容与哪个骰子/玩家/等相关。因此,在您模拟的玩家数量、掷骰数和回合数的变化方面,该代码是脆弱的。
一个整洁的解决方案可以避免这个问题,方法是使用单个列来包含掷骰子,并使用额外的列来指示掷骰子所涉及的回合和玩家。
这是一个可能的实现:
library(tidyverse)
simulate <- function(nPlayers=2, nRolls=2, nRounds=12) {
# Generate tidy data
data <- tibble() %>%
expand(
Round=c(1:nRounds),
Player=c(1:nPlayers),
Roll=c(1:nRolls)
) %>%
mutate(Result=ceiling(runif(nrow(.), max=6)))
# Calculate each player's score in each round
totalsByRound <- data %>%
group_by(Round, Player) %>%
summarise(Score=sum(Result), .groups="drop")
# Determine winner for each round
winners <- totalsByRound %>%
group_by(Round) %>%
slice_max(Score) %>%
rename(
Winner=Player,
WinningScore=Score
) %>%
# n() calculates group size with grouped data, so n() > 1 indicates a tie
filter(n() == 1)
# Convert to wide format ease of presentation
totalsByRound <- totalsByRound %>%
pivot_wider(
names_from=Player,
values_from=Score,
names_prefix="Player"
) %>%
left_join(winners, by="Round")
return(totalsByRound)
}
还有一个例子使用
# For repoducibility
set.seed(1234)
# Do the simulation
results <- simulate()
results
# A tibble: 12 x 5
Round Player1 Player2 Winner WinningScore
<int> <dbl> <dbl> <int> <dbl>
1 1 5 8 2 8
2 2 10 3 1 10
3 3 8 9 2 9
4 4 8 8 NA NA
5 5 4 4 NA NA
6 6 4 2 1 4
7 7 7 10 2 10
8 8 6 5 1 6
9 9 6 7 2 7
10 10 4 11 2 11
11 11 8 6 1 8
12 12 6 8 2 8
玩家分数很容易总结:
# Summarise results
results %>%
group_by(Winner) %>%
summarise(RoundsWon=n(), .groups="drop")
# A tibble: 3 x 2
Winner RoundsWon
<int> <int>
1 1 4
2 2 6
3 NA 2
您当然可以在 simulate 函数中包含摘要,但我不确定您的实际用例是什么,所以我省略了。
代码将通过更改参数值来处理其他数量的玩家、回合和滚动:
# Demo for different parameters
simulate(nPlayers=4, nRolls=3, nRounds=100)
# A tibble: 100 x 7
Round Player1 Player2 Player3 Player4 Winner WinningScore
<int> <dbl> <dbl> <dbl> <dbl> <int> <dbl>
1 1 8 11 8 13 4 13
2 2 9 8 7 11 4 11
3 3 7 8 13 8 3 13
4 4 11 9 8 6 1 11
5 5 5 10 5 4 2 10
6 6 9 8 14 8 3 14
7 7 17 11 9 12 1 17
8 8 10 13 14 11 3 14
9 9 12 14 6 14 NA NA
10 10 13 11 6 8 1 13
# … with 90 more rows
整洁的解决方案比使用for 循环更健壮,并且对于“大型”数据集应该明显更快。它也更紧凑,而且我相信更容易理解。