
N-queen puzzle in 4 lines of Scala - pathikrit
https://gist.github.com/pathikrit/6fa878fe87c6160a52c4c27dabbfa6df
======
dkopi
While definitely great proof of: 1\. The author knowing a lot of the
language's functional features (permutations, mapping, zipping, filters) 2\.
How powerful functional programming is when solving problems

I find this type of code an anti pattern of how good code should be. This
solution has a high "cognitive load" imho: [http://chrismm.com/blog/how-to-
reduce-the-cognitive-load-of-...](http://chrismm.com/blog/how-to-reduce-the-
cognitive-load-of-your-code/)

I'd much rather see a 15-20 line solution that's clear and readable, than a 4
line solution that I have to reverse engineer.

~~~
mathetic
Arggh, every single time someone posts an incredible cool small piece of code
that solves a difficult problem, comments like this appear.

This whole HN attitude of pristine code is killing me. This is a piece of code
in a _GIST_ and solves the problem in three lines, it is clearly not intended
for production use in a large code base.

Please stop searching for something wrong and enjoy what is presented in all
of its glory.

~~~
zyngaro
Maybe it's the case here but in the scala community in general I noted a
tendency to emphasize cleverness over clarity and simplicity.

~~~
ADRIANFR
Relevant Stack Overflow question:
[http://stackoverflow.com/questions/7084212/is-scala-
idiomati...](http://stackoverflow.com/questions/7084212/is-scala-idiomatic-
coding-style-just-a-cool-trap-for-writing-inefficient-code)

------
est
8-queen puzzle in 1 line of Python with pretty print

_=[__import__('sys').stdout.write("\n".join('.' * i + 'Q' \+ '.' * (8-i-1) for
i in vec) + "\n===\n") for vec in
__import__('itertools').permutations(xrange(8)) if 8 == len(set(vec[i]+i for i
in xrange(8))) == len(set(vec[i]-i for i in xrange(8)))]

~~~
e12e
I tried to make that a little more readable, and converted it to py3 -- This
one produces the same output with python3, as your one-liner with python2:

    
    
      #!/usr/bin/env python3
    
      from itertools import permutations as p
    
      for vec in p(range(8)):
        if 8 == len(set(vec[i]+i for i in range(8))) \
             == len(set(vec[i]-i for i in range(8))):
          print("\n".join( '.' * i + 'Q' + '.' * (8-i-1) for i in vec),
                end="\n===\n")
    

The string construction could/should probably also be refactored a bit, but at
least this version I have a hope of following the logic... :-)

------
todd8
Here's my Python3 version (4 line nQueens function):

    
    
        from itertools import permutations
    
        def nQueens(n):
            return (p for p in permutations(range(n))
                    if (len(set(c+d for c,d in enumerate(p))) == n and 
                        len(set(c-d for c,d in enumerate(p))) == n))
    
        for num,solution in enumerate(nQueens(8)):
            print("Solution #", num+1)
            print("\n".join(("  ".join("Q" if i == col else "-" for i in range(8))) for col in solution))

------
pkolaczk
Honestly, I can see more than 4 lines of code there.

~~~
agumonkey
nqueens is ~4, the rest is output

~~~
eggy
One line of J code taken from the jsoftware site [1]:

    
    
      queenst =: (, #: I.@,@(</)&i.)~ (] #"1~ [ */@:~:&(|@-/) {)&.|: ! A.&i. ]
    

This is the calculation, and you can output all 92 solutions for the 8 queens
problems like this:

    
    
        queenst 8
    
      0 4 7 5 2 6 1 3
      0 5 7 2 6 3 1 4
      0 6 3 5 7 1 4 2
      ....
    

each column is a row number, and the integer is which column the queen is in,
or vice versa on rows and columns.

,or print how many solutions

    
    
        $queens
      92 8
    

$ gives the 'shape' of the array, that is 92 rows (solutions) x 8 columns
(8-queens problem).

I always return to J, because I enjoy mathematics and functional programming.
Like math, you work with symbols you learn to think as you code in an
interpreted window, somewhat like when working in the Lisp REPL. Ken Iverson
created the APL language in 1960, and won an ACM Turing Award and gave a
lecture 'Notation as a Tool of Thought', which sums it up better than I could
ever hope to express it [3].

J was a collaboration between him, Arthur Whitney (of finance's k language,
and kdb fame), and Roger Hui, in an attempt to improve on APL, and to do away
with needing a special character keyboard. It is under the GPL3 license today.
J uses the ASCII character set, and is very functional and composable.

    
    
      [1]  http://code.jsoftware.com/wiki/Essays/N_Queens_Problem  
    
      [2] http://code.jsoftware.com/wiki/Essays/Queens_and_Knights  
    
      [3] http://www.jsoftware.com/papers/tot.htm

~~~
jxy

        > queenst =: (, #: I.@,@(</)&i.)~ (] #"1~ [ */@:~:&(|@-/) {)&.|: ! A.&i. ]
    

So this must be the origin of the one liner from [0]

    
    
        queens←{⍵{((+/b)⌿⍵),⍺|(,b)/⍳×/⍴b←~↑(⊂⍳⍺)∊¨(↓⍵)+[0]¨⊂(c-⍳c←1↓⍴⍵)∘.×¯1 0 1}⍣⍵⍳1 0}
    

Somehow J is shorter? I need someone who speaks both J and APL to tell me if
they are the same.

Never learned J, but I always return to APL. I guess J to APL is like latin
alphabet to chinese characters. You don't need a special keyboard for APL,
just like you don't need a special keyboard for Chinese. Sometimes I really
don't understand why they started J. Native English speaker's mentality? We
never needed special keyboard for diacritics, let alone east asian languages.
With an input method for APL characters, J does not even save the number of
keystrokes.

[0]
[https://dfns.dyalog.com/n_queens.htm](https://dfns.dyalog.com/n_queens.htm)

~~~
jxy
I was wrong. The two one-liners for J and APL are different. The original
paper [0] gives the original APL implementation of the above J one-liner.

I'm not going to delve deep into the algorithm, but the following quote from
the paper fascinates me.

    
    
        It is voracious for work space. For concreteness, consider
        the case n←8 . The intermediate expression p[;c] has shape
        (!8),(2!8),2 , requiring 9031704 bytes on IBM-based APL
        systems.
    

It uses 9 MB! Such a 'voracious' algorithm!

[0]
[http://www.jsoftware.com/papers/nqueens.htm](http://www.jsoftware.com/papers/nqueens.htm)

~~~
RodgerTheGreat
Even by modern standards that's a pretty hefty chunk of RAM for n=8.

~~~
jxy
The problem is that the complexity is O(n²n!)

~~~
eggy
I am not a J guru, but that is just the concise implementation. There are
others in the references previously cited. J is an interpreted language, and
when doing db stuff, it memory maps files for speed. I know this is not the
same, but I will now look into it, since I haven't done any J tracing unless a
program blows up.

I also use Dyalog APL,and I don't have a special keyboard. The symbols are
MORE like mathematical symbols to me. It's just that it is easier to share
code in J's plain ASCII text. Some systems still don't show APL characters
correctly, or the user doesn't know how just yet. I was also trying to study K
and Kona, so J was the better fit.

~~~
jxy
Is it possible to programmatically transliterate APL code to J? It would be
great in either interactive or scripting to try out the J interpreter, so my
code

    
    
        1+2-3×4÷5
    

could be converted to

    
    
        1+2-3*4%5
    

automatically. I guess only Dyalog APL supports function trains, and J has
more modern features. It would be interesting to use J as a backend. I really
wish GNU APL could support function trains soon.

~~~
eggy
I haven't run across any in my J studies, but J has evolved away from base
APL, so I think it might be possible to do a direct tranliteration, but would
miss some niftier ways of doing it in J. I am merely a student of J and APL,
though fascinated every day by both of them. I usually go back and forth from
Dyalog APL to J depending on the task or the read that sets me off on
discovery.

------
wslh
Not the shortest, but the most clear solving in Z3 because instead of an
algorithm you define the solution:
[https://github.com/0vercl0k/z3-playground/blob/master/nqueen...](https://github.com/0vercl0k/z3-playground/blob/master/nqueens_z3.py)

~~~
FreeFull
And here is the solution using Picat, using the included sat library:
[http://picat-lang.org/exs/bqueens.pi](http://picat-lang.org/exs/bqueens.pi)

------
SagelyGuru
There is no search solution to N-queens, so any code doing search is poor and
wasteful.

I am not going to spoil the fun by giving you the details here, just the hint:
start on the right square, depending on whether N is even or odd. Then place
successive queens in a knight jump pattern.

It is fascinating to me that whoever invented chess a long time ago may have
been aware of these subtle complementary relationships between the different
types of moves?

~~~
JoeAltmaier
That may find some solutions, but does it find them all?

~~~
SagelyGuru
You can probably find them all by considering all the valid starting
(boundary) positions, mostly obtainable by symmetry.

------
user2994cb
Well, here's a fairly compact Haskell function that should be reasonably
efficient (no fancy stuff mind):

    
    
      queens n = q n n [[]] where
       q 0 m ss = ss
       q n m ss = q (n-1) m (concatMap (\s->(map (:s)(filter (f 1 s) [0..m-1]))) ss)
       f _ [] a = True
       f n (b:s) a = a /= b && a /= b+n && a /= b-n && f (n+1) s a
      main = print $ queens 8

~~~
user2994cb
Actually, this is better (and no less clear):

    
    
      import Data.List
      queens n = q [] [0..n-1] where
       q s [] = [[]]
       q s as = concatMap (\a -> q (a:s) (delete a as)) (filter (f 1 s) as)
       f _ [] a = True
       f n (b:s) a = a /= b+n && a /= b-n && f (n+1) s a
      main = print $ length (queens 8)
    

Undoubtedly functional, the question is whether it is improved eg. by using
folds instead of explicit recursion, or replacing concatMap with monadic join.

~~~
user2994cb
That should be "q s [] = [s]", otherwise you get 92 copies of the empty list.

------
brownbat
A fast algorithm that really isn't very complex:

[http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=4DC...](http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=4DC9292839FE7B1AFABA1EDB8183242C?doi=10.1.1.57.4685&rep=rep1&type=pdf)

------
jxy
Another HN post becomes rosetta? Besides the poor search, it does not even try
to remove duplications because of symmetry.

Rosetta posts should always include a one liner from APL, so here is a link:

[https://dfns.dyalog.com/n_queens.htm](https://dfns.dyalog.com/n_queens.htm)

------
pmorici
Isn't the point of an n-queen solution to be fast? What does it matter how
many new lines you have in the solution if it isn't fast?

------
edejong
Personally, I love this simple, readable, short implementation in the EcliPse
solver:
[http://www.hakank.org/minizinc/queens_viz.mzn](http://www.hakank.org/minizinc/queens_viz.mzn)

------
dblock
If you want to get serious about solving queens fast here's an x86 assembly
implementation from 1995 -
[https://github.com/dblock/reines](https://github.com/dblock/reines) :)

~~~
userbinator
An even faster x86-64 Asm one that does it _with no memory accesses_ \-
everything is in registers:

[https://github.com/davidad/8queens/blob/1989666c45baa639f152...](https://github.com/davidad/8queens/blob/1989666c45baa639f152dfc89c70635f7007d20b/8queens.asm)

------
michaelaiello
This problem is also fun with perl regexes

[http://www.perlmonks.org/?node_id=297616](http://www.perlmonks.org/?node_id=297616)

------
junke
If you want a fine challenge, try "Queens and Knights"
([http://archive.vector.org.uk/art10003900](http://archive.vector.org.uk/art10003900)).
It has some interesting corner cases to consider.

------
digsmahler
Love it! That's a really clever use of the Set collection type to pair down
non-solutions.

~~~
pklausler
pare

~~~
digsmahler
lol. ty!

------
master_yoda_1
Here is my 2 line solution to n-queen.

#include <nqueensolver.h>

int main(){int n=5;solve(n);}

Please include the binaries for nqueen solver when compiling and running.

The point I am trying to make is that, in such a high label language like
scala, this kind of claim sounds foolish.

~~~
aconz2
I think many may take your response as a bit off-the-cuff, but I share this
sentiment. You could even go so far as to write the longest C program you
could dream of to solve it, then simply feed it into

    
    
       tr -d '\n'
    

and call it one line! Again, many will find this pedantic and unsatisfactory
but programmers should _really_ be more precise in what they mean by lines of
code.

What I think most people are really referring to is information content. To
achieve the same program in shorter length, the rest of the information has to
lie somewhere else (in the scala implementation or nqeensolver.h). We can
increase the density of the information needed to specify a program, but not
decrease it.

I actually just wrote something about this concept yesterday:

[https://aconz2.github.io/programming/2016/04/09/power_of_pl....](https://aconz2.github.io/programming/2016/04/09/power_of_pl.html)

------
Bladtman
By someone who clearly cannot count to 4?

~~~
pathikrit
OP here. Sorry for the code-golfy post on HN. But, some clarifications:

1\. Yes, it is O(n!) - it says so in the description but not on the title of
the post on HN.

2\. It is 4 lines of code for `nQueen` function. I did not include the
printing code in the line count.

3\. And no, I did not cheat by using semicolons in same lines - these are 4
legit lines IMO. You can put the `&` clause in 1 line to reduce it further.

