3

我有一个指定“桥牌游戏”的数据框(每一行都是一个独立的游戏),请参见下面的 4 个游戏的最小示例:

start <- list(c("10","15","5"), c("5") ,c("11","6"),c("6","11"))
end <- list(c("7","17","11"), c("10"), c("8","12"),c("8","12"))
ascending <- c("+","-","+","-")
position <- c(11,6,9,8)
desired_output <- c(5,5,"disqualified",3)

bridge_game <- data.frame(start = I(start), end = I(end), ascending = ascending, position = position, desired_output = desired_output)

bridge_game

桥牌游戏如何运作? 全世界的考生都参加了桥牌比赛挑战,我们在数据框中收集了每场桥牌比赛的数据。每座桥都由编号的木板(不一定必须从 1 开始的正整数)和破碎板的“间隙”组成。候选人可以选择他从桥的哪一侧开始步行(升序 = 面板编号随着步行的进行而增加;或下降 = 面板的编号随着步行的进行而减少)。

可以在此处找到用于更好地理解桥牌游戏的图形(以数据框中的第一行为例): 单击此处

对于每个桥牌游戏(= 数据框中的行),我们有以下信息(= 列):

  • bridge_game$ start : 整块木板的所有起始位置(随机顺序)
  • bridge_game$ end : 整块木板的所有结束位置(随机顺序)
  • bridge_game$升序:以面板升序 (+) 或降序 (-) 的顺序穿过桥
  • bridge_game$ position : 候选人最终出现在指定的小组中

挑战是什么? 我需要编写一个脚本,我可以在整个数据帧上逐行运行以获得以下输出:

  • bridge_game$ desired_output : 测试候选人是否掉入河中(最终在一个破碎的面板上并被“取消资格”)。如果他没有被取消资格,我需要计算候选人步行所覆盖的整个木板的数量(破损的木板不算在内)。

重要的是,它应该适用于任何数量的整块木板

更准确地说,我将逐步说明所请求的 R 脚本应如何在下面运行:

0) 解决了

a) 将字符列表转换为 bridge_game$start 和 bridge_game$end 列的数字列表。

b) 计算i(整个木板的区域数;每行i1i=max)并对开始和结束位置进行排序以获得每个i的正确开始和结束值。

1)测试位置是否在损坏的面板上:end(i=1 to max-1) > position > start(i=2 to max) --> if TRUE for any of the test pairs --> "disqualified"

2)如果不是,测试给定位置位于整个面板的哪个区域(i = n): start(i=1 to max) <= position <= end(i=1 to max) --> if TRUE 回馈我 (= n)

3)

a) 应用此公式(如果方向为升序“+”且 n = 1):输出 = 位置 - 开始(i=1)+ 1

b) 应用此公式(如果方向为下降“-”且 n = i max):输出 = end(i=max) - position + 1

c) 应用这个公式(如果方向是升序“+”并且 n > 1):输出 = 位置 - 开始(i=1)+ 1 -(开始(i=2 到 n) - 结束(i=1 到 n- 1) - 1x[n-1])

d) 应用这个公式(如果方向是下降的“-”并且 n < i max):output = end(i=max) - position + 1 - (start(i=n+1 to max) - end(i=n到 max-1) - 1x[i=max - n])

我希望我在那里得到了数学。为了检查正确的输出,我在“bridge_game”数据框中创建了一个“desired_output”列。

谢谢你的帮助!

4

4 回答 4

4

你把这个问题复杂化了。考虑以下实现

parse_pos <- function(x) sort(as.integer(x))

construct_bridge <- function(starts, ends) {
  starts <- parse_pos(starts); ends <- parse_pos(ends)
  bridge <- logical(tail(ends, 1L))
  whole_panels <- sequence(ends - starts + 1L, starts)
  bridge[whole_panels] <- TRUE
  bridge
}

count_steps <- function(bridge, direction, stop_pos) {
  if (isFALSE(bridge[[stop_pos]]))
    return("disqualified")
  start_pos = c("+" = 1L, "-" = length(bridge))[[direction]]
  sum(bridge[start_pos:stop_pos])
}

play_games <- function(starts, ends, direction, stop_pos) {
  mapply(function(s, e, d, sp) {
    bridge <- construct_bridge(s, e)
    count_steps(bridge, d, sp)
  }, starts, ends, direction, stop_pos)
}

输出

> with(bridge_game, play_games(start, end, ascending, position))
[1] "5"            "5"            "disqualified" "3" 

