Это сработает матрица любого размера (ограниченная аппаратным обеспечением) и не требует, чтобы матрица была прямоугольной angular например, 3 x 4. Она строит матрицу достоверности, в которой все исходные позиции матрицы представлены в виде столбцов, и строка будет верните TRUE
, если это верный ход, и FALSE
, если нет. Я не проверил все результаты, но выборочные проверки, которые я сделал, сработали.
library(gtools)
# convert matrix to numbers to reference by position
m <- matrix(seq_along(mat_3x3), ncol = ncol(mat_3x3))
# create blank matrix that is used to see if it is a valid move
mLength <- length(m)
mValid <- matrix(rep(FALSE, mLength ^ 2), ncol = mLength)
# create index to generate validity matrix
xIndex <- seq_len(ncol(m))
yIndex <- seq_len(nrow(m))
# wrap with NA to prevent out of bounds
mBounds <- rbind(NA, cbind(NA, m, NA), NA)
# set validity matrix TRUE if returns a value that is not NA
mValid[cbind(as.vector(mBounds[yIndex + 1, xIndex + 2]), seq_len(mLength))] <- TRUE
mValid[cbind(as.vector(mBounds[yIndex + 2, xIndex + 2]), seq_len(mLength))] <- TRUE
mValid[cbind(as.vector(mBounds[yIndex + 2, xIndex + 1]), seq_len(mLength))] <- TRUE
mValid[cbind(as.vector(mBounds[yIndex + 2, xIndex ]), seq_len(mLength))] <- TRUE
mValid[cbind(as.vector(mBounds[yIndex + 1, xIndex ]), seq_len(mLength))] <- TRUE
mValid[cbind(as.vector(mBounds[yIndex , xIndex ]), seq_len(mLength))] <- TRUE
mValid[cbind(as.vector(mBounds[yIndex , xIndex + 1]), seq_len(mLength))] <- TRUE
mValid[cbind(as.vector(mBounds[yIndex , xIndex + 2]), seq_len(mLength))] <- TRUE
# define function to check if provided sequence is valid
validate <- function(x) {
all(mValid[cbind(x[-1], x[-length(x)])])
}
# generate all permutations
p1 <- permutations(mLength, mLength)
p2 <- apply(p1, 1, validate)
p2 <- p1[p2, ]
# some results
> mat_3x3[p2[1, ]]
[1] "A" "D" "G" "E" "B" "C" "F" "H" "I"
> mat_3x3[p2[531, ]]
[1] "C" "E" "H" "G" "D" "A" "B" "F" "I"
Для генерации других последовательностей, в которых не используются все буквы, потребуется изменить приведенную выше функцию permutations
, чтобы ограничить длину целевого вектора :
p1 <- permutations(mLength, mLength - 1)
p2 <- apply(p1, 1, validate)
p2 <- p1[p2, ]
> mat_3x3[p2[1701, ]]
[1] "C" "F" "B" "D" "G" "E" "I" "H"
Использование combinat::permn
для использования функции validate
при построении перестановок.
library(combinat)
p <- list()
pTemp <- permn(mLength, function(x) x[validate(x)])
p[[mLength]] <- pTemp[lengths(pTemp) > 0]
# breaking all paths that use every option into smaller pieces to find shorter paths
for (i in seq_len(mLength)[-mLength]) {
pTemp <- lapply(p[[mLength]], function(x, y) embed(rev(x), length(x) - y), y = i)
p[[mLength - i]] <- unique(do.call(rbind, pTemp))
}
# total number of paths
sum(unlist(lapply(p, nrow)), length(p[[mLength]]))