mirror of
https://github.com/InternLM/InternBootcamp.git
synced 2026-04-26 17:13:14 +00:00
init-commit
This commit is contained in:
commit
18a552597a
3461 changed files with 1150579 additions and 0 deletions
140
internbootcamp/libs/campsite/campsite_solver.py
Executable file
140
internbootcamp/libs/campsite/campsite_solver.py
Executable file
|
|
@ -0,0 +1,140 @@
|
|||
def solve_campsite(grid, row_constraints, col_constraints):
|
||||
"""
|
||||
Solve the 'Campsite' puzzle using backtracking.
|
||||
|
||||
:param grid: A list of lists of characters ('T' or 'X') of size n×m.
|
||||
:param row_constraints: A list of length n with the required tent count per row.
|
||||
:param col_constraints: A list of length m with the required tent count per column.
|
||||
:return: A list of lists representing a solution (replacing 'X' with either 'C' or 'X'),
|
||||
or None if no solution exists.
|
||||
"""
|
||||
|
||||
n = len(grid)
|
||||
m = len(grid[0])
|
||||
|
||||
# Copy the grid to store the solution without mutating the original
|
||||
solution = [row[:] for row in grid]
|
||||
|
||||
# Track how many tents are currently placed in each row/column
|
||||
current_row_tents = [0] * n
|
||||
current_col_tents = [0] * m
|
||||
|
||||
# Precompute which cells are adjacent to at least one tree
|
||||
# because a tent can only go orthogonally adjacent to a tree
|
||||
adjacent_to_tree = [[False]*m for _ in range(n)]
|
||||
directions_orth = [(-1, 0), (1, 0), (0, -1), (0, 1)]
|
||||
for r in range(n):
|
||||
for c in range(m):
|
||||
if grid[r][c] == 'T':
|
||||
for dr, dc in directions_orth:
|
||||
rr, cc = r+dr, c+dc
|
||||
if 0 <= rr < n and 0 <= cc < m and grid[rr][cc] == 'X':
|
||||
adjacent_to_tree[rr][cc] = True
|
||||
|
||||
# Helper function to check if placing a tent at (r, c) violates adjacency constraints
|
||||
def can_place_tent(r, c):
|
||||
# If the cell is not empty or not adjacent to a tree, cannot place a tent
|
||||
if solution[r][c] != 'X' or not adjacent_to_tree[r][c]:
|
||||
return False
|
||||
|
||||
# Check row/col constraints if adding one more tent is still valid
|
||||
if current_row_tents[r] + 1 > row_constraints[r]:
|
||||
return False
|
||||
if current_col_tents[c] + 1 > col_constraints[c]:
|
||||
return False
|
||||
|
||||
# Tents cannot be adjacent (orth or diag) to any existing tent
|
||||
# We'll check the 8 directions around (r, c)
|
||||
directions_all = [
|
||||
(-1, 0), (1, 0), (0, -1), (0, 1),
|
||||
(-1, -1), (-1, 1), (1, -1), (1, 1)
|
||||
]
|
||||
for dr, dc in directions_all:
|
||||
rr, cc = r+dr, c+dc
|
||||
if 0 <= rr < n and 0 <= cc < m and solution[rr][cc] == 'C':
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
# A list of all grid coordinates we might try to fill
|
||||
# Sorting them can sometimes help performance, but plain is fine, too.
|
||||
all_cells = [(r, c) for r in range(n) for c in range(m)]
|
||||
history = []
|
||||
|
||||
# We'll do a simple backtracking approach that tries to place a tent or not
|
||||
def backtrack(idx=0):
|
||||
if idx == len(all_cells):
|
||||
history.append(f"All positions have been tried. Check if the current solution satisfies the row constraints and the col constraints.\n")
|
||||
is_satisfy = all(current_row_tents[r] == row_constraints[r] for r in range(n)) and all(current_col_tents[c] == col_constraints[c] for c in range(m))
|
||||
if is_satisfy:
|
||||
history.append("The current solution satisfy all the conditions. Find the solution!\n")
|
||||
else:
|
||||
history.append("The current solution does not satisfy all the conditions.\n")
|
||||
return is_satisfy
|
||||
|
||||
r, c = all_cells[idx]
|
||||
history.append(f"Select ({r},{c}), check if the tent can be placed in this location.\n")
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# OPTION 1: Place a tent in (r, c) if it's a valid move
|
||||
# -----------------------------------------------------------
|
||||
if can_place_tent(r, c):
|
||||
history.append(f"Tent can be placed at ({r},{c}). Place a tent at ({r},{c}).\n")
|
||||
solution[r][c] = 'C'
|
||||
current_row_tents[r] += 1
|
||||
current_col_tents[c] += 1
|
||||
|
||||
if backtrack(idx + 1):
|
||||
return True
|
||||
|
||||
history.append(f"Since current solution fails. Change the current location ({r},{c}) from a tent(C) to an open space(X). Then retry.\n")
|
||||
# Backtrack (undo placement)
|
||||
solution[r][c] = 'X'
|
||||
current_row_tents[r] -= 1
|
||||
current_col_tents[c] -= 1
|
||||
else:
|
||||
history.append(f"No tents can be placed in ({r},{c}).\n")
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# OPTION 2: Skip placing a tent at (r, c)
|
||||
# -----------------------------------------------------------
|
||||
if backtrack(idx + 1):
|
||||
return True
|
||||
history.append(f"Since there is no tent placed at the current location ({r},{c}), we backtrack to the previous location.\n")
|
||||
|
||||
# If neither placing nor skipping yields a solution, fail here
|
||||
return False
|
||||
|
||||
# Kick off the backtracking
|
||||
if backtrack():
|
||||
history.append('\nThe final answer is: '+'{'+'\n'.join([' '.join(row) for row in solution]) + '}')
|
||||
steps = ''.join(history)
|
||||
return solution, steps
|
||||
else:
|
||||
return None
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Example usage:
|
||||
#
|
||||
# Suppose you have the puzzle:
|
||||
if __name__ == "__main__":
|
||||
grid = [
|
||||
['X','X','X','X','X','T','X','X','T','X'],
|
||||
['X','T','X','X','X','X','X','X','X','X'],
|
||||
['X','X','X','T','T','X','X','X','X','X'],
|
||||
['T','X','X','X','X','X','T','T','X','X'],
|
||||
['X','T','X','X','T','X','X','X','X','X']
|
||||
]
|
||||
row_constraints = [3, 1, 3, 0, 3]
|
||||
col_constraints = [2, 1, 1, 1, 1, 0, 2, 1, 0, 1]
|
||||
|
||||
solved, steps = solve_campsite(grid, row_constraints, col_constraints)
|
||||
if solved:
|
||||
# Format the output as requested
|
||||
print(steps)
|
||||
else:
|
||||
print("No solution found (but puzzle is assumed to have a unique solution).")
|
||||
#
|
||||
# You can adapt this to parse your input format, then call `solve_campsite`
|
||||
# to get the solution, and finally output the result in the requested
|
||||
# "[[row1, row2, ...]]" string format.
|
||||
Loading…
Add table
Add a link
Reference in a new issue