sliding-cubes-api / utils.py
quynhanh2610's picture
Update utils.py
02ea2e7 verified
Raw
History Blame Contribute Delete
4.46 kB
# utils.py
from collections import deque
def to_tuple_set(blocks):
return set(tuple(b) for b in blocks)
def to_list(blocks_set):
return [list(b) for b in sorted(blocks_set)]
def get_neighbors(block, dimension):
neighbors = []
if dimension == 2:
x, y = block
moves = [(1, 0), (-1, 0), (0, 1), (0, -1)]
for dx, dy in moves:
neighbors.append((x + dx, y + dy))
else:
x, y, z = block
moves = [
(1, 0, 0), (-1, 0, 0),
(0, 1, 0), (0, -1, 0),
(0, 0, 1), (0, 0, -1)
]
for dx, dy, dz in moves:
neighbors.append((x + dx, y + dy, z + dz))
return neighbors
def is_connected(blocks_set, dimension):
if not blocks_set:
return True
start_node = next(iter(blocks_set))
visited = {start_node}
queue = deque([start_node])
while queue:
curr = queue.popleft()
for neighbor in get_neighbors(curr, dimension):
if neighbor in blocks_set and neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)
return len(visited) == len(blocks_set)
def apply_move(blocks_set, from_coord, to_coord):
new_set = set(blocks_set)
if from_coord not in new_set:
raise ValueError("from_coord is not in the configuration.")
if to_coord in new_set:
raise ValueError("to_coord is already occupied.")
new_set.remove(from_coord)
new_set.add(to_coord)
return new_set
def is_move_connected(blocks_set, from_coord, to_coord, dimension):
# Điều kiện trong bài báo: C \ {c} phải liên thông trong khi cube đang move
temp_set = set(blocks_set)
temp_set.remove(from_coord)
if not is_connected(temp_set, dimension):
return False
# Sau khi đặt cube xuống vị trí mới, cấu hình cũng nên liên thông
new_set = apply_move(blocks_set, from_coord, to_coord)
return is_connected(new_set, dimension)
def potential(blocks, dimension):
"""
Potential theo bài báo:
Πc = wc(cx + 2cy + 4cz)
Với 2D, coi z = 0.
"""
total_potential = 0
for b in blocks:
x = b[0]
y = b[1]
z = b[2] if dimension == 3 else 0
if z > 1:
w = 17
elif z == 1:
w = 16
else:
if y > 1:
w = 3
elif y == 1:
w = 2
else:
w = 1
total_potential += w * (x + 2 * y + 4 * z)
return total_potential
def is_finished_2d(blocks_set):
"""
Một ô (x,y) finished nếu toàn bộ hình chữ nhật
{0..x} x {0..y} đều có trong cấu hình.
"""
for x, y in blocks_set:
for i in range(x + 1):
for j in range(y + 1):
if (i, j) not in blocks_set:
return False
return True
def is_finished_3d(blocks_set):
"""
Một cube (x,y,z) finished nếu toàn bộ cuboid
{0..x} x {0..y} x {0..z} đều có trong cấu hình.
"""
for x, y, z in blocks_set:
for i in range(x + 1):
for j in range(y + 1):
for k in range(z + 1):
if (i, j, k) not in blocks_set:
return False
return True
def make_step_info(
step_idx,
from_c,
to_c,
move_type,
blocks_before,
blocks_after,
pot_before,
pot_after,
connected_after,
finished_after,
operation=None
):
step = {
"step": step_idx,
"from": list(from_c),
"to": list(to_c),
"move_type": move_type,
"blocks_before": to_list(blocks_before),
"blocks_after": to_list(blocks_after),
"potential_before": pot_before,
"potential_after": pot_after,
"is_connected_after": connected_after,
"is_finished_after": finished_after
}
if operation is not None:
step["operation"] = operation
return step
def build_response(
success,
message,
dimension,
initial_info,
steps,
final_info,
status,
algorithm="greedy_potential"
):
return {
"success": success,
"message": message,
"dimension": dimension,
"algorithm": algorithm,
"initial": initial_info,
"steps": steps,
"final": final_info,
"total_steps": len(steps),
"status": status
}