Generate all unique permutations and convert to data frame

# Loading necessary libraries
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.2     ✔ tibble    3.3.0
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.0.4     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(combinat)
## 
## Attaching package: 'combinat'
## 
## The following object is masked from 'package:utils':
## 
##     combn
# Setting seed for reproducibility
set.seed(1234)

# Defining the conditions
conditions <- c("NS", "S", "SN")

# Generating all unique permutations
perm_unique <- permn(conditions)

# Converting the list of permutations to a transposed dataframe and naming columns
perm_df <- map_dfr(perm_unique, ~as.data.frame(t(.x))) %>%
  rename_with(~paste0("condition_", seq_along(.))) %>%
  mutate(permutation = row_number()) %>%
  select(permutation, contains("condition"))

# Viewing the generated permutations
print(perm_df)
##   permutation condition_1 condition_2 condition_3
## 1           1          NS           S          SN
## 2           2          NS          SN           S
## 3           3          SN          NS           S
## 4           4          SN           S          NS
## 5           5           S          SN          NS
## 6           6           S          NS          SN

Randomize the Order of the Rows (Permutations)

# Randomizing the order of the rows (permutations)
perm_random <- perm_df %>%
  slice_sample(n = nrow(perm_df)) %>%
  mutate(participant = row_number()) %>%
  select(participant, contains("condition"))

# Viewing the randomized permutations
print(perm_random)
##   participant condition_1 condition_2 condition_3
## 1           1          SN           S          NS
## 2           2          NS          SN           S
## 3           3           S          SN          NS
## 4           4          NS           S          SN
## 5           5           S          NS          SN
## 6           6          SN          NS           S

Assigning 30 (fully counterbalanced) Participants to the Randomised Sequences

# Number of participants
n_participants <- 30

# Number of unique sequences generated (6 permutations)
n_sequences <- nrow(perm_df)

# Verify the number of sequences
print(n_sequences)
## [1] 6
# Randomly assigning participants to sequences
assignments <- sample(rep(1:n_sequences, each = n_participants / n_sequences))

# Creating the final dataframe with assignments
final_assignments <- data.frame(
  Participant = 1:n_participants,
  Sequence = assignments,
  Condition1 = perm_random[assignments, "condition_1"],
  Condition2 = perm_random[assignments, "condition_2"],
  Condition3 = perm_random[assignments, "condition_3"]
)

