A useful code I found online. Posting here for future reference.
// returns a random integer in the range [a, b] (inclusive)
function rnd(a, b) {
let x = Math.floor(Math.random() * (b - a + 1));
return a + x;
}
// returns a random latin square
function latinSquare(size) {
let b, i, j, m, n;
b = [];
// legally populate board by shifting each row by one
for (i = 0; i < size; i++) {
b[i] = [];
for (j = 0; j < size; j++) {
b[i][j] = ((i + j) % size) + 1;
}
}
// shuffle rows
for (m = size - 1; m > 0; m--) {
n = rnd(0, m); // 0 <= n <= m
swapRows(b, m, n);
}
// shuffle cols
for (m = size - 1; m > 0; m--) {
n = rnd(0, m); // 0 <= n <= m
swapCols(b, m, n);
}
return b;
}
// swaps two rows in a latin square
function swapRows(a, m, n) {
let swap = a[m];
a[m] = a[n];
a[n] = swap;
}
// swaps two columns in a latin square
function swapCols(a, m, n) {
let j, swap;
for (j = 0; j < a[m].length; j++) {
swap = a[j][m];
a[j][m] = a[j][n];
a[j][n] = swap;
}
}
let latin = latinSquare(8);
console.log(latin);