Q. How many distinct ways can 6 knights be placed on a 4 by 4 chess board, so that no knight attacks another knight? (And by distinct, rotations don’t count as a separate solution)
– from chessexpress, Sept 2017
Cython program, type OK()
to run:
#sixknights.pyx - placing 6 knights on a 4x4 board, rotations aren't counted. #quarters of board are numbered 0,1,2,3 clockwise from upper left. #squares in upper left are named 3,2 (top row) 1,0 (lower row), this is rotated for each quarter #so e.g. 3 is the corner square in each quarter, 0 the centre square etc #the 'score' for a quarter is the sum of powers of 2 of the knight square numbers. #canonical order: no quarter can have a higher score than the UL quarter. DEF NUMKNIGHTS = 6 DEF NUMRULES = 12 cdef: short Board[4][4], Quad[4][4] #i.e. Quad[0][1] means quadrant 0, square 1 = a3 int x[16], y[16], whichSquare[16], whichQuad[16],codelist[200][4] int tally = 0, rules[NUMRULES][3], rulelist[36], N[6] x[:] = [1,1,0,0,2,3,2,3,2,2,3,3,1,0,1,0] #gives the board coordinates for sq pos 0-15 y[:] = [2,3,2,3,2,2,3,3,1,0,1,0,1,1,0,0] whichQuad[:] = [3,3,3,3,2,2,2,2,1,1,1,1,0,0,0,0] #for each sq pos, which quadrant whichSquare[:] = [0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3] #which square in that quadrant rulelist[:] = [3,3,0, 3,1,0, 2,1,2, 2,2,0, 2,3,2, 1,1,1, 1,2,0, 1,3,1, 0,1,3, 0,2,1, 0,2,2, 0,3,3] txt = open("/Users/admin/data.txt", "w") cdef RotatedVersionAlreadyOnList(int code[]): for i in xrange(1,tally+1): for j in xrange(4): if codelist[i][0] == code[j] and codelist[i][1] == code[(j+1)%4] \ and codelist[i][2] == code[(j+2)%4] and codelist[i][3] == code[(j+3)%4]: return True return False cdef int PassKnightTests(int N[], int numOfNs): for i in xrange(4): Quad[i][:] = [0,0,0,0] for i in xrange(numOfNs): Quad[whichQuad[N[i]]][whichSquare[N[i]]] = 1 for j in xrange(NUMRULES): #rule[x,y,z] means: If Quad[i][x] == 1, for i in xrange(4): #and Quad[(i+y)%4][z] = 1, fail test - i.e. clashing knights if Quad[i][rules[j][0]] == 1: if Quad[(i+rules[j][1])%4][rules[j][2]] == 1: return False return True cdef TestAndWrite(int N[]): global tally cdef int score[4] for i in xrange(4): score[i]=0 Board[i][:] = [0,0,0,0] for i in xrange(NUMKNIGHTS): Board[x[N[i]]][y[N[i]]] = 1 score[whichQuad[N[i]]] += 2**whichSquare[N[i]] if RotatedVersionAlreadyOnList(score): return tally += 1 codelist[tally][:] = score txt.write("#%d. %d-%d-%d-%d\n" % (tally,score[0],score[1],score[2],score[3])) for j in xrange(4): for i in xrange(4): txt.write("%d " % Board[i][j]) txt.write("\n") cdef AddKnight(int level,int N[]): if level>1: if not PassKnightTests(N,level): return if level == NUMKNIGHTS: #have placed knights 0-5 already TestAndWrite(N) else: #place next knight if N[level-1]>0: #room for another knight for i in xrange(N[level-1]-1,-1,-1): # i.e. go down to 0 N[level] = i #place Knight no. 'level' on square i AddKnight(level+1,N) cpdef OK(): for i in xrange(NUMRULES): for j in xrange(3): rules[i][j] = rulelist[i*3+j] N[:] = [0,0,0,0,0,0] for i in xrange(15,12,-1): #first knight can be only in pos 15-13, w.l.o.g N[0] = i AddKnight(1,N) txt.write("Found %d.\n" % tally) txt.close()
Which produces the file:
#1. 14-8-12-0 1 1 0 1 1 0 0 0 0 0 0 0 0 0 1 1 #2. 14-8-10-0 1 1 0 1 1 0 0 0 0 0 0 1 0 0 0 1 #3. 14-8-8-8 1 1 0 1 1 0 0 0 0 0 0 0 1 0 0 1 #4. 14-8-6-0 1 1 0 1 1 0 0 0 0 0 0 1 0 0 1 0 #5. 14-8-4-8 1 1 0 1 1 0 0 0 0 0 0 0 1 0 1 0 #6. 14-8-2-8 1 1 0 1 1 0 0 0 0 0 0 1 1 0 0 0 #7. 14-0-14-0 1 1 0 0 1 0 0 0 0 0 0 1 0 0 1 1 #8. 14-0-12-8 1 1 0 0 1 0 0 0 0 0 0 0 1 0 1 1 #9. 14-0-10-8 1 1 0 0 1 0 0 0 0 0 0 1 1 0 0 1 #10. 14-0-6-8 1 1 0 0 1 0 0 0 0 0 0 1 1 0 1 0 #11. 13-2-8-2 1 1 1 0 0 1 0 0 0 0 0 0 0 1 0 1 #12. 12-10-12-0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 #13. 12-10-8-8 1 1 1 1 0 0 0 0 0 0 0 0 1 0 0 1 #14. 12-10-8-2 1 1 1 1 0 0 0 0 0 0 0 0 0 1 0 1 #15. 12-10-4-8 1 1 1 1 0 0 0 0 0 0 0 0 1 0 1 0 #16. 12-10-4-2 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 0 #17. 12-10-0-10 1 1 1 1 0 0 0 0 0 0 0 0 1 1 0 0 #18. 12-8-12-8 1 1 0 1 0 0 0 0 0 0 0 0 1 0 1 1 #19. 12-8-12-2 1 1 0 1 0 0 0 0 0 0 0 0 0 1 1 1 #20. 12-8-10-8 1 1 0 1 0 0 0 0 0 0 0 1 1 0 0 1 #21. 12-8-8-10 1 1 0 1 0 0 0 0 0 0 0 0 1 1 0 1 #22. 12-8-6-8 1 1 0 1 0 0 0 0 0 0 0 1 1 0 1 0 #23. 12-8-4-10 1 1 0 1 0 0 0 0 0 0 0 0 1 1 1 0 #24. 12-2-12-2 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 #25. 12-2-8-10 1 1 1 0 0 0 0 0 0 0 0 0 1 1 0 1 #26. 12-2-4-10 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 0 #27. 11-4-8-4 1 0 0 0 1 1 0 1 1 0 0 0 0 0 0 1 #28. 10-8-10-8 1 0 0 1 1 0 0 0 0 0 0 1 1 0 0 1 #29. 10-8-10-4 1 0 0 1 1 0 0 0 1 0 0 1 0 0 0 1 #30. 10-8-6-8 1 0 0 1 1 0 0 0 0 0 0 1 1 0 1 0 #31. 10-4-10-4 1 0 0 0 1 0 0 1 1 0 0 1 0 0 0 1 #32. 9-6-9-0 1 0 1 0 0 1 0 1 0 0 1 0 0 0 0 1 #33. 9-6-8-4 1 0 1 0 0 1 0 1 1 0 0 0 0 0 0 1 #34. 9-6-8-2 1 0 1 0 0 1 0 1 0 0 0 0 0 1 0 1 #35. 9-6-1-4 1 0 1 0 0 1 0 1 1 0 1 0 0 0 0 0 #36. 9-6-1-2 1 0 1 0 0 1 0 1 0 0 1 0 0 1 0 0 #37. 9-6-0-6 1 0 1 0 0 1 0 1 1 0 0 0 0 1 0 0 #38. 9-4-9-4 1 0 0 0 0 1 0 1 1 0 1 0 0 0 0 1 #39. 9-4-9-2 1 0 0 0 0 1 0 1 0 0 1 0 0 1 0 1 #40. 9-4-8-6 1 0 0 0 0 1 0 1 1 0 0 0 0 1 0 1 #41. 9-4-1-6 1 0 0 0 0 1 0 1 1 0 1 0 0 1 0 0 #42. 9-2-9-2 1 0 1 0 0 1 0 0 0 0 1 0 0 1 0 1 #43. 9-2-8-6 1 0 1 0 0 1 0 0 1 0 0 0 0 1 0 1 #44. 9-2-1-6 1 0 1 0 0 1 0 0 1 0 1 0 0 1 0 0 #45. 8-6-8-6 1 0 1 0 0 0 0 1 1 0 0 0 0 1 0 1 #46. 8-6-1-6 1 0 1 0 0 0 0 1 1 0 1 0 0 1 0 0 #47. 6-1-6-1 0 1 0 0 1 0 1 0 0 1 0 1 0 0 1 0 Found 47.