这里的关键是我们可以使用逻辑向量来表示一个桥,其中一个损坏的/整个面板由F/索引T。然后我们只是测试停止位置是否在整个面板上。如果是这样,则返回从开始位置到结束位置的面板总和(损坏的面板不会影响总和,因为它们只是零)或“不合格”。

于 2020-11-28T19:52:12.603 回答
3

看来我对第 3 步有更简单的解决方案。函数npanels从面板编号创建一个向量,确定玩家在其中停止的位置。如果运动方向为正(ascending变量为"+"),则这是所需的解决方案,如果为负,则根据此向量的长度计算所需的值。

start <- list(c(5,10,15), c(5) ,c(6,11),c(6,11))
end <- list(c(7,11,17), c(10), c(8,12),c(8,12))
position <- c(11,6,9,8)
ascending <- c("+","-","+","-")
game <- data.frame(start = I(start), end = I(end), position = position, ascending = ascending)

npanels <- function (data) {
  v <- unlist(Map(":",
                  unlist(data[["start"]]),
                  unlist(data[["end"]])))
  p <- which(v == data[["position"]])
  l <- length(v)
  b <- 1+l-p
  d <- data[["ascending"]]
  n <- ifelse(d == "+", p, b)
  n <- if(is.na(n)) "disqualified" else n
  return(n)
}

game$solution <- apply(game, 1, npanels)

game
于 2020-11-28T20:01:27.073 回答
2

这可能会为您提供第三步所需的内容。我从您的另一篇文章中修改了该功能。

首先,将检查n(或region)是否为NA. 如果是,则和position之间没有匹配。startend

否则,您可以包含if else查看ascending和的 2x2 组合n。方程使用类似的从 中提取值x。值得注意的是,您似乎想要sum具有一系列索引的值(例如,当您说“开始(i = 2 到 n)”时,您想要sum这些值,例如sum(start[2:n]))。

请注意,这会将您的方程式直接转换为代码,因为它似乎是需要的。但是,基于其他答案中描述的逻辑,还有更简单的替代方案。

start <- list(c(5,10,15), c(5) ,c(6,11),c(6,11))
end <- list(c(7,11,17), c(10), c(8,12),c(8,12))
ascending <- c("+","-","+","-")
imax <- c(3,1,2,2)
position <- c(11,6,9,8)

example <- data.frame(start = I(start), end = I(end), ascending = ascending, imax = imax, position = position)

my_fun <- function(x) {
  n <- NA
  out <- NA
  start <- as.numeric(unlist(x[["start"]]))
  end <- as.numeric(unlist(x[["end"]]))
  for (i in 1:x[["imax"]]) {
    if (between(x[["position"]], start[i], end[i])) n <- i
  }
  if (!is.na(n)) {
    if (x[["ascending"]] == "+") {
      if (n == 1) {
        out <- x[["position"]] - start[1] + 1
      } else if (n > 1) {
        out <- x[["position"]] - start[1] + 1 - (sum(start[2:n]) - sum(end[1:(n-1)]) - (n - 1))
      }
    } else if (x[["ascending"]] == "-") {
      if (n == x[["imax"]]) {
        out <- end[x[["imax"]]] - x[["position"]] + 1  
      } else if (n < x[["imax"]]) {
        out <- end[x[["imax"]]] - x[["position"]] + 1 - (sum(start[(n+1):x[["imax"]]]) - sum(end[n:(x[["imax"]] - 1)]) - (x[["imax"]] - n))
      }
    }
  }
  out
}

example$desired_output <- apply(example, 1, my_fun) 

输出

      start       end ascending imax position desired_output
1 5, 10, 15 7, 11, 17         +    3       11              5
2         5        10         -    1        6              5
3     6, 11     8, 12         +    2        9             NA
4     6, 11     8, 12         -    2        8              3
于 2020-11-28T19:09:39.947 回答
0

更新:

步骤 0) 完成:

#Change to numeric
bridge_game$start <- lapply(bridge_game$start, as.numeric)
bridge_game$end <- lapply(bridge_game$end, as.numeric)

#Calculate number of tracts of whole wooden panels
bridge_game$tracts <- lapply(bridge_game$start, length)

#Sort start and end positions
bridge_game$start <- lapply(bridge_game$start, sort)
bridge_game$end <- lapply(bridge_game$end, sort)

#Calculate number of tracts of whole wooden panels
bridge_game$tracts <- lapply(bridge_game$start, length)

从步骤 1) 开始挣扎...

于 2020-11-26T18:05:23.530 回答