Verify the queens puzzle
Snails, 14 bytes
&
o.,\Q!(z.,\Q
Try it online!
Nothing like a 2D pattern matching language for a 2D decision problem. :)
Explanation
The &
on the first line is a match mode option which requires the pattern on the second line to match from every possible position in the input. If that's the case, the program prints 1
, otherwise it prints 0
.
As for the pattern itself, note that there's an implicit )
at the end.
o ,, Move in any orthogonal direction (up, down, left or right).
.,\Q ,, Make sure that there's a Q somewhere in that direction from the
,, starting position of the match.
!( ,, After finding the Q, make sure that the following part _doesn't_ match:
z ,, Move in any orthogonal or diagonal direction.
.,\Q ,, Try to find another Q in a straight line.
)
Why this works is easiest to see by starting from the negative lookahead: by ensuring that there is no Q
in a straight line from the other Q
we've already found, we make sure that there are no more than N queens (otherwise, there would have to be two in one row, and it wouldn't be possible to find these queens without finding another). Then the first part, making sure that there's a queen reachable in an orthogonal direction from any position, makes sure that there are exactly N queens. If one was missing, there would be a row and a column without a queen. Starting from the intersection of these, it wouldn't be possible to find a queen by going only in an orthogonal direction.
Jelly, 17 or 15 bytes
ỴµUŒD;ŒD;ZVṀ;V=1Ṃ
Try it online!
Uses ‘
for a queen and ¹
for blank space. (This is mostly a consequence of the ban on taking input as an array, because it forces the input to be strings; converting strings to integers is difficult in Jelly, with the easiest method being evaluation, and it turns out that instead of 1 and 0, using "add 1" (‘
) and "add 0" (¹
) make it possible to omit several sum and map instructions, because we can count the queens in a list by evaluating it.) The truthy and falsey values are Jelly's normal 1
and 0
.
EDIT: The question's been changed since I wrote this answer to allow taking input as a matrix. This allows dropping the leading Ỵµ
, saving 2 bytes. It also probably allows changing the input format to something more normal, using S
to sum rather than V
to evaluate, but I don't think that saves bytes and I kind-of like this funky format.
Explanation
ỴµUŒD;ŒD;ZVṀ;V=1Ṃ
Ỵ Split on newlines.
µ Set this value as the default for missing arguments.
; ; Concatenate the following three values:
UŒD - the antidiagonals;
ŒD - the diagonals;
Z - and the columns.
V Evaluate (i.e. count the queens on) all of those.
Ṁ Take the largest value among the results.
;V Append the evaluation (i.e. queen count) of {each row}.
=1 Compare each value to 1.
Ṃ Take the minimum (i.e. most falsey) result.
So the basic idea is that we ensure that there's at most one queen on each antidiagonal, diagonal, and column; and exactly one queen on each row. These conditions are together enough to require that there's at most one queen on each of the four sorts of line, and a number of queens equal to the side length of the board.
Incidentally, Jelly could probably do with a built-in for antidiagonals, but AFAICT it doesn't seem to have one, so I need to settle for reflecting the board and then taking the diagonals.
Another interesting note is that changing =1Ṃ
to E
(all equal) gives a generalized n-queens checker, which will also accept an n×n board where each row, column, diagonal, and antidiagonal contains no more than k queens, and the board contains exactly kn queens. Restricting k to equal 1 actually cost two bytes.
Octave, 57 70 67 51 52 bytes
Saved 1 byte using flip
instead of rot90
thanks to @LuisMendo, but found a bug on the 1x1 case
@(A)all(sum([A A' (d=@spdiags)(A) d(flip(A))],1)==1)
Takes input as a binary matrix with 1 representing a Queen and 0 representing an empty space.
Creates an anonymous function that first concatenates the input matrix and its transpose.
spdiags
creates a matrix with the same number of rows as the argument, with the diagonals turned into columns (zero-padded as necessary), so concatenate spdiags
of the input matrix to get the diagonals and spdiags
of the matrix flipped horizontally to get the antidiagonals.
Now take the sum of each column of the concatenated matrix and make sure each column is exactly 1.
Sample run on ideone.