Solving the Knight's Tour Puzzle In 60 Lines of Python 311
ttsiod writes "When I was a kid, I used to play the Knight's Tour puzzle with pen and paper: you simply had to pass once from every square of a chess board, moving like a Knight. Nowadays, I no longer play chess; but somehow I remembered this nice little puzzle and coded a 60-line Python solver that can tackle even 100x100 boards in less than a second. Try beating this, fellow coders!"
awesome (Score:5, Funny)
too bad that your code will break with the next python version.
Re: (Score:2, Informative)
I got it to run in Python 3, and here are the changes I need to make:
1) The file was screwed up and used a tab instead of 8 spaces (a problem unrelated to Python 3).
2) I had to change all the print statements into print functions by wrapping the argument in parentheses.
3) I had to change xrange to range.
4) I had to add from functools import reduce to the top of the file.
Done. 4 changes made in 5 minutes, the hardest of which (#1) would have screwed up Python 2.x as well.
MAJOR version (Score:3, Informative)
The code will break with the next MAJOR version, not revision. That's entirely normal -- it's actually pretty much what version (as opposed to revision) means.
Re: (Score:2)
too bad that your code will break with the next python version.
No need for a next python version. Just let the code grow and in any mo
Traceback (most recent call last):
File "", line 1, in
TypeError: 'int' object is not callable
Re: (Score:3, Interesting)
Re:awesome (Score:5, Funny)
printf (Score:3, Interesting)
Point of fact: Python has the sexiest sprintf() support available. Observe..
>>> print "I ate %d %s in %.3f seconds" % (99,'hotdogs',62.0895)
I ate 99 hotdogs in 62.090 seconds
Re: (Score:2)
And here's the ruby version:
print "I ate %d %s in %.3f seconds" % [99,'hotdogs',62.0895]
Notice the difference?
Re:printf (Score:4, Funny)
No output, and your font is all wrong.
*ducks*
Re: (Score:3, Funny)
It will run 1/10th the speed of Python?
Re:printf (Score:4, Funny)
You misspelled puts? ;-D
Re: (Score:2)
wtf? That has to be the most retarded backwards compatibility break I've ever seen.
Re: (Score:2, Informative)
Yawn.
Another claim that Perl is "in its last throes".
Re:evolve or die (Score:5, Insightful)
Re: (Score:2)
but the 2to3 [python.org] tool will make this simple transforms (xrange->range, print "foo"->print("foo") automatically.
Re: (Score:3, Insightful)
Nah, "for index in range(1, 100):" makes a bloated memory list of 1,2,3,4,5,6,7...99,100 whereas xrange(1,100) is memory-efficient iterator that just returns an incremented value upon each loop.
A valid concern for large lists and essential knowledge for Python programmers, but for the the 64 element list you need to represent a chess board, who really gives a shit? Just write the clean, future-proof code and let the machine do the hard work. You're trading programmer convenience for machine time by using Python anyway.
Re: (Score:2)
Yep. Python is cool. Try doing that with one of PHP's many backwards-incompatible changes.
Re: (Score:2)
PHP 5 is pretty API stable.
Sure they made some mistakes earlier, but they are fixed now.
Re: (Score:3, Interesting)
Here's code you can put in your Python 2.x code today to future proof it against the change to xrange:
try:
range = xrange
except NameError:
pass
After that, just write range in your code and it will automatically use the equivalent of Python 2's xrange. If you're running Python 2.6, you can use a print function (instead of a print keyword) by adding from __future__ import print_function to your header as well, and you're good to go for a large number of Python 3 switc
Easy (Score:5, Funny)
C-x C-m KnightsPuzzle
Re:Easy (Score:5, Informative)
While your humor is appreciated, I feel compelled to point out that it should be
M-x knights-puzzle
Lisp doesn't use CamelCase.
Re: (Score:3, Interesting)
Lisp doesn't use CamelCase.
Don't show off your ignorance too much. LISP has used CamelCase for at least thirty years. Admittedly neither Scheme nor Common LISP conventionally use it, but InterLISP certainly does.
All done. (Score:3, Interesting)
#!/usr/bin/env python import sys g_sqSize = -1 # the board size, passed at runtime g_board = [] # the board will be constructed as a list of lists def main(): global g_sqSize if len(sys.argv) != 2: g_sqSize = 8 # Default: Fill the normal 8x8 chess board else: try: g_sqSize = int(sys.argv[1]) # or, the NxN the user wants except: print "Usage: " + sys.argv[0] + " " sys.exit(1) for i in xrange(0, g_sqSize): g_board.append(g_sqSize*[0]) # Fill the board with zeroes Fill(0,0,1) # Start the recursion with a 1 in the upper left print "No solution found" # if the recursion returns, it failed def InRangeAndEmpty(ty,tx): # check if coordinates are within the board return ty>=0 and tx>=0 and ty
Re:All done. (Score:5, Funny)
Except you commented out all of the code.
Re:All done. (Score:5, Funny)
Re: (Score:3, Funny)
Knuth (Score:3, Funny)
He's preached against premature optimization for years.
Re: (Score:3, Funny)
Re:All done. (Score:5, Funny)
There. I did it in one line of code.
That doesn't look like perl to me...
Re:All done. (Score:5, Funny)
What would Michael Knight do? (Score:4, Funny)
He'd hop into KITT and go anywhere he damn well pleases.
Nice. And a Mathematica implementation... (Score:3, Interesting)
... here: http://www.tri.org.au/tourcode.html [tri.org.au]
Least.. Readable.. Code.. Ever... (Score:2)
Good grief! That has to be the most unreadable blob of code I've ever seen...
Here's a taste of a relatively readable part:
Cell[CellGroupData[{
Cell["\<\ :=
KnightTour[rows_Integer, columns_Integer, start_List, end_List:{}, \
HidePaths_Integer:0]
Module[{sR = rows+1, sC = columns+1, i = 0, j = 0, path, endMoves, tree = \
{0}, SNew, KnightMoves, FeasibleMoves, area},
path = If[IntegerQ[start[[1]]], {start}, start];
\t
\tendMoves
Re: (Score:3, Interesting)
That's because you're looking at some MathML code. What one actually types into Mathematica, and sees in Mathematica (or sees in a raw text file version IF the "InputForm" of the code is looked at) is the following. Unfortunately, the code ends suddenly because slashcode somehow doesn't allow more to be shown. BAAAAAD slashcode.
Complaining about the readability of what you posted is like complaining about the raw HTML which goes into this webpage.
Try lisp (Score:4, Insightful)
Though I have better things to do than actually try, looking over the code FTFA, I have to say that I think a transliteration of this code into Scheme or Lisp would actually look cleaner than Python. And I do know that that would deal with the problem the writer ran into, namely that Python has an absurdly low recursion limit.
I do like Python's syntax (for anything under 100 lines of code) but calling it a model of functional programming is just silly.
Re: (Score:2, Interesting)
# recurse using our neighbours, trying first the ones with the
# least amount of free neighbours, i.e. the "loners"
for ty,tx in sorted(emptyNeighbours, key=lambda c: reduce(
lambda x,y: x+y,
map(lambda j: InRangeAndEmpty(c[0]+j[0], c[1]+j[1]) and 1 or 0,
jumps))):
Fill(ty,tx,counter+1)
Idiomatic python(or at least more-so):
def sort_key(c):
Re:Try lisp (Score:4, Interesting)
I won't pretend to remember Lisp inventor John McCarthy's exact words which is odd because there were only about ten but he simply asked if Python could gracefully manipulate Python code as data. "No, John, it can't," said Peter and nothing more, graciously assenting to the professor's critique, and McCarthy said no more though Peter waited a moment to see if he would and in the silence a thousand words were said.
http://smuglispweeny.blogspot.com/2008/02/ooh-ooh-my-turn-why-lisp.html [blogspot.com]
better algo (Score:5, Informative)
Apparently, this isn't NP-complete. There is an algorithm that can solve this in O(n) time, see here: http://mathworld.wolfram.com/KnightsTour.html [wolfram.com]
This will save a LOT of time for larger boards. Try to implement this.
Re:better algo (Score:5, Interesting)
The ultimate algorithm is called Warnsdorf's heuristic:
http://www.delphiforfun.org/programs/knights_tour.htm [delphiforfun.org]
It solves all possible orders (>100x100) in less than a second.
The algorithm cited in the article is really shitty, because it requires recursion.
Hint: I implemented an algorithm to enumerate all magic knight tours (magic, like in magic squares):
http://magictour.free.fr/ [magictour.free.fr]
Re: (Score:3, Interesting)
http://github.com/pib/scripts/tree/master/knight.py [github.com]
It's faster than the one in TFA as well, though it has no backtracking, so it won't find some solutions once you get bigger than 76x76, but at least it doesn't overflow the stack.
It also will tell you whether it found an open, closed, or incomplete path.
Re: (Score:2)
Wait a second. What's wrong with recursion?
Re:better algo (Score:5, Funny)
Wait a second. What's wrong with recursion?
Re:better algo (Score:4, Informative)
Nothing is wrong with it at all. In a traditional compiled language its often the most efficent way to write something and it often gets you the most efficent compiled code and when it does not most compilers will be smart enough to build a loop construct when the go to the assembler stage.
If you are using an interpreted langague like python or my favoirte Dialect( needs more respect ) then you have to be a little careful with it because these have a "soft stack" that can only get so deep. They have to keep track of how deep they are and where that have been, rather then just a beq and jmp on some register value, so they know what to do next. Mosty interpreters have a fixed stack depth although some manage to abstact this to linked list like structures internally and can keep going until the heap is exhasted. In any case you can't search to big a space recusively or it will fail.
Re: (Score:3, Funny)
I don't know. What's wrong with recursion?
Re: (Score:2)
Re: (Score:2)
True. But have you looked at the algorithm? It's remarkably simple, was written in 1992, and is totally generalized to any size chessboard (there is an example in Arnd Roth's implementation for a 180x180 board).
28 lines in Prolog :-) (Score:5, Interesting)
wrapper(Size, [X, Y], Path) :- :- :- :-
X == 1,
Y == 1,
Depth is Size * Size - 1,
worker(Size, [X, Y], Depth, [], ReversedPath),
reverse(ReversedPath, Path),
write(Path), nl.
worker(_, State, 0, CurrentPath, [State|CurrentPath]).
worker(Size, State, Depth, CurrentPath, FinalPath)
DepthM1 is Depth - 1,
move_generator(Size, State, NewState),
not(checker(NewState, CurrentPath)),
worker(Size, NewState, DepthM1, [State|CurrentPath], FinalPath).
checker(State, [State|_]).
checker(State, [_|StateList])
checker(State, StateList).
move_generator(Size, [X, Y], [NewX, NewY])
move(MoveX, MoveY),
NewX is X + MoveX, NewX == 1,
NewY is Y + MoveY, NewY == 1.
move(1, 2).
move(2, 1).
move(2, -1).
move(1, -2).
move(-1, -2).
move(-2, -1).
move(-2, 1).
move(-1, 2).
Re:28 lines in Prolog :-) (Score:5, Insightful)
I would truly be amazed to see anyone writing the same logic in C++ in anything less than 3 times the lines of code I wrote in Python. And even if this is somehow possible (using external libraries like BOOST, I'd wager), the code will take longer to write, and it will be far more difficult to comprehend or refactor...
And I'd wager that this guy has never worked on huge projects. Any chunk of code that is less than a hundred lines is not going to be difficult to refactor; in fact, such a short piece of code probably gets longer and more confusing by adding object oriented structure (notice his code isn't encapsulated into a class or anything). The real advantages of structured programming isn't seen until you have a large project that has constantly changing requirements. That is where flexibility REALLY makes a difference.
I would also argue that any modern language gives you everything you need to write good, flexible code, and the quality of the code produced is more closely related to the skill of the programmer, than it is to the programming language itself.
In fact, for myself, it would not be an exaggeration to say I can write more flexible code in assembly now than I could five years ago in any language. Of course, it would be well structured assembly, not the wild mess of code I've written in previous years. YMMV.
Re:28 lines in Prolog :-) (Score:5, Interesting)
Yeah, that sort of assertion bugs me. My own experience has been the exact opposite - attempting to understand large Python programs that have evolved over a number of years is damn near impossible. I know, I've tried. The terseness of the language and the absolute lack of explicit typing means you can't just open up a random function and understand what's going on. You often have to trace backwards through the code just to discover what it's attempting to do.
Typically Python programmers try and paper over this problem with tons of doc comments. Problem is that like any comment, they can get out of date, and often aren't useful anyway. If I had a dollar for every time I've seen:
foo: The foo to bar.
in a Python doc comment, I'd be a rich guy. What is a foo exactly? A class? A tuple? A list of tuples of classes? Or worse, any of the above?
In contrast, I've found it very easy to dive right into some of the large C++ code bases we have at work and immediately understand what the code does and how it does it, largely because C++ is more explicit and the (partly redundant) specification of type information means you can rapidly find how different components interact. Redundant comments are kept to a minimum. Comprehension is radically improved.
This is very useful when attempting to understand error messages, for instance. My absolute worst nightmare troubleshooting wise is running a giant Python script and getting a type error 20 frames deep, because I know it could easily burn an afternoon just untangling the mess. More explicit languages rarely seem to have this problem.
Re:28 lines in Prolog :-) (Score:4, Insightful)
This is certainly one of the practical drawbacks of duck-typing. But name-based polymorphism is exceedingly powerful, and with great power comes great responsibility. (Namely, to document one's arguments and return values properly.)
Re: (Score:3, Insightful)
That Java code is only 10 lines longer, but it doesn't include the code for some other classes it uses to solve the problem.
But anyhow, you're missing his point. The basic backtracking algorithm for the problem is simple in any language, and could indeed be made much shorter in Java (w/o the entire search framework). He's talking about improving the search with a heuristic (in his case, what is known as a "minimum remaining values" search heuristic among the AI folks). But he's still probably wrong, as you'
Re: (Score:3, Informative)
I don't know if you're just being ironic, but your Java code isn't even correct with respect to AWT/Swing threading semantics. You're supposed to create Swing objects only in the AWT event loop thread, using EventQueue.runLater() or one of its wrappers. I guess you're using Thread.sleep() later to get around the threading bugs you just created, but since your code is uncommented it's hard to tell.
Re: (Score:2)
Re:28 lines in Prolog :-) (Score:5, Interesting)
knights
knights n = loop (n*n) [[(1,1)]]
where loop 1 = map reverse . id
loop i = loop (i-1) . concatMap nextMoves
nextMoves already@(x:xs) = [next:already | next <- possible]
where possible = filter (\x -> on_board x && not (x `elem` already)) $ jumps x
jumps (x,y) = [(x+a, y+b) | (a,b) <- [(1,2), (2,1), (2,-1), (1,-2), (-1,-2), (-2,-1), (-2,1), (-1,2)]]
on_board (x,y) = (x >= 1) && (x <= n) && (y >= 1) && (y <= n)
(from http://www.haskell.org/haskellwiki/99_questions/90_to_94).
Perl (Score:5, Interesting)
#!/usr/bin/perl
use Chess;
$knight = Chess::Piece::Knight->new();
$board = Chess::Board->new(100, 100, setup => {
$knight => "a1";
});
$knight->tour()->show();
Re:Perl (Score:5, Informative)
Chess::Piece::Knight [cpan.org].
Perl is awesome!
Re: (Score:2)
What does the quality of the language have to do about a sister projected of keeping and storing 3rd party libraries. I actually hate it because of that because you get these perl apps and they assume that you have some stupid library installed and you need to keep on trying over and over again for the right library.
Re: (Score:2)
Because it saves time writing code and "standardizes" common functinality (like a Chess board abstraction). Both of those are indirect ways of saying CPAN makes complicated problems easier to solve. The whole point of writing software is to solve problems, and CPAN makes it easier. Why reinvent the wheel, even if it is only 60 lines of Python?
Also: CPAN can automatically grab dependencies, so I'm not really sure what you're whining about in your second sentence.
Re: (Score:2)
... and you need to keep on trying over and over again for the right library.
Or just read the requirements of the software you're installing. Maybe that would be too easy?
Re: (Score:2, Informative)
(Note: I'm the GP AC.)
Heh. That's funny, but actually, I *was* being a smartass. Don't get me wrong, I love Perl, but the example above is completely made up. (And looking into the Chess package on CPAN, it appears that there is no preimplemented way to generate knight's tours, either.)
Still, I'm glad to hear that Perl's reputation for there being a module for anything and everything on CPAN still lives, at least. ;)
Pretty poor language, if it makes you think... (Score:2)
It's a pretty poor language, if if makes its users confuse code that calls external modules with actual implementations.
Re: (Score:2)
dump the recursion (Score:5, Interesting)
With the "added intelligence" of the second version, the recursive search devolved into a linear one since the very first attempt at each step will lead to a good solution (add a print to the backtracking part and see if this isn't the case).
So you might as well convert the recursion into a loop and eliminate the stack overflows for large boards.
A trivial backtracking algorithm and... (Score:5, Insightful)
Re:A trivial backtracking algorithm and... (Score:5, Funny)
Of course like all other programmers he thinks he is better then everyone else.
Doing it without CS teaching? (Score:2)
It isn't anything special in particular. What _is_ special is doing it without receiving the instruction first.
I think reinventing the wheel is a good thing in some situations; one is when you reinvent the wheel to study it but not use it. Another is when you reinvent the wheel without having been shown what a wheel is and how it works.
It's a sign that you can think for yourself and come up with good solutions to the problems you want to solve independent of instruction.
Re:Doing it without CS teaching? (Score:5, Insightful)
Yes, but a lot of this stuff really isn't worth posting online. Espectially Slashdot I have created many algorithms myself without the need to post it for slashdot acceptance. Some interesting compression algorithms, Memory management algorithms... Whatever that I feel like exploring today. But it is for my own personal knowledge not for public viewing of my code as my method will be to prove some particular point to myself nor will it be efficient or complete, and any attempt to have it posted like the guy who posted this thread will just get critized for anything that is not the best as it could possibly be.
Re: (Score:2)
I did this in high school you insensitive clod!
Oh and it was in FORTRAN :P
OMG (Score:4, Funny)
...and then there's APL (Score:5, Interesting)
Pentominoes Quine in Perl (Score:5, Interesting)
I had to solve it in C (Score:5, Interesting)
As part of my undergrad education. Taking less than a second on today's hardware is nothing spectacular; the secret is in the algorithm: You rate the squares according to the number of moves available from that square and, when given a choice, pick the square with the least number of moves. This way, you don't work yourself into a dead-end situation as frequently. Combine this with a little backtracking, and you've got a nice example to show how algorithm selection has a much larger impact on runtime performance than language selection.
Incidentally, 200 MHz was considered a fast CPU when I did it, and I remember it taking 8 billion moves and all night without finding a solution. Until, that is, we implemented the preferential choice part of the algorithm. After that, it was pretty much instantaneous.
Python??? Try it getting that speed in Java. (Score:2)
Anyhow, what's the point? I didn't think this was a hard problem at all when we did it.
He mixed tabs and spaces (Score:2, Interesting)
Not cool.
I hope a firehose exploit was involved. (Score:5, Insightful)
1 #include <set>
2 #include <iostream>
3 #include <cassert>
4 using namespace std;
5
6 int dx[8]={1,1,-1,-1,2,2,-2,-2}, dy[8]={2,-2,2,-2,1,-1,1,-1};
7 int D[50][50];
8 int N,C;
9
10 #define valid(x,y) ((x>=0) && (x<N) && (y>=0) && (y<N) && (D[x][y]==-1 ) )
11
12 bool show()
13 {
14 for (int i=N;i--;)
15 {
16 for (int j=N;j--;)
17 cout<<"\t"<<D[i][j];
18 cout<<"\n";
19 }
20 return true;
21 }
22
23 bool rec(int x, int y)
24 {
25 D[x][y]=C++;
26 if(C==N*N)
27 return show();
28
29 set< pair<int, pair<int,int> > > poss;
30 for (int r=8;r--;)
31 if(valid(x+dx[r], y+dy[r]))
32 {
33 int neighb=0;
34 for (int t=8;t--;)
35 neighb+= valid(x+dx[r]+dx[t],y+dy[r]+dy[t] );
36 poss.insert( make_pair(neighb, make_pair(x+dx[r],y+dy[r] ) ));
37 }
38
39 for (typeof(poss.begin()) q=poss.begin(); q!=poss.end(); q++)
40 if (rec(q->second.first, q->second.second))
41 return true;
42
43 D[x][y]=-1;
44 C--;
45
46 return false;
47 }
48
49 void solve(int n)
50 {
51 N=n, C=0;
52 memset(D,-1,sizeof(D));
53 assert(rec(0,0))
54 }
55
56 int main()
57 {
58 int n;
59 while((cin>>n) && (n>0))
60 solve(n);
61 return 0;
62 }
The bastards! Those darn brackets force me to have 2 extra lines
Re: (Score:2)
Just change your coding style to have the { on the same line as if and for, which is a popular style, and you've done it.
Re: (Score:3, Insightful)
Well C(++) doesn't force you to use new lines at all for most purposes. In the PP's example the exception would be the pre-processor directives.
So, the PP's solution would fit in just 4 lines of code, way fewer than the 60 required for the Python example, but what does that prove w.r.t. either language implementation of the algorithm?
Lines of code is a real stupid measurement for complexity, productivity, maintainability and / or elegance and I really wish people would stop using it like that.
Improvements to the heuristic (Score:2, Interesting)
TFA has basically stumbled upon Warnsdorff's algorithm [wikipedia.org]. It's a great method, but it doesn't work for really large boards due to blind alleys. There's another method available which uses decomposition to achieve a linear running time(in # of squares), but which is quite a bit more complex to implement. There's a nice tweak to the algorithm which can get much farther than the unmodified original: in the event of a tie (where two candidates have the same number of open neighbours), break the tie by choosing th
/me waits for the 1-line J version. (Score:2)
Memo to OP: Never, never, brag how short your code is, especially if you're using something as bloated as Python.
There's always a more concise way. And a faster way.
You're just asking for a beating, and well-deserved.
Here it is in 30. (Score:2)
Here it is in 30 lines of Water. Oh, and it outputs in HTML.
<class knights_tour size=8 board=opt >
<method make>
_subject
</method>
<method in_range_and_empty x=req y=req>
<and
Re: (Score:2)
1 line from the future (.NET 4.0) (Score:3, Funny)
object[] finalBoard = System.Math.KnightsTour(64);
Batteries included (Score:4, Interesting)
There is an elegant Knight's Tour solver right inside your Python distribution. You can find it at /usr/lib/python2.5/test/test_generators.py [python.org]. Written by Tim Peters (a.k.a. timbot).
Re: (Score:2)
"rm -rf knights"
rm: cannot remove `knights': No such file or directory
Ummm.....
Re:OK (Score:4, Funny)
Re:Python uses lambda calculus? (Score:5, Informative)
Alas, Python lambdas are very limited, only allowing a single expression. If you need a function that does two things, you can't use lambda anymore. This is not a great hardship as Python allows you to declare inner-scoped functions and you can use that instead, but it's still annoying. I do recommend Python though, as it's a great language even with the occasional shortcoming.
Re: (Score:2, Informative)
wtf? of course you could!
lambda x,y: (spam(x), meth(y)) [-1]
yeah, less readable etc but works. And yes, Python is even capable of executing interesting, obscure one-liners:
http://mobile.slashdot.org/comments.pl?sid=1022735&cid=25689627
Re: (Score:2)
Nice technique, thanks, I'll have to remember that. Still, it would be nice if lambdas had the same basic syntax as regular functions so you could do multiple lines in the same way.
Re: (Score:3, Informative)
The colon in lambda is like a guy with a Vista laptop on a LUG meeting. The whole lambda syntax construct is an expression, and def's, if's, while's and all the other guys begin a block of statements (and are statements themselves). In Python, you simply cannot cleanly embed a statement within an expression -- you'd need braces of some kind (and suggesting that to the devs would be like asking to be crucified). Just think, how would this look like:
map(lambda x:
if abs(x) > 5:
Re: (Score:2)
I understand the reasons why lambdas are the way they are, but that doesn't make it any better. A shortcoming that's really difficult to overcome is still a shortcoming, just a justified one.
Re: (Score:2)
Re: (Score:2)
False dichotomy. It's a design decision on the part of the language designers and it's a shortcoming in my eyes.
Re: (Score:2)
I always do this:
Also works for non-booleans as well.
Re: (Score:3, Interesting)
Not to stir up old debates again, but if you like Lisp, you might be better off going for Ruby than for Python. Coming from a Scheme background, I find Ruby to be the more elegant language.
Python is a great language, but my feeling about it is that it's designed to support one way of programming (and not even completely - it's sort of ambivalent between procedural and object-oriented). This is fine, and has the advantage off encouraging consistency among programs from different authors. However, I feel ther
Re: (Score:3, Interesting)
It's even less readable that PERL. Shit, I didn't think it's possible. And I used to "program" in PERL...
Re: (Score:2, Troll)
It's not "perfect", but compared to the 40+ other languages I've used, it seems to be at or near the top, in terms of human readability.
(Lisp has obvious advantages for machine readability, but it's quite rare that this is useful.)
Re: (Score:3, Interesting)
http://anthonyf.wordpress.com/2006/07/07/solving-the-knights-tour [wordpress.com]
I think even if you didn't know any lisp you would find this solution to be pretty readable.
Re: (Score:3, Interesting)
I like Lisp a lot, and I certainly prefer its syntax to Java or C (or--god help us all--C++), but I still think that it is clearly less readable than Python.
If there's a serious argument against this, it must be Lisp's macro capabilities...
Re: (Score:2)
Plenty of practical uses for this in graph theory.
Although I'm not convinced that Python serves much practical purpose, like the 500 other trendy scripting languages out there. Perhaps when you ask "stuff that matters" you're only referring to Python? I'm not sure.
Re: (Score:2)