【问题标题】:Creating a Basic R Dice Rolling Function to Sum Dice Values创建一个基本的 R 骰子滚动函数来对骰子值求和
【发布时间】:2021-06-25 16:21:36
【问题描述】:

我正在尝试编写一个函数,该函数最多可组合 4 个(公平的 6 面)骰子,以根据骰子上显示的数字尽可能多地创建一个特定值(名为“target.mountain”)。

然后返回这些值以及所述组合中未使用的任何值。如果不用于形成“target.mountain”的其他数字总和可以在 (5-10) 范围内,那么就这样做。

举个例子,我掷出 4,3,2,5,我的 target.mountain 值为 9

我愿意

4 + 5 -> 9 和 2 + 3 = 5 我的函数将返回 9, 5

另一个例子是

滚动 = (2,3,6,4) --> (6 + 3), (4 + 2) --> 9, 6

一旦找到这些值,然后列出它看起来像

[1] 9, 5(示例 1)

[1] 9, 6(示例 2)

我该怎么做?

如果您曾经玩过棋盘游戏“山羊山”,那么这可能会说明我需要骰子如何工作,因为我无法弄清楚!

【问题讨论】:

  • 为什么不返回4+3+2 == 9, 5
  • 这也可以,但是我想用尽可能少的数字组合来创建目标值,所以理想情况下我想组合 2 而不是组合 3

标签: r dice combn


【解决方案1】:

让我们把问题变得更难一些,比如 5 个骰子。

library(tidyverse)
rolls <- sample(1:6,replace = TRUE, size = 5)
target.mountain <- 7

#Make all possible combinations of the dice:
map_dfr(seq_along(rolls),~ combn(seq_along(rolls),.x,simplify = FALSE) %>%
          map(~tibble(dice = list(.), sum = sum(rolls[.]), rolls = list(rolls[.]),length = length(.)))) %>%
  #filter to only those combinations which equal the target  
  filter(sum == target.mountain) %>%
  #Now make all possible combinations of the sets that equal the target
  {map2(.x = list(.), .y = nrow(.) %>% map(.x = seq(.), .f = combn,x=.,simplify = FALSE) %>% unlist(recursive = FALSE),
        ~.x[unlist(.y),])} %>%
  #Subset to non-overlapping sets
  subset(map_lgl(.,~length(reduce(.x$dice,union))==length(unlist(.x$dice)))) -> part1 

map(part1, as.data.frame)
#[[1]]
#  dice sum rolls length
#1 1, 3   7  3, 4      2
#
#[[2]]
#  dice sum rolls length
#1 4, 5   7  6, 1      2
#
#[[3]]
#     dice sum   rolls length
#1 2, 3, 5   7 2, 4, 1      3
#
#[[4]]
#  dice sum rolls length
#1 1, 3   7  3, 4      2
#2 4, 5   7  6, 1      2

从这里你可以应用你想要的任何规则:

part1 %>% 
  #subset to the largest number of sets
  subset(map_dbl(.,nrow) == max(map_dbl(.,nrow))) %>%
  #subset to the fewest number of total dice
  subset(map_dbl(.,~sum(.x$length)) == min(map_dbl(.,~sum(.x$length)))) %>%
  #if there are still ties, pick the first
  `[[`(1) -> part2

as.data.frame(part2)
#  dice sum rolls length
#1 1, 3   7  3, 4      2
#2 4, 5   7  6, 1      2

【讨论】:

  • 这也很棒,非常感谢您的帮助。但是,如何从地图中提取值以便它们采用列表格式?它只是列表()吗?
  • 奇怪的是,有一个函数dplyr::pull,你可以使用part2 %&gt;% pull(rolls),它会生成一个列表。
  • 你是个英雄,老实说让我免于发疯。非常感谢!
  • 抱歉第二个问题,但我想你不能再帮忙了?现在我知道哪些骰子用于组合以获得 target.mountain 我如何返回()未与列表中的 target.mountain 值一起使用的其他骰子?现在已经玩了一个小时左右。
  • 不断遇到这个错误,不知道如何修复它。错误:.x 为空,且未提供 .init
【解决方案2】:

问题的可能解决方案

target.mountain = 9
dice <- c(4,3,2,5)

library(tidyverse)

fn <- function(target.mountain, dice){
  fltr <- map(seq_along(dice), ~combn(dice, .x, sum) == target.mountain)
  out <- map(seq_along(dice), ~combn(dice, .x))
  sum_target <- map2(out, fltr, ~.x[, .y]) %>% 
    purrr::discard(.x = ., function(x) length(x) == 0) %>% 
    keep(.x = ., .p = function(x) length(x) == min(lengths(.))) %>% 
    flatten_dbl()
  
  no_sum_target <- dice[!(dice %in% sum_target)]
  result <- toString(c(sum(sum_target), no_sum_target))
  return(result)
}

fn(target.mountain = target.mountain, dice = dice)
#> [1] "9, 3, 2"

reprex package (v1.0.0) 于 2021-03-29 创建

【讨论】:

  • 这太棒了!老实说,我已经坚持了好几天了。无法解释这会有多大帮助,因为我不知道该去哪里。现在,我必须返回的值只有在 (5-10) 范围内才有用。既然您已经帮助我获得了我需要的值,是否有一种方法可以组合“剩余”数字(不是 == target.mountain 的数字)以便它们可以使用?如果这没有意义,可以澄清一下吗?
  • 看看@Ian Campbell 的回答,它的用途要广泛得多
  • 没问题,非常感谢您的帮助!意义重大。
  • 很高兴我的回答对你有帮助
猜你喜欢
  • 2014-03-16
  • 2013-09-17
  • 2018-09-24
  • 2019-09-24
  • 2021-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-14
相关资源
最近更新 更多