N-Queens Puzzle

17

1

(Despite 60+ questions tagged , we don't have a simple n-queens challenge.)

In chess, the N-Queens Puzzle is described as follows: Given an n x n chessboard and n queens, arrange the queens onto the chessboard so that no two queens are threatening each other. Below is an example solution for n = 8, borrowed from Wikipedia.

8-queens example solution from Wikipedia

Or, in ASCII rendering:

xxxQxxxx
xxxxxxQx
xxQxxxxx
xxxxxxxQ
xQxxxxxx
xxxxQxxx
Qxxxxxxx
xxxxxQxx

The challenge here will be to take input n and output an ASCII representation of a solution to the n-Queens puzzle. Since there are more than one possible solution (e.g., at the least, a rotation or reflection), your code only needs to output any valid solution.

Input

A single positive integer n with n >= 4 in any convenient format. (n=2 and n=3 have no solutions, and n=1 is trivial, so those are excluded)

Output

The resulting ASCII representation of a solution to the N-queens puzzle, as outlined above. You may choose any two distinct ASCII values to represent blank spaces and queens. Again, this can be output in any suitable format (single string, a list of strings, a character array, etc.).

Rules

  • Leading or trailing newlines or whitespace are all optional, as well as whitespace between characters, so long as the characters themselves line up correctly.
  • You can either use an algorithm to calculate the possible positions, or use the explicit "stair-step" style of solution, whichever is golfier for your code.
  • Either a full program or a function are acceptable. If a function, you can return the output rather than printing it.
  • If possible, please include a link to an online testing environment so other people can try out your code!
  • Standard loopholes are forbidden.
  • This is so all usual golfing rules apply, and the shortest code (in bytes) wins.

Examples

n=4
xQxx
xxxQ
Qxxx
xxQx

n=7
xxQxxxx
xxxxxxQ
xQxxxxx
xxxQxxx
xxxxxQx
Qxxxxxx
xxxxQxx

n=10
xxxxQxxxxx
xxxxxxxxxQ
xxxQxxxxxx
xxxxxxxxQx
xxQxxxxxxx
xxxxxxxQxx
xQxxxxxxxx
xxxxxxQxxx
Qxxxxxxxxx
xxxxxQxxxx

AdmBorkBork

Posted 2017-07-21T14:03:59.523

Reputation: 41 581

1Related. – totallyhuman – 2017-07-21T14:07:26.230

1Could you give testcases for odd inputs? – user41805 – 2017-07-21T14:13:29.317

@Cowsquack Added n=7 example – AdmBorkBork – 2017-07-21T14:32:13.503

@KeyuGan Neither of those have the [tag:code-golf] tag, so I don’t think they’re even candidate dupes – Lynn – 2017-07-21T14:59:26.617

Could we output an array of number instead of an array of characters? – Keyu Gan – 2017-07-21T15:57:14.893

1@KeyuGan Something like the MATL answer? Yeah, that's fine. – AdmBorkBork – 2017-07-21T16:02:28.887

@AdmBorkBork was "You can either use an algorithm to calculate the possible positions, or use the explicit "stair-step" style of solution, whichever is golfier for your code." meant to exclude non-deterministic solutions such as loop-with-random-permute&check? – Jonathan Allan – 2017-07-21T18:43:57.630

2@JonathanAllan No such exclusion was intended, so long as the program finishes in finite time with probability one (as standard for all submissions). – AdmBorkBork – 2017-07-21T18:45:18.770

Are one of these the relevant oeis sequence?

– programmer5000 – 2017-07-22T10:36:43.313

@programmer5000 The first result, A000170, is the relevant problem in that it tells how many solutions exist, but none of OEIS gives the actual board positions, which is what this question is asking. – AdmBorkBork – 2017-07-23T14:29:17.303

Answers

5

MATL, 33 32 27 bytes

`x,GZ@]1Z?tt!P!,w&TXds]h1>a

Try it online!

Semi-brute force, non-determistic approach:

  1. Generate a random permutation of row positions
  2. Generate a random permutation of column positions
  3. Check that no queens share a diagonal or anti-diagonal
  4. Repeat if necessary.

The obtained solution is random. If you run the code again you may get a different valid configuration. Running time is also random, but the longest test case (n = 10) finishes in about 30 seconds in TIO most of the time.

Luis Mendo

Posted 2017-07-21T14:03:59.523

Reputation: 87 464

I'm not sure this counts as a solution, given that it doesn't always give the correct answer. – junkmail – 2017-07-21T15:23:17.997

1@junkmail Huh? There is no such thing as the correct answer, as there a several solutions (as stated by the challenge). The code always gives a correct answer, just not the same every time – Luis Mendo – 2017-07-21T15:24:23.860

It's theoretically possible for the program to run arbitrarily many times and still fail to give an answer. – junkmail – 2017-07-21T15:28:01.073

1@junkmail But it finishes in finite time with probability one – Luis Mendo – 2017-07-21T15:28:33.717

Hmm, I read "You can either use an algorithm to calculate the possible positions, or use the explicit "stair-step" style of solution, whichever is golfier for your code." as excluding this approach, but I wasn't sure and forgot to ask. I have now. EDIT: the approach has been approved by OP. – Jonathan Allan – 2017-07-21T18:44:09.103

@JonathanAllan Thanks for helping clarify this – Luis Mendo – 2017-07-21T20:42:20.137

The problem with generating random permutations is that you are probably relying on a pseudorandom generator to do it. And that pseudorandom generator will ultimately just cycle through a finite sequence. So it could, in fact, simply run forever. The cycle would be very long though. – James Hollis – 2017-07-22T10:30:20.770

1@JamesHollis I disagree. That could make some permutations more likely than others, but it wouldn't prevent any permutation from appearing. So the solution would eventually be reached. And in addition, assuming the random generator is ideal is usually accepted – Luis Mendo – 2017-07-22T10:33:01.300

5

C, 114 bytes

Q(n,o,y){o=n%2;n-=o;for(y=0;y<n+o;++y)printf("%*c\n",y<n?o+n-(n+y%(n/2)*2+(n%6?y<n/2?n/2-1:2-n/2:y<n/2))%n:0,81);}

Directly prints a solution in O(1) time.

orlp

Posted 2017-07-21T14:03:59.523

Reputation: 37 067

1It's not clear to me how it can be O(1) with a loop repeating n times. How can all of those calculations always be done in constant time? – poi830 – 2017-07-22T03:10:48.837

1@poi830 I mean O(1) computation time per row to determine the position of the queen. – orlp – 2017-07-22T03:18:52.533

couldn't you save a few by making a new variable for n/2? – Jeffmagma – 2017-12-26T02:44:24.757

Suggest n-=o=n%2;for(y=n+o;y--;) instead of o=n%2;n-=o;for(y=0;y<n+o;++y) – ceilingcat – 2019-01-24T07:18:11.013

2

Mathematica, 103 108 110 117 bytes

-5 bytes for DuplicateFreeQ -> E!=##&@@@

-7 bytes for ReplacePart[Array[],] -> SparseArray[]

SparseArray[Thread@#&@@Select[Permutations@Range@#~Tuples~2,And@@(E!=##&@@@{#-#2,+##})&@@#&]->1,{#,#}]&

Return a 2D-array. It takes 2.76s to calculate f[6] and 135s for f[7]. (In the current version, - becomes 0 and Q to 1.

output

The algorithm is similar to MATL answer but here the code is completely brute-force.

Keyu Gan

Posted 2017-07-21T14:03:59.523

Reputation: 2 028

1

C - 222 bytes

v,i,j,k,l,s,a[99];main(){for(scanf("%d",&s);*a-s;v=a[j*=v]-a[i],k=i<s,j+=(v=j<s&&(!k&&!!printf(2+"\n\n%c"-(!l<<!j)," #Q"[l^v?(l^j)&1:2])&&++l||a[i]<s&&v&&v-i+j&&v+i-j))&&!(l%=s),v||(i==j?a[i+=k]=0:++a[i])>=s*k&&++a[--i]);}

The code is not mine, but from the IOCCC. I hope I'm not breaking any rules. Also, this displays all solutions for N between 4 and 99. I'll try to get a TIO link later.

QuaerendoInvenietis

Posted 2017-07-21T14:03:59.523

Reputation: 11

As this code isn't yours, could you convert it into a Community Wiki? (just click the button below the editing window that says "Community Wiki") – caird coinheringaahing – 2017-07-21T18:26:33.987

Hi QuaerendoInvenietis and welcome to PPCG. As it's currently written, this doesn't seem to take a particular number as input and output only that solution. – AdmBorkBork – 2017-07-21T18:47:28.807

1

Python 3, 204 189 bytes

import itertools as p
n=int(input())
r=range(n)
b='.'*(n-1)+'Q'
for c in p.permutations(r):
 if len(set((x*z+c[x],z)for x in r for z in[1,-1]))==n+n:[print(*(b[x:]+b[:x]))for x in c];break

Brute force search through all permutations. I could remove the * and print the list comprehensions, but they look awful.

Output:

10
Q . . . . . . . . .
. . Q . . . . . . .
. . . . . Q . . . .
. . . . . . . Q . .
. . . . . . . . . Q
. . . . Q . . . . .
. . . . . . . . Q .
. Q . . . . . . . .
. . . Q . . . . . .
. . . . . . Q . . .

Slightly ungolfed:

import itertools as p
n=int(input())
r=range(n)
b='.'*(n-1)+'Q'
for c in p.permutations(r):
    if len(set( (x*z+c[x],z) for x in r for z in[1,-1] )) == n+n:
        [print(*(b[x:] + b[:x])) for x in c]
        break

James Hollis

Posted 2017-07-21T14:03:59.523

Reputation: 221

1

Jelly, 24 21 bytes

,JŒc€IF€An/PC
ẊÇ¿=þRG

Try it online!

Assuming each queen are placed on separate rows, we only need to find the column indices to place each queen at to avoid conflicts, which can be found by generating a random permutation of [1, 2, ..., n] and testing it.

Explanation

,JŒc€IF€An/PC  Helper. Input: permutation of [1, 2, ..., n]
 J             Enumerate indices, obtains [1, 2, ..., n]
,              Join
  Œc€          Find all pairs in each
     I         Calculate the difference of each pair
      F€       Flatten each
        A      Absolute value
               (We now have the distance in column between each queen and
                the distance in rows between each queen. If they are unequal,
                the queens do not conflict with each other)
         n/    Reduce using not-equals
           P   Product, returns 1 only if they are all unequal
            C  Complement
               Returns 1 when there is a conflict, else 0

ẊÇ¿=þRG  Main.  Input: n
Ẋ        Shuffle (When given an integer, it will shuffle [1, 2, ..., n])
 Ç¿      While the helper returns 1, continue shuffling
     R   Range, gets [1, 2, ..., n]
   =þ    Equality table (Generates the board as a matrix)
      G  Pretty-print the matrix

miles

Posted 2017-07-21T14:03:59.523

Reputation: 15 654

Can't you use Œc€ instead of œc€2 for -1? – Erik the Outgolfer – 2017-07-22T13:36:00.920

1

Befunge, 122 bytes

&::2%-v>2*00g++00g%00g\-\00g\`*4>8#4*#<,#-:#1_$55+"Q",,:#v_@
/2p00:<^%g01\+*+1*!!%6g00-2g01\**!!%6g00-g012!:`\g01:::-1<p01

Try it online!

This is more or less based on the C solution by orlp.

Explanation

Source code with execution paths highlighted

* Read the number of queens, q, from stdin and calculate two variables for later use: n = q - q%2, and hn = n/2
* Start the main loop, iterating r, the row number, from q down to 0, decrementing at the start of the loop, so the first r is q minus 1.
* Calculate the offset of the queen in each row with the following formula:

offset = (n - (
  (hn <= r) * (2 - hn) * !!(n % 6) + 
  (hn > r) * ((hn - 2) * !!(n % 6) + 1) + 
  (y % hn * 2) + n
) % n) * (n > r)

* Output offset space characters to indent the queen's position for the current row, plus one additional space just because it makes the output loop easier.
* Output the Q for the queen, followed by a newline to move to the next row.
* Test if r is zero, in which case we've reached the end of the board and can exit, otherwise we repeat the main loop again.

James Holderness

Posted 2017-07-21T14:03:59.523

Reputation: 8 298

0

Haskell, 145 bytes

The obvious brute force approach:

b=1>0
t[]=b
t(q:r)=all(/=q)r&&foldr(\(a,b)->(abs(q-b)/=a&&))b(zip[1..]r)&&t r
q n|y<-[1..n]=(\q->(' '<$[1..q])++"Q")<$>[x|x<-mapM(\_->y)y,t x]!!0

Try it online!

ბიმო

Posted 2017-07-21T14:03:59.523

Reputation: 15 345

0

Retina, 136 bytes

.+
$* 
 
$_;$`Q¶
( +)\1( ?);
:$1;
:( +);\1\1
$1$1
:((   )+);( *)
 $1$1% $3$3
: ( +);( \1)?( *)
 $1 $1%$#2$* $#2$* $#2$* $1$3$3
( +)%\1?

Try it online! Port of @orlp's excellent C answer. Explanation:

.+
$* 

Convert to unary, using spaces (there is a space after the *).

$_;$`Q¶

Create N rows with N spaces, a ;, then 0..N-1 spaces, then a Q. The remaining stages apply to all rows.

( +)\1( ?);
:$1;

Integer divide N by 2. (Also wrap the result in :; to make it easier to anchor patterns.)

:( +);\1\1
$1$1

If the loop index equals N/2*2, then just leave that many spaces.

:((   )+);( *)
 $1$1% $3$3

If N/2 is a multiple of 3, then take double the loop index plus one, modulo N/2*2+1.

: ( +);( \1)?( *)
 $1 $1%$#2$* $#2$* $#2$* $1$3$3

Otherwise, take double the loop index plus (N/2-1) plus an extra 3 in the bottom half of the board, modulo N/2*2.

( +)%\1?

Actually perform the modulo operation.

Neil

Posted 2017-07-21T14:03:59.523

Reputation: 95 035

0

Charcoal, 44 bytes

Nθ≔÷θ²ηEθ◧Q⊕⎇⁼ι⊗ηι⎇﹪η³﹪⁺⁺⊗ι⊖η׳¬‹ιη⊗η﹪⊕⊗ι⊕⊗η

Try it online! Link is to verbose version of code. Another port of @orlp's excellent C answer.

Neil

Posted 2017-07-21T14:03:59.523

Reputation: 95 035

0

APL (Dyalog Unicode), 18 bytesSBCS

Full program prompting for n from stdin. Prints space-separated solution to stdout using · for empty squares and for Queens.

⎕CY'dfns'
⊃queens⎕

Try it online!

⎕CY'dfns'Copy the "dfns" library

 get input from stdin

queens find all truly unique Queens' solutions (no reflections or rotations)

 pick the first solution

Adám

Posted 2017-07-21T14:03:59.523

Reputation: 37 779

0

J, 49 bytes

i.=/0({(1-.@e.,)@(([:(=#\){.|@-}.)\."1)#])!A.&i.]

Try it online!

Brute force by testing all permutations of length n.

miles

Posted 2017-07-21T14:03:59.523

Reputation: 15 654