Eu montei uma ferramenta para gerar permutações aleatórias de linha / coluna com algumas fórmulas e algum VBA. O layout da folha é assim:
Agradedereferênciaéumexemplotrivialdeumamatrizválida,conformepostadanarespostapreliminardoGary'sStudent(possivelmenteexcluída).Aspermutaçõesdelinhaecolunaincorporamtodasaspossíveiscombinaçõesexclusivasdepermutaçõesparaagrade6x6.(Issopodeserfacilmentemodificadoparaincluirpermutaçõesnãoexclusivas,sedesejado.)OsvaloresemE12:E26
eL12:L26
sãodistribuídosaleatoriamenteparazeroouum,parafornecerabaseparaexecutarounãoumadeterminadapermutação.AscolunasD
eK
apenasasconvertememvaloresbooleanosparamanipulaçãosimplificadanoVBA(vejaabaixo).AgradepermutadaégeradapelafunçãopersonalizadadoSwap
,inseridacomoumafórmuladematriz.PressionarF9
paraacionarorecálculodafolhafazcomqueasváriasfunçõesRAND
geremnovamenteseusvaloresaleatórios,alterandoasériedepermutaçõesaseremexecutadas.
OcódigodoVBAquehabilitaessecomportamentoé:
FunctiondoSwap(srcRgAsRange,rowSwapsAsRange,colSwapsAsRange)AsVariantDimworkVtAsVariantDimiterAsLongworkVt=srcRg.Value'DorowswapsForiter=1TorowSwaps.Rows.CountWithrowSwapsIf.Cells(iter,3).ValueThenworkVt=swapRow(workVt,.Cells(iter,1),.Cells(iter,2))EndIfEndWithNextiter'DocolswapsForiter=1TocolSwaps.Rows.CountWithcolSwapsIf.Cells(iter,3).ValueThenworkVt=swapCol(workVt,.Cells(iter,1),.Cells(iter,2))EndIfEndWithNextiter'StoreandreturndoSwap=workVtEndFunctionFunctionswapCol(ByValinArrAsVariant,idx1AsLong,idx2AsLong)AsVariantDimtempValAsVariant,workVtAsVariantDimiterAsLong'CheckifRangeorArrayinputIfIsObject(inArr)ThenIfTypeOfinArrIsRangeThenworkVt=inArr.ValueElseswapCol="ERROR"
Exit Function
End If
Else
workVt = inArr
End If
' Just crash if not correct size
' Do swap
For iter = LBound(workVt, 1) To UBound(workVt, 1)
tempVal = workVt(iter, idx1)
workVt(iter, idx1) = workVt(iter, idx2)
workVt(iter, idx2) = tempVal
Next iter
' Return
swapCol = workVt
End Function
Function swapRow(ByVal inArr As Variant, idx1 As Long, idx2 As Long) As Variant
Dim tempVal As Variant, workVt As Variant
Dim iter As Long
' Check if Range or Array input
If IsObject(inArr) Then
If TypeOf inArr Is Range Then
workVt = inArr.Value
Else
swapRow = "ERROR"
Exit Function
End If
Else
workVt = inArr
End If
' Just crash if not correct size
' Do swap
For iter = LBound(workVt, 2) To UBound(workVt, 2)
tempVal = workVt(idx1, iter)
workVt(idx1, iter) = workVt(idx2, iter)
workVt(idx2, iter) = tempVal
Next iter
' Return
swapRow = workVt
End Function
O código acima não é bem robusto, mas serve ao propósito atual. A extensão / generalização deve ser bastante direta, se necessário. Em particular, ele deve lidar como é qualquer tamanho de grade de referência 2-D, mesmo que seja não-quadrado. O importante é garantir que as matrizes de instruções de permutação sejam configuradas corretamente.
EDITAR: Depois de brincar um pouco com isso, fica claro que essa solução não fornece acesso ao espaço total de possíveis permutações. Então, eu ajustei adicionando um " bit shift aleatório" para trocar os tipos de etiquetas entre si. Para simplificar, mudei de ABC
labels para 123
labels, o que permite a implementação por meio de uma simples operação MOD
e também uma rápida verificação de sanidade na forma de somas de linha e coluna: