import numpy as np
import math
from prettytable import PrettyTable

def distance_in_each_coordinate(x, y):
    return [ abs(a-b) for (a,b) in zip(x, y) ]

# x1 = (50, -12, 34)
# x2 = (49, -11, 34)
# y = (-5, 24, 65)

# print(distance_in_each_coordinate(x2, y), end=" ")
# total_dist = 0
# n = np.array(distance_in_each_coordinate(x2, y)) 
# while (n.shape[0] > 0):
#     m = min(n)
#     n -= m
#     total_dist += m
#     n = n[n != 0]
# print(total_dist)

def grid_queen_2D_heuristic(current, destination):
    total_dist = 0
    n = np.array(distance_in_each_coordinate(current, destination))
    while (n.shape[0] > 0):
        print(n, end=" ")
        m = min(n)
        if (m%8 != 0): ## when not exactly 8*x steps
            total_dist += 1
        total_dist += m//8
        n -= m
        n = n[n != 0]
        print(n)
    print(total_dist)
    return total_dist.item()

def grid_great_king_2D_heuristic(current, destination):
    total_dist = 0
    n = np.array(distance_in_each_coordinate(current, destination))
    while (n.shape[0] > 0):
        m = min(n)
        if (m%8 != 0): ## when not exactly 8*x steps
            total_dist += 1
        total_dist += m//8
        n -= m
        n = n[n != 0]
        if (n.shape[0] > 0 and n[0] > 0 and n[0] <= (m%8)):
            n[0] -= n[0]
            n = n[n != 0]
    return total_dist.item()

def grid_jumper_2D_heuristic(current, destination):
    n = distance_in_each_coordinate(current, destination)
    x = n[0]
    y = n[1]
    a = round(max(x/2, y/2, (x+y)/3))
    return a + ((a + x + y) % 2)

# x1 = (-5,-3)
# x2 = (-2,-5)
# y = (172, 174)

# a, b = distance_in_each_coordinate(x1, y)
# print([a, b])
# if (a > b):
#     print(((a/3), (b/2)))
#     print([math.ceil(a/3), math.ceil(b/2)])
# else:
#     print(((a/2), (b/3)))
#     print([math.ceil(a/2), math.ceil(b/3)])
# a, b = distance_in_each_coordinate(x2, y)
# print([a, b])
# if (a > b):
#     print(((a/3), (b/2)))
#     print([math.ceil(a/3), math.ceil(b/2)])
# else:
#     print(((a/2), (b/3)))
#     print([math.ceil(a/2), math.ceil(b/3)])

def print_grid(grid, grid_size):
    for i in range(grid_size):
        for j in range(grid_size):
            if (grid[i][j] == 0 and i == 0 and j == 0):
                print("  ", end="")
                print("0", end=" ")
            elif(grid[i][j] == 0):
                print("  ", end="")
                print("-", end=" ")
            elif (grid[i][j] > 9):
                print(" ", end="")
                print(grid[i][j], end=" ")
            else:
                print("  ", end="")
                print(grid[i][j], end=" ")
        print()
    for _ in range(grid_size):
        print("__", end="")
    print()

def write_out_grid(grid, grid_size):
    file = open("output.csv", "a")
    for i in range(grid_size):
        for j in range(grid_size):
            if (grid[i][j] == 0):
                file.write(";")
            else:
                file.write(str(grid[i][j]))
                file.write(";")
        file.write("\n")
    file.write("\n")
    file.close()



grid_size = 32
grid = [[0 for _ in range(grid_size)] for _ in range(grid_size)] 
stack = []
stack.append(((0,0), 0))
moves = [(3, 2), (3, -2), (-3, 2), (-3, -2)]
grid[0][0] = -1
while (len(stack) != 0):
    item = stack.pop(0)
    x = item[0][0]
    y = item[0][1]
    steps = item[1]
    if (grid[x][y] == 0 or grid[x][y] > steps):
        grid[x][y] = steps
    # print_grid(grid, grid_size)
    # print()
    for move in moves:
        nx = x + move[0]
        ny = y + move[1]
        if (nx >= 0 and nx <= grid_size-1 and ny >= 0 and ny <= grid_size - 1):
            if (grid[nx][ny] == 0 or grid[nx][ny] > steps + 1):
                stack.insert(0, ((nx, ny), steps + 1))
grid[0][0] = 0
write_out_grid(grid, grid_size)
print_grid(grid, grid_size)

grid_size = 32
grid = [[0 for _ in range(grid_size)] for _ in range(grid_size)] 
stack = []
stack.append(((0,0), 0))
moves = [(2, 3), (2, -3), (-2, 3), (-2, -3)]
grid[0][0] = -1
while (len(stack) != 0):
    item = stack.pop(0)
    x = item[0][0]
    y = item[0][1]
    steps = item[1]
    if (grid[x][y] == 0 or grid[x][y] > steps):
        grid[x][y] = steps
    # print_grid(grid, grid_size)
    # print()
    for move in moves:
        nx = x + move[0]
        ny = y + move[1]
        if (nx >= 0 and nx <= grid_size-1 and ny >= 0 and ny <= grid_size - 1):
            if (grid[nx][ny] == 0 or grid[nx][ny] > steps + 1):
                stack.insert(0, ((nx, ny), steps + 1))
grid[0][0] = 0
write_out_grid(grid, grid_size)
print_grid(grid, grid_size)

grid_size = 32
grid = [[0 for _ in range(grid_size)] for _ in range(grid_size)] 
stack = []
stack.append(((0,0), 0))
moves = [(3, 2), (3, -2), (-3, 2), (-3, -2), (2, 3), (2, -3), (-2, 3), (-2, -3)]
grid[0][0] = -1
while (len(stack) != 0):
    item = stack.pop(0)
    x = item[0][0]
    y = item[0][1]
    steps = item[1]
    if (grid[x][y] == 0 or grid[x][y] > steps):
        grid[x][y] = steps
    # print_grid(grid, grid_size)
    # print()
    for move in moves:
        nx = x + move[0]
        ny = y + move[1]
        if (nx >= 0 and nx <= grid_size-1 and ny >= 0 and ny <= grid_size - 1):
            if (grid[nx][ny] == 0 or grid[nx][ny] > steps + 1):
                stack.insert(0, ((nx, ny), steps + 1))
grid[0][0] = 0
write_out_grid(grid, grid_size)
print_grid(grid, grid_size)

    







