Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

15 Puzzle

The goal of the 15 puzzle problem is to complete pieces on $4 \times 4$ cells where one of the cells is empty space.

In this problem, the space is represented by 0 and pieces are represented by integers from 1 to 15 as shown below.

1 2 3 4
6 7 8 0
5 10 11 12
9 13 14 15

You can move a piece toward the empty space at one step. Your goal is to make the pieces the following configuration in the shortest move (fewest steps).

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 0

Write a program which reads an initial state of the puzzle and prints the fewest steps to solve the puzzle.

Input

The $4 \times 4$ integers denoting the pieces or space are given.

Output

Print the fewest steps in a line.

Constraints

The given puzzle is solvable in at most 45 steps.

Sample Input

1 2 3 4
6 7 8 0
5 10 11 12
9 13 14 15

Sample Output

8

Solution in Python3 (judge verdict: Time Limit Exceeded)

goal = ((1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12), (13, 14, 15, 0))
goal_position = [
[3, 3],
[0, 0],
[0, 1],
[0, 2],
[0, 3],
[1, 0],
[1, 1],
[1, 2],
[1, 3],
[2, 0],
[2, 1],
[2, 2],
[2, 3],
[3, 0],
[3, 1],
[3, 2]
]

N = 4

stack = []
steps = []
positions = []
hash_stack = []

initial = []
position = []
hash_table = set()
for i in range(N):
	a, b, c, d = map(int, input().split())
	if a == 0:
		position.extend([i, 0])
	elif b == 0:
		position.extend([i, 1])
	elif c == 0:
 		position.extend([i, 2])
	elif d == 0:
 		position.extend([i, 3])
	initial.append( [a, b, c, d] )

stack.append(initial)
steps.append(0)
positions.append(position)

hash_table.add(tuple(initial[0]) + tuple(initial[1]) + tuple(initial[2]) + tuple(initial[3]))
hash_stack.append(hash_table)


limit = 45


def calc_heuristic(state):
	dis_sum = 0
	for i in range(N):
		for j in range(N):
			if state[i][j] != 0:
				dis_sum += abs(i - goal_position[state[i][j]][0])
				dis_sum += abs(j - goal_position[state[i][j]][1])
	return dis_sum


import copy

while len(stack) != 0:
	state = stack.pop()
	step = steps.pop()
	position = positions.pop()
	hash_table = hash_stack.pop()

	step += 1

	if position[0] < 3:
		child = copy.deepcopy(state)
		child[position[0]][position[1]] = child[position[0]+1][position[1]]
		child[position[0]+1][position[1]] = 0
		h = calc_heuristic(child)
		child_tuple = tuple(child[0]) + tuple(child[1]) + tuple(child[2]) + tuple(child[3])
		if h == 0:
			limit = step
			continue
		elif h + step <= limit and set(child_tuple).isdisjoint(hash_table):
			stack.append(child)
			steps.append(step)
			positions.append([position[0]+1, position[1]])

			hash_tmp = copy.deepcopy(hash_table)
			hash_tmp.add(child_tuple)
			hash_stack.append(hash_tmp)

	if position[1] < 3:
		child = copy.deepcopy(state)
		child[position[0]][position[1]] = child[position[0]][position[1]+1]
		child[position[0]][position[1]+1] = 0
		h = calc_heuristic(child)
		child_tuple = tuple(child[0]) + tuple(child[1]) + tuple(child[2]) + tuple(child[3])
		if h == 0:
			limit = step
			continue
		elif h + step <= limit and set(child_tuple).isdisjoint(hash_table):
			stack.append(child)
			steps.append(step)
			positions.append([position[0], position[1]+1])

			hash_tmp = copy.deepcopy(hash_table)
			hash_tmp.add(child_tuple)
			hash_stack.append(hash_tmp)


	if position[0] > 0:
		child = copy.deepcopy(state)
		child[position[0]][position[1]] = child[position[0]-1][position[1]]
		child[position[0]-1][position[1]] = 0
		h = calc_heuristic(child)
		child_tuple = tuple(child[0]) + tuple(child[1]) + tuple(child[2]) + tuple(child[3])
		if h == 0:
			limit = step
			continue
		elif h + step <= limit and set(child_tuple).isdisjoint(hash_table):
			stack.append(child)
			steps.append(step)
			positions.append([position[0]-1, position[1]])

			hash_tmp = copy.deepcopy(hash_table)
			hash_tmp.add(child_tuple)
			hash_stack.append(hash_tmp)


	if position[1] > 0:
		child = copy.deepcopy(state)
		child[position[0]][position[1]] = child[position[0]][position[1]-1]
		child[position[0]][position[1]-1] = 0
		h = calc_heuristic(child)
		child_tuple = tuple(child[0]) + tuple(child[1]) + tuple(child[2]) + tuple(child[3])
		if h == 0:
			limit = step
			continue
		elif h + step <= limit and set(child_tuple).isdisjoint(hash_table):
			stack.append(child)
			steps.append(step)
			positions.append([position[0], position[1]-1])

			hash_tmp = copy.deepcopy(hash_table)
			hash_tmp.add(child_tuple)
			hash_stack.append(hash_tmp)



print(limit)