import random
n = 10
startPosition = (-1, -1) # random if (-1, -1)
possibleMoves = [(3, 0), (2, 2), (0, 3), (-2, 2), (-3, 0), (-2, -2), (0, -3), (2, -2)]
nSquared = n * n
orderTable = []
def Solve():
global orderTable
orderTable = [[0 for x in range(n)] for y in range(n)]
x, y = startPosition
if x == y == -1:
x, y = random.randrange(n), random.randrange(n)
orderTable[y][x] = 1
for alreadyOrdered in range(1, nSquared):
nx, ny = NextFrom(x, y)
if nx == ny == -1:
return False
orderTable[ny][nx] = alreadyOrdered + 1
x, y = nx, ny
return True
def PrintSolution():
maxDigits = len(str(nSquared))
for row in orderTable:
print(' '.join((f'{value:{maxDigits}}' for value in row)))
def NextFrom(x, y):
nx, ny = -1, -1
minDegree = len(possibleMoves) + 1
for dstX, dstY in ValidDestinationsFrom(x, y):
dstDegree = CalculateDegreeOf(dstX, dstY)
if dstDegree < minDegree:
minDegree = dstDegree
nx, ny = dstX, dstY
return nx, ny
def InBounds(x, y):
return 0 <= x < n and 0 <= y < n
def ValidDestinationsFrom(x, y):
for dx, dy in possibleMoves:
nx, ny = x + dx, y + dy
if InBounds(nx, ny) and orderTable[ny][nx] == 0:
yield nx, ny
def CalculateDegreeOf(x, y):
return sum(1 for dst in ValidDestinationsFrom(x, y))
solutionFound = False
while not solutionFound:
solutionFound = Solve()
PrintSolution()
aW1wb3J0IHJhbmRvbQoKbiA9IDEwCnN0YXJ0UG9zaXRpb24gPSAoLTEsIC0xKSAgIyByYW5kb20gaWYgKC0xLCAtMSkKcG9zc2libGVNb3ZlcyA9IFsoMywgMCksICgyLCAyKSwgKDAsIDMpLCAoLTIsIDIpLCAoLTMsIDApLCAoLTIsIC0yKSwgKDAsIC0zKSwgKDIsIC0yKV0KCm5TcXVhcmVkID0gbiAqIG4Kb3JkZXJUYWJsZSA9IFtdCgoKZGVmIFNvbHZlKCk6CiAgICBnbG9iYWwgb3JkZXJUYWJsZQogICAgb3JkZXJUYWJsZSA9IFtbMCBmb3IgeCBpbiByYW5nZShuKV0gZm9yIHkgaW4gcmFuZ2UobildCgogICAgeCwgeSA9IHN0YXJ0UG9zaXRpb24KICAgIGlmIHggPT0geSA9PSAtMToKICAgICAgICB4LCB5ID0gcmFuZG9tLnJhbmRyYW5nZShuKSwgcmFuZG9tLnJhbmRyYW5nZShuKQogICAgb3JkZXJUYWJsZVt5XVt4XSA9IDEKCiAgICBmb3IgYWxyZWFkeU9yZGVyZWQgaW4gcmFuZ2UoMSwgblNxdWFyZWQpOgogICAgICAgIG54LCBueSA9IE5leHRGcm9tKHgsIHkpCiAgICAgICAgaWYgbnggPT0gbnkgPT0gLTE6CiAgICAgICAgICAgIHJldHVybiBGYWxzZQogICAgICAgIG9yZGVyVGFibGVbbnldW254XSA9IGFscmVhZHlPcmRlcmVkICsgMQogICAgICAgIHgsIHkgPSBueCwgbnkKICAgIHJldHVybiBUcnVlCgoKZGVmIFByaW50U29sdXRpb24oKToKICAgIG1heERpZ2l0cyA9IGxlbihzdHIoblNxdWFyZWQpKQogICAgZm9yIHJvdyBpbiBvcmRlclRhYmxlOgogICAgICAgIHByaW50KCcgJy5qb2luKChmJ3t2YWx1ZTp7bWF4RGlnaXRzfX0nIGZvciB2YWx1ZSBpbiByb3cpKSkKCgpkZWYgTmV4dEZyb20oeCwgeSk6CiAgICBueCwgbnkgPSAtMSwgLTEKICAgIG1pbkRlZ3JlZSA9IGxlbihwb3NzaWJsZU1vdmVzKSArIDEKICAgIGZvciBkc3RYLCBkc3RZIGluIFZhbGlkRGVzdGluYXRpb25zRnJvbSh4LCB5KToKICAgICAgICBkc3REZWdyZWUgPSBDYWxjdWxhdGVEZWdyZWVPZihkc3RYLCBkc3RZKQogICAgICAgIGlmIGRzdERlZ3JlZSA8IG1pbkRlZ3JlZToKICAgICAgICAgICAgbWluRGVncmVlID0gZHN0RGVncmVlCiAgICAgICAgICAgIG54LCBueSA9IGRzdFgsIGRzdFkKICAgIHJldHVybiBueCwgbnkKCgpkZWYgSW5Cb3VuZHMoeCwgeSk6CiAgICByZXR1cm4gMCA8PSB4IDwgbiBhbmQgMCA8PSB5IDwgbgoKCmRlZiBWYWxpZERlc3RpbmF0aW9uc0Zyb20oeCwgeSk6CiAgICBmb3IgZHgsIGR5IGluIHBvc3NpYmxlTW92ZXM6CiAgICAgICAgbngsIG55ID0geCArIGR4LCB5ICsgZHkKICAgICAgICBpZiBJbkJvdW5kcyhueCwgbnkpIGFuZCBvcmRlclRhYmxlW255XVtueF0gPT0gMDoKICAgICAgICAgICAgeWllbGQgbngsIG55CgoKZGVmIENhbGN1bGF0ZURlZ3JlZU9mKHgsIHkpOgogICAgcmV0dXJuIHN1bSgxIGZvciBkc3QgaW4gVmFsaWREZXN0aW5hdGlvbnNGcm9tKHgsIHkpKQoKCnNvbHV0aW9uRm91bmQgPSBGYWxzZQp3aGlsZSBub3Qgc29sdXRpb25Gb3VuZDoKICAgIHNvbHV0aW9uRm91bmQgPSBTb2x2ZSgpClByaW50U29sdXRpb24oKQo=