InternBootcamp/internbootcamp/libs/campsite/campsite_validor.py
2025-05-23 15:27:15 +08:00

101 lines
No EOL
3.9 KiB
Python
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

def validate_campsite_solution(puzzle, row_constraints, col_constraints, solution):
"""
Checks if 'solution' is a valid solution to the given Campsite puzzle.
:param puzzle: 2D list (n×m), each cell is 'T' (tree) or 'X' (empty).
:param row_constraints: list of length n, how many tents should be in each row.
:param col_constraints: list of length m, how many tents should be in each column.
:param solution: 2D list (n×m), each cell is 'T', 'X', or 'C' (tent).
:return: (is_valid, message)
is_valid (bool) - True if the solution is valid, False otherwise
message (str) - Explanation if invalid, or "Valid solution" otherwise.
"""
n = len(puzzle)
m = len(puzzle[0])
# 1) Check the dimensions match
if len(solution) != n or any(len(row) != m for row in solution):
return False, "Solution dimension mismatch."
# 2) Puzzle 'T' must remain 'T' in the solution
for r in range(n):
for c in range(m):
if puzzle[r][c] == 'T' and solution[r][c] != 'T':
return False, f"Solution changed puzzle tree at row={r}, col={c}."
# Optionally, disallow new trees in puzzle 'X':
# If puzzle[r][c] == 'X' and solution[r][c] == 'T',
# you can decide how strict you want to be.
#
# Usually, in a Campsite puzzle, the trees are fixed,
# so we typically disallow adding new 'T' where puzzle was 'X'.
if puzzle[r][c] == 'X' and solution[r][c] == 'T':
return False, f"Solution introduced a new tree at row={r}, col={c}."
# 3) Check row/column counts of tents
row_counts = [0] * n
col_counts = [0] * m
for r in range(n):
for c in range(m):
if solution[r][c] == 'C':
row_counts[r] += 1
col_counts[c] += 1
for r in range(n):
if row_counts[r] != row_constraints[r]:
return False, f"Row {r} has {row_counts[r]} tents, expected {row_constraints[r]}."
for c in range(m):
if col_counts[c] != col_constraints[c]:
return False, f"Column {c} has {col_counts[c]} tents, expected {col_constraints[c]}."
# 4) Validate adjacency rules for tents
# (a) Each tent is orthogonally adjacent to at least one tree.
# (b) No two tents are adjacent in any of the 8 directions.
directions_orth = [(-1, 0), (1, 0), (0, -1), (0, 1)]
directions_diag = [(-1, -1), (-1, 1), (1, -1), (1, 1)]
directions_all = directions_orth + directions_diag
for r in range(n):
for c in range(m):
if solution[r][c] == 'C':
# (a) Ensure there's a tree in one of the orth. neighbors
has_tree_neighbor = False
for dr, dc in directions_orth:
rr, cc = r + dr, c + dc
if 0 <= rr < n and 0 <= cc < m and solution[rr][cc] == 'T':
has_tree_neighbor = True
break
if not has_tree_neighbor:
return False, f"Row={r}, Col={c} tent not adjacent to any tree."
# (b) Ensure no tent in any of the 8 directions
for dr, dc in directions_all:
rr, cc = r + dr, c + dc
if 0 <= rr < n and 0 <= cc < m:
if solution[rr][cc] == 'C':
return False, f"Tents at ({r},{c}) and ({rr},{cc}) are adjacent."
# If all checks pass
return True, "Valid solution."
if __name__ == "__main__":
puzzle = [
['X','X','X','T'],
['T','X','X','X'],
['X','X','T','X']
]
row_constraints = [1, 0, 2]
col_constraints = [1, 1, 0, 1]
solution = [
['C','X','X','T'], # A tent at (0,0)
['T','X','X','X'],
['X','C','T','C'] # A tent at (2,3)
]
is_valid, msg = validate_campsite_solution(puzzle, row_constraints, col_constraints, solution)
print(is_valid, msg)