# Viewing the final assignments
print(final_assignments)
##    Participant Sequence Condition1 Condition2 Condition3
## 1            1        2         NS         SN          S
## 2            2        1         SN          S         NS
## 3            3        2         NS         SN          S
## 4            4        4         NS          S         SN
## 5            5        1         SN          S         NS
## 6            6        1         SN          S         NS
## 7            7        2         NS         SN          S
## 8            8        5          S         NS         SN
## 9            9        6         SN         NS          S
## 10          10        3          S         SN         NS
## 11          11        3          S         SN         NS
## 12          12        4         NS          S         SN
## 13          13        6         SN         NS          S
## 14          14        4         NS          S         SN
## 15          15        6         SN         NS          S
## 16          16        2         NS         SN          S
## 17          17        4         NS          S         SN
## 18          18        5          S         NS         SN
## 19          19        1         SN          S         NS
## 20          20        4         NS          S         SN
## 21          21        2         NS         SN          S
## 22          22        6         SN         NS          S
## 23          23        5          S         NS         SN
## 24          24        5          S         NS         SN
## 25          25        3          S         SN         NS
## 26          26        3          S         SN         NS
## 27          27        6         SN         NS          S
## 28          28        5          S         NS         SN
## 29          29        1         SN          S         NS
## 30          30        3          S         SN         NS
LS0tCnRpdGxlOiAiUEVBVCBQcm9qZWN0OiBSYW5kb21pc2F0aW9uIFByb2Nlc3MiCmF1dGhvcjogIkxheWFuIEZlc3NsZXIiCmRhdGU6ICIyMDI1LTA5LTE3IgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGVkaXRvcl9vcHRpb25zOiBudWxsCiAgbWFya2Rvd246CiAgICB3cmFwOiBzZW50ZW5jZQogIHdvcmRfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKLS0tCgoKIyBHZW5lcmF0ZSBhbGwgdW5pcXVlIHBlcm11dGF0aW9ucyBhbmQgY29udmVydCB0byBkYXRhIGZyYW1lIApgYGB7cn0KIyBMb2FkaW5nIG5lY2Vzc2FyeSBsaWJyYXJpZXMKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoY29tYmluYXQpCgojIFNldHRpbmcgc2VlZCBmb3IgcmVwcm9kdWNpYmlsaXR5CnNldC5zZWVkKDEyMzQpCgojIERlZmluaW5nIHRoZSBjb25kaXRpb25zCmNvbmRpdGlvbnMgPC0gYygiTlMiLCAiUyIsICJTTiIpCgojIEdlbmVyYXRpbmcgYWxsIHVuaXF1ZSBwZXJtdXRhdGlvbnMKcGVybV91bmlxdWUgPC0gcGVybW4oY29uZGl0aW9ucykKCiMgQ29udmVydGluZyB0aGUgbGlzdCBvZiBwZXJtdXRhdGlvbnMgdG8gYSB0cmFuc3Bvc2VkIGRhdGFmcmFtZSBhbmQgbmFtaW5nIGNvbHVtbnMKcGVybV9kZiA8LSBtYXBfZGZyKHBlcm1fdW5pcXVlLCB+YXMuZGF0YS5mcmFtZSh0KC54KSkpICU+JQogIHJlbmFtZV93aXRoKH5wYXN0ZTAoImNvbmRpdGlvbl8iLCBzZXFfYWxvbmcoLikpKSAlPiUKICBtdXRhdGUocGVybXV0YXRpb24gPSByb3dfbnVtYmVyKCkpICU+JQogIHNlbGVjdChwZXJtdXRhdGlvbiwgY29udGFpbnMoImNvbmRpdGlvbiIpKQoKIyBWaWV3aW5nIHRoZSBnZW5lcmF0ZWQgcGVybXV0YXRpb25zCnByaW50KHBlcm1fZGYpCgpgYGAKIyBSYW5kb21pemUgdGhlIE9yZGVyIG9mIHRoZSBSb3dzIChQZXJtdXRhdGlvbnMpCmBgYHtyfQojIFJhbmRvbWl6aW5nIHRoZSBvcmRlciBvZiB0aGUgcm93cyAocGVybXV0YXRpb25zKQpwZXJtX3JhbmRvbSA8LSBwZXJtX2RmICU+JQogIHNsaWNlX3NhbXBsZShuID0gbnJvdyhwZXJtX2RmKSkgJT4lCiAgbXV0YXRlKHBhcnRpY2lwYW50ID0gcm93X251bWJlcigpKSAlPiUKICBzZWxlY3QocGFydGljaXBhbnQsIGNvbnRhaW5zKCJjb25kaXRpb24iKSkKCiMgVmlld2luZyB0aGUgcmFuZG9taXplZCBwZXJtdXRhdGlvbnMKcHJpbnQocGVybV9yYW5kb20pCmBgYAoKIyBBc3NpZ25pbmcgMzAgKGZ1bGx5IGNvdW50ZXJiYWxhbmNlZCkgUGFydGljaXBhbnRzIHRvIHRoZSBSYW5kb21pc2VkIFNlcXVlbmNlcwpgYGB7cn0KIyBOdW1iZXIgb2YgcGFydGljaXBhbnRzCm5fcGFydGljaXBhbnRzIDwtIDMwCgojIE51bWJlciBvZiB1bmlxdWUgc2VxdWVuY2VzIGdlbmVyYXRlZCAoNiBwZXJtdXRhdGlvbnMpCm5fc2VxdWVuY2VzIDwtIG5yb3cocGVybV9kZikKCiMgVmVyaWZ5IHRoZSBudW1iZXIgb2Ygc2VxdWVuY2VzCnByaW50KG5fc2VxdWVuY2VzKQoKIyBSYW5kb21seSBhc3NpZ25pbmcgcGFydGljaXBhbnRzIHRvIHNlcXVlbmNlcwphc3NpZ25tZW50cyA8LSBzYW1wbGUocmVwKDE6bl9zZXF1ZW5jZXMsIGVhY2ggPSBuX3BhcnRpY2lwYW50cyAvIG5fc2VxdWVuY2VzKSkKCiMgQ3JlYXRpbmcgdGhlIGZpbmFsIGRhdGFmcmFtZSB3aXRoIGFzc2lnbm1lbnRzCmZpbmFsX2Fzc2lnbm1lbnRzIDwtIGRhdGEuZnJhbWUoCiAgUGFydGljaXBhbnQgPSAxOm5fcGFydGljaXBhbnRzLAogIFNlcXVlbmNlID0gYXNzaWdubWVudHMsCiAgQ29uZGl0aW9uMSA9IHBlcm1fcmFuZG9tW2Fzc2lnbm1lbnRzLCAiY29uZGl0aW9uXzEiXSwKICBDb25kaXRpb24yID0gcGVybV9yYW5kb21bYXNzaWdubWVudHMsICJjb25kaXRpb25fMiJdLAogIENvbmRpdGlvbjMgPSBwZXJtX3JhbmRvbVthc3NpZ25tZW50cywgImNvbmRpdGlvbl8zIl0KKQoKIyBWaWV3aW5nIHRoZSBmaW5hbCBhc3NpZ25tZW50cwpwcmludChmaW5hbF9hc3NpZ25tZW50cykKYGBgCgoK