| import React, { useState, useEffect } from 'react'; | |
| const PuzzleGrid = ({ grid, clues, showSolution, onCellChange }) => { | |
| const [userAnswers, setUserAnswers] = useState({}); | |
| useEffect(() => { | |
| setUserAnswers({}); | |
| }, [grid]); | |
| const handleCellInput = (row, col, value) => { | |
| const key = `${row}-${col}`; | |
| const newAnswers = { ...userAnswers, [key]: value.toUpperCase() }; | |
| setUserAnswers(newAnswers); | |
| onCellChange && onCellChange(row, col, value); | |
| }; | |
| const getCellValue = (row, col) => { | |
| if (showSolution && !isBlackCell(row, col)) { | |
| return grid[row][col]; | |
| } | |
| const key = `${row}-${col}`; | |
| return userAnswers[key] || ''; | |
| }; | |
| const isBlackCell = (row, col) => { | |
| return grid[row][col] === '.'; | |
| }; | |
| const getCellNumber = (row, col) => { | |
| if (!clues) return null; | |
| const clue = clues.find(c => c.position.row === row && c.position.col === col); | |
| return clue ? clue.number : null; | |
| }; | |
| if (!grid || grid.length === 0) { | |
| return <div className="puzzle-grid">No puzzle loaded</div>; | |
| } | |
| const gridRows = grid.length; | |
| const gridCols = grid[0] ? grid[0].length : 0; | |
| return ( | |
| <div className="puzzle-container"> | |
| <div | |
| className="puzzle-grid" | |
| style={{ | |
| gridTemplateColumns: `repeat(${gridCols}, 35px)`, | |
| gridTemplateRows: `repeat(${gridRows}, 35px)` | |
| }} | |
| > | |
| {grid.map((row, rowIndex) => | |
| row.map((cell, colIndex) => { | |
| const cellNumber = getCellNumber(rowIndex, colIndex); | |
| const isBlack = isBlackCell(rowIndex, colIndex); | |
| // Only render cells that contain letters (not black/unused cells) | |
| if (isBlack) { | |
| return ( | |
| <div | |
| key={`${rowIndex}-${colIndex}`} | |
| className="grid-cell empty-cell" | |
| style={{ visibility: 'hidden' }} | |
| > | |
| </div> | |
| ); | |
| } | |
| return ( | |
| <div | |
| key={`${rowIndex}-${colIndex}`} | |
| className="grid-cell white-cell" | |
| > | |
| {cellNumber && <span className="cell-number">{cellNumber}</span>} | |
| <input | |
| type="text" | |
| maxLength="1" | |
| value={getCellValue(rowIndex, colIndex)} | |
| onChange={(e) => handleCellInput(rowIndex, colIndex, e.target.value)} | |
| className={`cell-input ${showSolution ? 'solution-text' : ''}`} | |
| disabled={showSolution} | |
| /> | |
| </div> | |
| ); | |
| }) | |
| )} | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| export default PuzzleGrid; |