- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
My Knight's Tour in perl. Just another brute-force solution.
Admin
I wonder what the purpose of "Programmers' Praxis" might be?
It's an interesting question, I think. Given that the problem in question is mathematically solvable, why not just provide the mathematical solution (as some have)?
Assuming that the solution is available on the Web (which it invariably is), one would have thought that the "winner(s)" would provide a link and (preferably) a commentary on why the web-provided solution (a) doesn't compile (b) is sub-optimal and/or (c) is incorrect.
Posting gobbet upon gobbet of awful instant code in random languages is surely a sign of severe autism.
What, I think, the concept needs is a lack of refinement.
How about this? Post an insoluble problem, and ask for a programmatic solution. It doesn't have to be the right solution (although an annoying number of posters can't even manage that for a solved problem); just an interesting solution.
Travelling salesmen? Packing randomly-sized cuboids into a box? Anything.
Just, please, not this. It's getting fucking irritating.
PS Your Robot-Fu is dying. Maybe the next Programmer Praxis?
Admin
Admin
Hmm. Thot tinks Bim Job not be funny fuck. Not want.
Admin
I had the crazy idea that the purpose was to practice programming. Perhaps to try to come up with particularly elegant, clever, or efficient ways to solve a problem. Or perhaps simply to try out a language you haven't used before. Looking up someone else's solution doesn't accomplish any of that. Not to mention, is pretty boring, unless they're solution is particularly interesting in some way.
Hey, I'll let you in on a secret: Have you ever done a crossword puzzle? Did you know that the person who created the crossword puzzle ALREADY HAS A SOLUTION? Did you ever take a test in school? Did you know that the teacher ALREADY KNOWS THE RIGHT ANSWERS?
Admin
Admin
Well... Sometimes you need to show the teachers that the answers they know are wrong.
Admin
I was talking about how the given starting point would actually be listed as the ending point. Of course, since it's a path, it can be turned around, hence the sandwich analogy.
A cleverer individual might have noticed that without assistance.
Admin
Hi.
This was a really nice task! A bit harder this time, but solvable. Here is my recursive Perl-approach, including a manual switch for the hard or easy condition (starting field == ending field ?).
Greetings H2
Admin
#!perl
use strict; use Net::Amazon::MechanicalTurk;
my ($x, $pos) = @ARGV;
my $mturk = Net::Amazon::MechanicalTurk->new( serviceUrl => 'http://mechanicalturk.sandbox.amazonaws.com/?Service=AWSMechanicalTurkRequester', serviceVersion => '2007-06-21', accessKey => '1AAAAA1A1AAAAA11AA11', secretKey => '1aAaAAAAAAAA+aAaAaaaaaaAAA/AAAAAA1a1aAaa' );
my $question = "Solve the Knight's Tour problem for a grid of $x by $x starting at position $pos";
Admin
This is my implementation in Java...
Cheers! SF
Admin
Ugly OCaml solution using backtrack:
Admin
Admin
Here is my python based DFS algorithm. It takes forever because of my data type choices, and the fact that it's DFS... but it gets the job done.
Admin
Two possible outs.
change the problem to consider a "tour" to be a Hamiltonian circuit of all the squares /with the right parity./
use a different 3D generalization of the knight's move (e.g., to the opposite corner of a 1 x 2 x 3 rectangular prism... or 1 x 2 x 4, perhaps.)
Admin
You keep using that word. I dinna think it means what you think it means.
Admin
You fell victim to one of the classic blunders! The most famous is never get involved in the daily wtf programmatic praxis, but only slightly less well-known is this: never go in against a Turk when chess is on the line!
Admin
This is backtracing Javascript version. Note 1] it's terribly slooooww (now I'm really happy that I didn't try to implement it on ZX Spectrum :-) ), 2] it tries to render progress, however it shows only in Opera, other browsers are too stupid to be able to render something during script run.
Online (not recommended if you are not using Opera).
BTW the antispam really sucks :-)
Admin
Admin
You missed the degenerate case of a 1x1 board: there are no moves in the Knight's Tour and the knight starts and ends on the same piece.
Admin
1), 2), 3) and 5): Two empty mosaics; i.e no colored pieces. 4): No colors.
Admin
Crappy brute force depth first recursive solution in matlab. It doesn't check for closed loops however.
KnightTour.m:
doMove.m:
Admin
backtracking... I must have a solution in ADA somewhere back from the early college years.
Admin
Python solution that does brute force and the algorithm thingey on wikipedia.
''' Created on Aug 13, 2009
@author: silo ''' from Numeric import zeros import random
def possibleMoves(board, knightMoves, knightLoc): moveList = [] for move in knightMoves: newPos = (knightLoc[0] + move[0],knightLoc[1] + move[1]) if legalMove(newPos, board): moveList.append(move) return moveList
def legalMove(newPos, board): if(newPos[0] >= 0 and newPos[1] >=0 and newPos[0] < len(board) and newPos[1] <len(board)): if(board[newPos[0]][newPos[1]] == 0): return True return False
def performMove(move, board, knightLoc, moveCounter): newPos = (knightLoc[0] + move[0],knightLoc[1] + move[1]) board[newPos[0]][newPos[1]] = moveCounter return newPos
def boardIsComplete(board, currentPos, startingPos, closed):
def selectMove(moveList): return moveList[random.randint(0,len(moveList)-1)]
def completeBoard(startLoc, board, knightMoves): knightLoc = startLoc takenMoves = [] moveCounter = 2 while True: moves = possibleMoves(board, knightMoves, knightLoc) if len(moves) == 0: break move = selectMove(moves); takenMoves.append(move); knightLoc = performMove(move, board, knightLoc, moveCounter) moveCounter = moveCounter + 1 return (board, takenMoves, knightLoc)
def useAlg(startLoc, board, knightMoves): knightLoc = startLoc takenMoves = [] moveCounter = 2 while True: moves = possibleMoves(board, knightMoves, knightLoc) if len(moves) == 0: break nMoves = 10; moveToTake = knightMoves[0] for move in moves: newNMoves = len(possibleMoves(board,knightMoves, (knightLoc[0] + move[0],knightLoc[1] + move[1]))) if newNMoves < nMoves: nMoves = newNMoves moveToTake = move takenMoves.append(moveToTake); knightLoc = performMove(moveToTake, board, knightLoc, moveCounter) moveCounter = moveCounter + 1 return (board, takenMoves, knightLoc)
def performTour(startLoc, board, knightMoves, closed): while True: board = zeros(boardSize) board[startLoc[0]][startLoc[1]] = 1 completedBoard = completeBoard(startLoc, board, knightMoves) if boardIsComplete(completedBoard[0],completedBoard[2], startLoc, closed): break return completedBoard
knightMoves = [(-2,1),(-2,-1),(-1,2), (-1,-2), (1,2), (1,-2), (2,1), (2,-1)] boardSize = 5,5 startLoc = (0,0) board = zeros(boardSize) board[startLoc[0]][startLoc[1]] = 1 closed = False #completedBoard = useAlg(startLoc, board, knightMoves) completedBoard = performTour(startLoc, board, knightMoves, closed)
print completedBoard[0] print completedBoard[1
Admin
I know this is late, but I have devised an ultra-fast algorithm for this problem, based on splicing a bunch of small, hard-coded tours together. This can calculate a 1000x1000 tour in 10 seconds. It would be easy to rewrite in any language, and would parallelise well.
Admin
Another perl solution (prints all possible tours)
#!/usr/bin/perl -- my $boardside=6; $startx=3; $starty=3; my @board=(1..(($boardside+4)*($boardside+4)));
sub getboardfield { my ($boardref,$x,$y)=(@_); my $board=$boardref; $len=@board; $side=sqrt($len)-4; #print "side=$side\n"; $elnum=($x+1)*($side+4)+($y+1); $retval=$board->[$elnum]; #print "elnum=$elnum, returning $retval\n"; return $retval; }
sub setboardfield { my ($boardref,$x,$y,$val)=(@_); my $board=$boardref; $len=@board; $side=sqrt($len)-4; #print "setboardfield($x,$y,$val) of board w/size $side*$side \n"; $elnum=($x+1)*($side+4)+($y+1); #print "elnum=$elnum\n"; $board->[$elnum]=$val; }
sub initboard { my ($boardref)=(@_); #my @board=@{$boardref}; my $board=$boardref; $len=@board; $side=sqrt($len)-2; # edges for ($i=0;$i<$len;$i++) { $board->[$i]=-1; }
}
sub printboard { my ($boardref)=(@_); my @board=@{$boardref}; print "\n"; $len=@board; $side=sqrt($len)-2; for ($x=1;$x<=$side;$x++) { for ($y=1;$y<=$side;$y++) { $v=getboardfield($boardref,$x,$y); $fieldcontent="."; if ($v>0) { $fieldcontent=$v; } printf "%02d ", $fieldcontent; } print "\n"; } }
sub solve { my ($boardref,$currentstep,$startx,$starty,$x,$y)=(@_); #print "solve step $currentstep startx,y=$startx,$starty x,y=$x,$y\n"; my @board=@{$boardref}; if (getboardfield($boardref,$x,$y)!=0) { return; } $len=@board; $side=sqrt($len)-4; setboardfield($boardref,$x,$y,$currentstep); if ($currentstep>=(($side*$side))) { printboard($boardref); return; } solve($boardref,$currentstep+1,$startx,$starty,$x-2,$y-1); solve($boardref,$currentstep+1,$startx,$starty,$x-1,$y-2); solve($boardref,$currentstep+1,$startx,$starty,$x+1,$y-2); solve($boardref,$currentstep+1,$startx,$starty,$x+2,$y-1); solve($boardref,$currentstep+1,$startx,$starty,$x-2,$y+1); solve($boardref,$currentstep+1,$startx,$starty,$x-1,$y+2); solve($boardref,$currentstep+1,$startx,$starty,$x+1,$y+2); solve($boardref,$currentstep+1,$startx,$starty,$x+2,$y+1); setboardfield($boardref,$x,$y,0); }
initboard(@board); $currentstep=1; $x=$startx; $y=$starty; solve(@board,$currentstep,$startx,$starty,$x,$y);
Admin
The source code is too long to post here so I embedded it in the image. Save the image somewhere and rename it to a .rar extension to extract the files.
The algorithm is simply to splice together a bunch of smaller, hardcoded tours.
Admin
Okay, that's weird. The file appears to begin with a PNG header, and has a RAR header much further down. I can understand a PNG being OK with garbage at the end, but why would RAR allow garbage at the top of the file?
Works, though!
Admin
copy /b in.png + knightstour.rar out.png
Admin
My first Common Lisp program for ten years. If any Lispers out there can critique my program, I'd appreciate it.
My first version was annoyingly slow, so this uses http://en.wikipedia.org/wiki/Knight%27s_tour#Warnsdorff.27s_algorithm
Usage:
Admin
Every packer I know allows that. It allows the (un)packer to open self-extracting archives, which is often useful (e.g. for extracting the self-extracting archive on a different platform, etc.)
Admin
Nice and fast, but it does not allow to set the start position. Is that limitation of that algorthm? And I noticed that for some sizes the end position is not equal the start position, I don't know if it is because such soluton does not exists for a particular size (that it should warn about it) or it just ignores this rule.
Anyway, cool solution.
Admin
As for setting the starting point, that turns out not to have any real impact on the problem. The problem statment asks for the knight returns to its starting point: in that case, the starting point is meaningless.
Admin
load "Array2";
exception noMove
fun addPos (x, y) (xs, ys) = (x + xs, y + ys)
fun legalMoves [] _ = [] | legalMoves ((x, y) :: xs) n = if (x > 0 andalso x <= n) andalso (y > 0 andalso y <= n) then (x, y) :: legalMoves xs n else legalMoves xs n;
fun testMoves [] _ _ _ _ = raise noMove | testMoves ((x, y) :: xs) matrix start size count =
let val newMatrix = Array2.array(size, size, 0) val someSize = (SOME size) val region = {base = matrix, row = 0, col = 0, nrows = someSize, ncols = someSize} val contain = {src = region, dst = newMatrix, dst_row = 0, dst_col = 0} val test = Array2.copy contain val already = Array2.sub(newMatrix, x - 1, y - 1) val test2 = Array2.update(newMatrix, x - 1, y - 1, 1) in if already = 0 (We haven't already visited the position - so we try that path) then (x, y) :: doStep (x, y) newMatrix start size count handle noMove => testMoves xs matrix start size count (We have already visited this position, so we try another possible move) else testMoves xs matrix start size count end and doStep (x, y) matrix start size count = let val moveMod = [(1,2), (2,1), (2, ~1), (1, ~2), (~1, ~2), (~2, ~1), (~2, 1), (~1, 2)] val allMoves = map (addPos (x, y)) moveMod val moves = legalMoves allMoves size in
if (x, y) = start andalso count = (size * size) then start :: [] else if moves = [] orelse ((x, y) = start andalso count > 0) then raise noMove else testMoves moves matrix start size (count + 1) end;
fun knightRun size pos = let val matrix = Array2.array(size, size, 0) in if size % 2 = 0 then doStep pos matrix pos size 0 else [] end;
Admin
You'll find that nearly all problems out there have been solved by thousands before, even ones you haven't heard of. It still can be a challenge - just don't Google the answer. Sit back in your chair, think about the problem, and try and solve it on your own, using what you know. THAT is the whole idea behind problem solving challenges - not who can Google a solution the fastest.
Some people feel that posting an answer the fastest must be "winning" these challenges - it's not.
Once again:
If you really want to test your intellect on unsolved problems that you can't Google and get an answer to, here's a list to get you started:
http://mathworld.wolfram.com/UnsolvedProblems.html
Admin
Can anybody please write a solution for square 4x4 and 5x5 with using DFS (depth-first algorithm) in java or C#?
Admin
How about making the board into a torus? Sphere will also do.