sudoku-revenge | 7 solves
Let’s play sudoku! For real this time…
Description
The TLDR of this challenge is to generate a Latin Square of size n
such that given a permutation a
containing numbers from 1 to n, the a[i]
th cell of row i
of our board has the value i
. This proves to be quite straightforward for boards where n
is odd, although proves to not be as intuitive for even n
. However we can note that this problem is equivalent to the existance of an idempotent quasigroup of order n, or in other words, there is a latin square of size n such that the main diagonal is ordered numbers 1 to n. This turns out to have a quite simple inductive proof, and this proof can be used to generate boards for even n
.
We are given a file sudoku-revenge.py
. The code (while not very nicely formatted), does the following:
- It generates a number
n
between 100, 200 which is the size of the board - It then generates a list
a
with numbers from1
ton
, and shuffles the list - Finally, it takes a
n
xn
board as input, and validates that thea[i]
th cell of rowi
of our board has the valuei
First off, we should note that there is a simpler problem we can solve first: which is:
- Generate a Latin Square with the diagonals being
[1, n]
strictly increasing.
This works since columns of a latin square can clearly be shuffled, so we can simply shuffle each respective number into its original place. Since the a
list is a permutation, this will always work.
Now we can try generating a Latin Square, and theres a pretty simple way to do this:
- Create an array from [1, n]
- then repeatedly append the array rotated by 1 with wrapping.
The implementation is something like this:
1 | row = [i for i in range(1, n+1)] |
Consider for example, n = 5
:
1 | |1, 2, 3, 4, 5| |
Now as an observation, note the existance of 1, n in each row:
1 | |1, , , , | |
It seems to be in row 1, 3, 5, …, followed by row 2, 4, 6, …, and this ends up being true for all odd n!
But if we try this strategy on even n:
1 | |1, 2, 3, 4| |
1 | |1, , , | |
Unfortunately they overlap, so we cannot directly use this.
I played with this for a while, trying different patterns and so on, but it wasnt trivial. I then found this paper.
What this exactly describes is a way to create a idempotent latin square of size n+1 from a idempotent latin square of size n.
Solution
So here is the overall idea. We can create a function called create(n)
which creates a latin square of size n. For the odd case, its simple, we just unshuffle the rows in the way as described above.
1 |
|
Now for the even case, we use the inductive strategy. We can first get a board of size n-1, which will be odd. Then we can apply the transformation as described.
1 | else: |
Finally, whenever we get an n
from the server, and an a
from the server, we can compute the idempotent latin square, then unshuffle it based on the a array.
1 | p = remote(HOST, PORT) |
Flag
1 | nbctf{th1s_1s_whY_y0U_t3s7_tH3_ch3Ck3r_f1r57} |