Добавление другого подхода, имеющий:
board = structure(c("A", "A", "Q", "Q", "Q", "Q", "Q", "Q", "A", "P",
"P", "Q", "Q", "Q", "L", "E", "Q", "Q", "Q", "Q"), .Dim = 4:5, .Dimnames = list(
NULL, NULL))
word = "APPLE"
мы начинаем с:
matches = lapply(strsplit(word, NULL)[[1]], function(x) which(x == board, arr.ind = TRUE))
, которая является простым -Наверное unavoidable- поиском индексов «доски», которые соответствуют каждой букве слова. Это «список», содержащий индексы строк/COL, как:
#[[1]]
# row col
#[1,] 1 1
#[2,] 2 1
#[3,] 1 3
#
#[[2]]
# row col
#[1,] 2 3
#[2,] 3 3
#
##.....
Имея это, мы должны выяснить, постепенно, имеет ли индекс в каждом элементе соседа (т.е. вправо/влево/вверх/вниз ячейка) в следующем элементе. Например.нам нужно что-то вроде:
as.matrix(find_neighbours(matches[[1]], matches[[2]], dim(board)))
# [,1] [,2]
#[1,] FALSE FALSE
#[2,] FALSE FALSE
#[3,] TRUE FALSE
, который сообщает нам, что строка 3 из matches[[1]]
является соседом ряда 1 из matches[[2]]
, т.е. [1, 3]
и [2, 3]
, действительно, соседние клетки. Нам это нужно для каждого последующего элемента «спичек»:
are_neighs = Map(function(x, y) which(find_neighbours(x, y, dim(board)), TRUE),
matches[-length(matches)], matches[-1])
are_neighs
#[[1]]
# [,1] [,2]
#[1,] 3 1
#
#[[2]]
# [,1] [,2]
#[1,] 2 1
#[2,] 1 2
#
#[[3]]
# [,1] [,2]
#[1,] 2 1
#
#[[4]]
# [,1] [,2]
#[1,] 1 1
Теперь, когда мы имеем парно («я» с «я + 1») соседа совпадает мы должны завершить цепочку. В этом примере мы хотели бы иметь такой вектор, как c(1, 2, 1, 1)
, который содержит информацию о том, что строка 1 из are_neighs[[1]]
связана цепью с строкой 2 из are_neighs[[2]]
, которая прикована к строке 1 из are_neighs[[3]]
, которая прикована к строке 1 из are_neighs[[4]]
. Это пахнет проблемы «igraph», но я не так хорошо знаком с ним (надеюсь, кто-то есть идея получше), так вот наивный подход, чтобы получить, что цепочки:
row_connections = matrix(NA_integer_, nrow(are_neighs[[1]]), length(are_neighs))
row_connections[, 1] = 1:nrow(are_neighs[[1]])
cur = are_neighs[[1]][, 2]
for(i in 1:(length(are_neighs) - 1)) {
im = match(cur, are_neighs[[i + 1]][, 1])
cur = are_neighs[[i + 1]][, 2][im]
row_connections[, i + 1] = im
}
row_connections = row_connections[complete.cases(row_connections), , drop = FALSE]
который возвращает:
row_connections
# [,1] [,2] [,3] [,4]
#[1,] 1 2 1 1
Имея этот вектор, теперь мы можем извлечь соответствующую цепочку из «are_neighs»:
Map(function(x, i) x[i, ], are_neighs, row_connections[1, ])
#[[1]]
#[1] 3 1
#
#[[2]]
#[1] 1 2
#
#[[3]]
#[1] 2 1
#
#[[4]]
#[1] 1 1
, которые могут быть использованы для извлечения соответствующей строки/COL цепочки индексов от «совпадений»:
ans = vector("list", nrow(row_connections))
for(i in 1:nrow(row_connections)) {
connect = Map(function(x, i) x[i, ], are_neighs, row_connections[i, ])
ans[[i]] = do.call(rbind, Map(function(x, i) x[i, ], matches, c(connect[[1]][1], sapply(connect, "[", 2))))
}
ans
#[[1]]
# row col
#[1,] 1 3
#[2,] 2 3
#[3,] 3 3
#[4,] 3 4
#[5,] 4 4
Обертывание все это в функции (find_neighbours
определяется внутри):
library(Matrix)
ff = function(word, board)
{
matches = lapply(strsplit(word, NULL)[[1]], function(x) which(x == board, arr.ind = TRUE))
find_neighbours = function(x, y, d)
{
neighbours = function(i, j, d = d)
{
ij = rbind(cbind(i, j + c(-1L, 1L)), cbind(i + c(-1L, 1L), j))
ijr = ij[, 1]; ijc = ij[, 2]
ij = ij[((ijr > 0L) & (ijr <= d[1])) & ((ijc > 0L) & (ijc <= d[2])), ]
ij[, 1] + (ij[, 2] - 1L) * d[1]
}
x.neighs = lapply(1:nrow(x), function(i) neighbours(x[i, 1], x[i, 2], dim(board)))
y = y[, 1] + (y[, 2] - 1L) * d[1]
x.sparse = sparseMatrix(i = unlist(x.neighs),
j = rep(seq_along(x.neighs), lengths(x.neighs)),
x = 1L, dims = c(prod(d), length(x.neighs)))
y.sparse = sparseMatrix(i = y, j = seq_along(y), x = 1L, dims = c(prod(d), length(y)))
ans = crossprod(x.sparse, y.sparse, boolArith = TRUE)
ans
}
are_neighs = Map(function(x, y) which(find_neighbours(x, y, dim(board)), TRUE), matches[-length(matches)], matches[-1])
row_connections = matrix(NA_integer_, nrow(are_neighs[[1]]), length(are_neighs))
row_connections[, 1] = 1:nrow(are_neighs[[1]])
cur = are_neighs[[1]][, 2]
for(i in 1:(length(are_neighs) - 1)) {
im = match(cur, are_neighs[[i + 1]][, 1])
cur = are_neighs[[i + 1]][, 2][im]
row_connections[, i + 1] = im
}
row_connections = row_connections[complete.cases(row_connections), , drop = FALSE]
ans = vector("list", nrow(row_connections))
for(i in 1:nrow(row_connections)) {
connect = Map(function(x, i) x[i, ], are_neighs, row_connections[i, ])
ans[[i]] = do.call(rbind, Map(function(x, i) x[i, ], matches, c(connect[[1]][1], sapply(connect, "[", 2))))
}
ans
}
Мы можем попробовать:
ff("APPLE", board)
#[[1]]
# row col
#[1,] 1 3
#[2,] 2 3
#[3,] 3 3
#[4,] 3 4
#[5,] 4 4
И с более чем матчей:
ff("AQQP", board)
#[[1]]
# row col
#[1,] 1 1
#[2,] 1 2
#[3,] 2 2
#[4,] 2 3
#
#[[2]]
# row col
#[1,] 1 3
#[2,] 1 2
#[3,] 2 2
#[4,] 2 3
#
#[[3]]
# row col
#[1,] 1 3
#[2,] 1 4
#[3,] 2 4
#[4,] 2 3
Хотя, это гибкий при возвращении нескольких совпадений он не возвращает все возможные совпадения и, в двух словах, из-за использования match
при построении цепочки соседей - вместо этого можно использовать линейный поиск, но в данный момент добавляет значительный код сложность.
Добро пожаловать в StackOverflow. Пожалуйста, ознакомьтесь с этими советами о том, как создать [минимальный, полный и проверенный пример] (http://stackoverflow.com/help/mcve), а также этот пост в [создании отличного примера в R] (http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example).Возможно, следующие советы по [заданию хорошего вопроса] (http://stackoverflow.com/help/how-to-ask) также могут быть полезны для чтения. – lmo
никогда не думал писать коды для игр в R! :) –