I have a data frame which specifies "bridge games" (every row is one independent game), see a minimal example with 4 games below:
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
How does the bridge game work? Candidates all over the world participate in a bridge game challenge and we have collected the data of every bridge game in a data frame. Every bridge consists of numbered wooden panels (positive integers that not necessarily have to start at 1) and "gaps" of broken panels. The candidate can choose from which side of the bridge he is starting his walk (ascending = the numbering of the panel increases as the walk progresses; or descending = the numbering of the panel decreases as the walk progresses).
A graphic for a better understanding of the bridge game can be found here (exemplified for the 1st row in the data frame): click here
For every bridge game (= row in the data frame) we have the following information (= columns):
What is the challenge? I need to write a script that I can run row-wise over the whole data frame to get the following output:
Importantly, it should work for any number i of whole tracts of wooden panels.
To be more precise I give a step-by-step instruction how the requested R script should operate below:
0) solved
a) Convert list of characters into numeric list for columns bridge_game$start and bridge_game$end.
b) Calculate i (the number of tracts of whole wooden panels; i goes from 1 to i=max for every row) and sort the start and end positions to get the correct start and end values for every i.
1) Test whether the position is at a broken panel: end(i=1 to max-1) > position > start(i=2 to max) --> if TRUE for any of the tested pairs --> "disqualified"
2) If no, test in which tract of whole panels the given position lies (i = n): start(i=1 to max) <= position <= end(i=1 to max) --> if TRUE give back i (= n)
3)
a) Apply this formula (if direction is ascending "+" and n = 1): output = position - start(i=1) + 1
b) Apply this formula (if direction is descending "-" and n = i max): output = end(i=max) - position + 1
c)Apply this formula (if direction is ascending "+" and n > 1): output = position - start(i=1) + 1 - (start(i=2 to n) - end(i=1 to n-1) - 1x[n-1])
d) Apply this formula (if direction is descending "-" and n < i max): output = end(i=max) - position + 1 - (start(i=n+1 to max) - end(i=n to max-1) - 1x[i=max - n])
I hope I got the math right there. To check for the correct output I have created a "desired_output" column in the "bridge_game" data frame.
Thanks for your help!
It seems i have more simple solution for step #3. Function npanels
creates a vector from the panel numbers, determines the position of the player's stop in it. If the direction of movement is positive (ascending
variable is "+"
), then this is the desired solution, if negative, then the desired value is calculated based on the length of this vector.
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