I'm trying the following code to generate a 3x3 sudoku,
[*1..3].permutation.uniq{
_1.index(1) && _1.index(2) && _1.index(3)
}
I'm trying to pass multiple condition in uniq
method, but I can't do so. I've seen other SO post in which they suggest,
uniq{[cond1, cond2, ...]}
But, it doesn't work, tried ||
too.
I think &&
takes only the last, whereas ||
takes only the first condition, as both of them are truthy!
How to solve this?
Expected output:
3x3 sudoku like:
[1, 2, 3]
[2, 3, 1]
[3, 1, 2]
The order of numbers in above sudoku doesn't matter.
I'm trying to use those three parameters in uniqueness, somehow. Like, if any permutation has any number at same index, then drop that one.
I doubt that you can generate a sudoku using uniq
because the method operates on a single element at a time without taking the other elements into account.
You could use a loop to remove those values.
You start by generating all permutations: (I'm using a 4×4 sudoku for demonstration purposes)
permutations = [*1..4].permutation.to_a
#=> [[1, 2, 3, 4], [1, 2, 4, 3], [1, 3, 2, 4], [1, 3, 4, 2], [1, 4, 2, 3], [1, 4, 3, 2],
# [2, 1, 3, 4], [2, 1, 4, 3], [2, 3, 1, 4], [2, 3, 4, 1], [2, 4, 1, 3], [2, 4, 3, 1],
# [3, 1, 2, 4], [3, 1, 4, 2], [3, 2, 1, 4], [3, 2, 4, 1], [3, 4, 1, 2], [3, 4, 2, 1],
# [4, 1, 2, 3], [4, 1, 3, 2], [4, 2, 1, 3], [4, 2, 3, 1], [4, 3, 1, 2], [4, 3, 2, 1]]
From this array, you pick a random element as the first row:
row_1 = permutations.sample #=> [3, 2, 1, 4]
You then remove all elements that have 3
in the 1st spot, or 2
in the 2nd, 1
in 3rd, or 4
in 4th:
permutations.delete_if { |row| row_1.zip(row).any? { |i, j| i == j } }
#=> [[1, 3, 4, 2], [1, 4, 2, 3], [1, 4, 3, 2],
# [2, 1, 4, 3], [2, 3, 4, 1], [2, 4, 3, 1],
# [4, 1, 2, 3], [4, 1, 3, 2], [4, 3, 2, 1]]
From the remaining array, you can pick another random element as the second row and start over:
row_2 = permutations.sample #=> [2, 3, 4, 1]
permutations.delete_if { |row| row_2.zip(row).any? { |i, j| i == j } }
#=> [[1, 4, 2, 3], [1, 4, 3, 2],
# [4, 1, 2, 3], [4, 1, 3, 2]]
row_3 = permutations.sample #=> [1, 4, 3, 2]
permutations.delete_if { |row| row_3.zip(row).any? { |i, j| i == j } }
#=> [[4, 1, 2, 3]]
row_4 = permutations.sample #=> [4, 1, 2, 3] (or permutations.last)
The resulting row_1
, row_2
, row_3
and row_4
are: (printed as a sudoku)
╔═════╤═════╗
║ 3 2 │ 1 4 ║
║ 2 3 │ 4 1 ║
╟─────┼─────╢
║ 1 4 │ 3 2 ║
║ 4 1 │ 2 3 ║
╚═════╧═════╝
You might notice that although rows and columns only contain unique numbers, the 2×2 subgrids contain duplicates. It is therefore invalid.
You could probably add another condition that takes the subgrids into account, but there are much easier ways to generate a valid sudoku. Here's one:
You generate a random valid first row, e.g.:
row_1 = [*1..4].shuffle #=> [3, 4, 2, 1]
For the 2nd row, you rotate the first row by 2: (the subgrid size)
row_2 = row_1.rotate(2) #=> [2, 1, 3, 4]
For the 3rd and 4th row, you rotate the first row by 1 and 3 respectively:
row_3 = row_1.rotate(1) #=> [4, 2, 1, 3]
row_4 = row_1.rotate(3) #=> [1, 3, 4, 2]
Printed as a sudoku:
╔═════╤═════╗
║ 3 4 │ 2 1 ║
║ 2 1 │ 3 4 ║
╟─────┼─────╢
║ 4 2 │ 1 3 ║
║ 1 3 │ 4 2 ║
╚═════╧═════╝