#!/usr/bin/env python3 """ Test to identify and fix word boundary issues causing unwanted prefixes/suffixes. """ import sys from pathlib import Path # Add project root to path project_root = Path(__file__).parent.parent # Go up from test-integration to backend-py sys.path.insert(0, str(project_root)) from src.services.crossword_generator_fixed import CrosswordGeneratorFixed def test_word_boundary_violations(): """Test for word boundary violations that create unwanted prefixes/suffixes.""" generator = CrosswordGeneratorFixed(vector_service=None) # Test case 1: Simple word placement with boundary checking print("๐Ÿงช Testing word boundary violations...\n") # Create a grid and place a word grid = [["." for _ in range(10)] for _ in range(10)] # Place "MACHINE" horizontally at row 5, col 2 placed_words = [] # First, place MACHINE if generator._can_place_word(grid, "MACHINE", 5, 2, "horizontal"): original_state = generator._place_word(grid, "MACHINE", 5, 2, "horizontal") placed_words.append({ "word": "MACHINE", "row": 5, "col": 2, "direction": "horizontal", "number": 1 }) print("โœ… Placed MACHINE horizontally") print_grid_section(grid, 4, 7, 0, 10) else: print("โŒ Cannot place MACHINE") return False # Now try to place a word that might create boundary violations # Try placing "CAR" vertically intersecting with "A" in MACHINE test_words = [ ("CAR", 3, 4, "vertical"), # Should intersect at 'A' in MACHINE ("ACE", 4, 3, "vertical"), # Should intersect at 'C' in MACHINE ("RIG", 6, 7, "vertical"), # Should intersect at 'I' in MACHINE ] for word, row, col, direction in test_words: print(f"\n๐Ÿ” Testing placement of '{word}' at ({row}, {col}) {direction}") if generator._can_place_word(grid, word, row, col, direction): # Check if this placement would create boundary issues print(f"โœ… Can place '{word}' - checking for boundary violations...") # Simulate the placement test_grid = [row[:] for row in grid] # Deep copy test_original = generator._place_word(test_grid, word, row, col, direction) print_grid_section(test_grid, 2, 9, 0, 10) # Check if any unintended words are formed violations = check_word_boundary_violations(test_grid, word, row, col, direction, placed_words) if violations: print(f"โŒ Boundary violations detected: {violations}") else: print(f"โœ… No boundary violations for '{word}'") # Restore grid generator._remove_word(test_grid, test_original) else: print(f"โŒ Cannot place '{word}' at ({row}, {col}) {direction}") print("\n" + "="*50) return True def print_grid_section(grid, start_row, end_row, start_col, end_col): """Print a section of the grid for visualization.""" print("Grid section:") for r in range(start_row, min(end_row, len(grid))): row_str = "" for c in range(start_col, min(end_col, len(grid[0]))): if grid[r][c] == ".": row_str += ". " else: row_str += f"{grid[r][c]} " print(f"Row {r:2d}: {row_str}") print() def check_word_boundary_violations(grid, new_word, row, col, direction, existing_words): """Check if placing a word creates unintended word extensions.""" violations = [] # Check the immediate boundaries of the new word if direction == "horizontal": # Check before the word if col > 0 and grid[row][col - 1] != ".": violations.append(f"Unwanted prefix: letter '{grid[row][col - 1]}' before '{new_word}'") # Check after the word if col + len(new_word) < len(grid[0]) and grid[row][col + len(new_word)] != ".": violations.append(f"Unwanted suffix: letter '{grid[row][col + len(new_word)]}' after '{new_word}'") # Check perpendicular extensions at each letter for i, letter in enumerate(new_word): letter_col = col + i # Check above and below each letter for unintended words above_letters = [] below_letters = [] # Collect letters above r = row - 1 while r >= 0 and grid[r][letter_col] != ".": above_letters.insert(0, grid[r][letter_col]) r -= 1 # Collect letters below r = row + 1 while r < len(grid) and grid[r][letter_col] != ".": below_letters.append(grid[r][letter_col]) r += 1 # Check if this forms an unintended word if above_letters or below_letters: full_vertical_word = "".join(above_letters) + letter + "".join(below_letters) if len(full_vertical_word) > 1: # Check if this is an intended word from existing placements intended = False for existing in existing_words: if (existing["direction"] == "vertical" and existing["col"] == letter_col and existing["word"] == full_vertical_word): intended = True break if not intended and len(full_vertical_word) > 1: violations.append(f"Unintended vertical word '{full_vertical_word}' at column {letter_col}") else: # vertical # Check before the word (above) if row > 0 and grid[row - 1][col] != ".": violations.append(f"Unwanted prefix: letter '{grid[row - 1][col]}' above '{new_word}'") # Check after the word (below) if row + len(new_word) < len(grid) and grid[row + len(new_word)][col] != ".": violations.append(f"Unwanted suffix: letter '{grid[row + len(new_word)][col]}' below '{new_word}'") # Check perpendicular extensions at each letter for i, letter in enumerate(new_word): letter_row = row + i # Collect letters to the left and right left_letters = [] right_letters = [] # Collect letters to the left c = col - 1 while c >= 0 and grid[letter_row][c] != ".": left_letters.insert(0, grid[letter_row][c]) c -= 1 # Collect letters to the right c = col + 1 while c < len(grid[0]) and grid[letter_row][c] != ".": right_letters.append(grid[letter_row][c]) c += 1 # Check if this forms an unintended word if left_letters or right_letters: full_horizontal_word = "".join(left_letters) + letter + "".join(right_letters) if len(full_horizontal_word) > 1: # Check if this is an intended word from existing placements intended = False for existing in existing_words: if (existing["direction"] == "horizontal" and existing["row"] == letter_row and existing["word"] == full_horizontal_word): intended = True break if not intended and len(full_horizontal_word) > 1: violations.append(f"Unintended horizontal word '{full_horizontal_word}' at row {letter_row}") return violations def test_enhanced_boundary_checking(): """Test enhanced boundary checking logic.""" print("๐Ÿงช Testing enhanced boundary checking logic...\n") generator = CrosswordGeneratorFixed(vector_service=None) # Test problematic scenario from the images # Create a scenario where MACHINE might get extended to MACHINERY grid = [["." for _ in range(12)] for _ in range(12)] # Place MACHINE first generator._place_word(grid, "MACHINE", 5, 2, "horizontal") placed_words = [{ "word": "MACHINE", "row": 5, "col": 2, "direction": "horizontal", "number": 1 }] print("Initial grid with MACHINE:") print_grid_section(grid, 4, 7, 0, 12) # Now try to place words that might create the "RY" suffix issue # Place "Y" somewhere that might extend MACHINE problem_placements = [ ("RYOT", 5, 9, "horizontal"), # This would make MACHINE -> MACHINERYOT ("CAR", 3, 8, "vertical"), # This might create unwanted extensions ] for word, row, col, direction in problem_placements: print(f"\n๐Ÿ” Testing problematic placement: '{word}' at ({row}, {col}) {direction}") # Check current can_place_word logic can_place = generator._can_place_word(grid, word, row, col, direction) print(f"Current _can_place_word result: {can_place}") if can_place: # Show what would happen test_grid = [row[:] for row in grid] generator._place_word(test_grid, word, row, col, direction) print("Result grid:") print_grid_section(test_grid, 3, 8, 0, 12) # Check for violations manually violations = check_word_boundary_violations(test_grid, word, row, col, direction, placed_words) if violations: print(f"โŒ This placement creates violations: {violations}") else: print("โœ… No violations detected") if __name__ == "__main__": print("๐Ÿ” Testing Word Boundary Issues\n") test_word_boundary_violations() print("\n" + "="*60 + "\n") test_enhanced_boundary_checking() print("\n๐ŸŽฏ Analysis complete. Check output for boundary violation patterns.")