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()
