diff --git a/src/components/DominoRetilingPuzzle.tsx b/src/components/DominoRetilingPuzzle.tsx index a261cd1..d12d14f 100644 --- a/src/components/DominoRetilingPuzzle.tsx +++ b/src/components/DominoRetilingPuzzle.tsx @@ -2,7 +2,7 @@ import React, { useState, useCallback, useEffect } from 'react'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; -import { CheckCircle, XCircle, Info, ChevronDown, ChevronUp, RotateCcw, Shuffle, Lightbulb } from 'lucide-react'; +import { CheckCircle, ChevronDown, ChevronUp, Shuffle, Lightbulb } from 'lucide-react'; import SocialShare from '@/components/SocialShare'; interface Domino { @@ -22,6 +22,7 @@ const DominoRetilingPuzzle: React.FC = ({ showSocialS const [showInstructions, setShowInstructions] = useState(false); const [moveCount, setMoveCount] = useState(0); const [showHint, setShowHint] = useState(false); + const [hoverPlacement, setHoverPlacement] = useState<{ row: number; col: number; isHorizontal: boolean } | null>(null); const BOARD_ROWS = 8; const BOARD_COLS = 9; // 8 + 1 extra square on top row @@ -70,6 +71,7 @@ const DominoRetilingPuzzle: React.FC = ({ showSocialS setDominoes(newDominoes); setSelectedDomino(null); setMoveCount(0); + setHoverPlacement(null); }, []); useEffect(() => { @@ -99,7 +101,7 @@ const DominoRetilingPuzzle: React.FC = ({ showSocialS }; // Check if we can place a domino at a position - const canPlaceDomino = (row: number, col: number, isHorizontal: boolean, excludeDominoId: number): boolean => { + const canPlaceDomino = useCallback((row: number, col: number, isHorizontal: boolean, excludeDominoId: number): boolean => { const cell1Row = row; const cell1Col = col; const cell2Row = isHorizontal ? row : row + 1; @@ -109,35 +111,16 @@ const DominoRetilingPuzzle: React.FC = ({ showSocialS const occupied = getOccupiedCells(excludeDominoId); return !occupied.has(`${cell1Row},${cell1Col}`) && !occupied.has(`${cell2Row},${cell2Col}`); - }; - - // Get valid placements for the selected domino - const getValidPlacements = useCallback((dominoId: number): { row: number; col: number; isHorizontal: boolean }[] => { - const placements: { row: number; col: number; isHorizontal: boolean }[] = []; - - for (let row = 0; row < BOARD_ROWS; row++) { - const maxCol = row === 0 ? BOARD_COLS : 8; - for (let col = 0; col < maxCol; col++) { - // Check horizontal placement - if (canPlaceDomino(row, col, true, dominoId)) { - placements.push({ row, col, isHorizontal: true }); - } - // Check vertical placement - if (canPlaceDomino(row, col, false, dominoId)) { - placements.push({ row, col, isHorizontal: false }); - } - } - } - - return placements; }, [getOccupiedCells]); // Handle clicking on a domino const handleDominoClick = (dominoId: number) => { if (selectedDomino === dominoId) { setSelectedDomino(null); + setHoverPlacement(null); } else { setSelectedDomino(dominoId); + setHoverPlacement(null); } }; @@ -151,15 +134,35 @@ const DominoRetilingPuzzle: React.FC = ({ showSocialS : d )); setSelectedDomino(null); + setHoverPlacement(null); setMoveCount(prev => prev + 1); }; + // Handle cell hover + const handleCellHover = (row: number, col: number) => { + if (selectedDomino === null) return; + + // Check which placements are valid for this cell + const canH = canPlaceDomino(row, col, true, selectedDomino); + const canV = canPlaceDomino(row, col, false, selectedDomino); + + if (canH && canV) { + // Prefer horizontal + setHoverPlacement({ row, col, isHorizontal: true }); + } else if (canH) { + setHoverPlacement({ row, col, isHorizontal: true }); + } else if (canV) { + setHoverPlacement({ row, col, isHorizontal: false }); + } else { + setHoverPlacement(null); + } + }; + // Check if puzzle is solved (all dominoes horizontal) const isSolved = dominoes.length > 0 && dominoes.every(d => d.isHorizontal); // Get domino color based on orientation - const getDominoColor = (isHorizontal: boolean, isSelected: boolean): string => { - if (isSelected) return 'bg-amber-400 border-amber-600'; + const getDominoColor = (isHorizontal: boolean): string => { if (isHorizontal) return 'bg-emerald-500 border-emerald-700'; return 'bg-rose-400 border-rose-600'; }; @@ -167,19 +170,13 @@ const DominoRetilingPuzzle: React.FC = ({ showSocialS // Render the board const renderBoard = () => { const cells: JSX.Element[] = []; - const validPlacements = selectedDomino !== null ? getValidPlacements(selectedDomino) : []; - const occupied = getOccupiedCells(); + const occupied = getOccupiedCells(selectedDomino ?? undefined); // Render cells for (let row = 0; row < BOARD_ROWS; row++) { const maxCol = row === 0 ? BOARD_COLS : 8; for (let col = 0; col < maxCol; col++) { - const isOccupied = occupied.has(`${row},${col}`); const isExtraSquare = row === 0 && col === 8; - - // Check if this is a valid horizontal placement start - const validHorizontal = validPlacements.find(p => p.row === row && p.col === col && p.isHorizontal); - const validVertical = validPlacements.find(p => p.row === row && p.col === col && !p.isHorizontal); const cellStyle: React.CSSProperties = { position: 'absolute', @@ -194,59 +191,31 @@ const DominoRetilingPuzzle: React.FC = ({ showSocialS key={`cell-${row}-${col}`} className={`border border-border/50 ${ isExtraSquare ? 'bg-primary/20' : (row + col) % 2 === 0 ? 'bg-muted/30' : 'bg-muted/60' - }`} + } ${selectedDomino !== null ? 'cursor-pointer' : ''}`} style={cellStyle} + onMouseEnter={() => handleCellHover(row, col)} + onMouseLeave={() => setHoverPlacement(null)} + onClick={() => { + if (hoverPlacement && hoverPlacement.row === row && hoverPlacement.col === col) { + handlePlacementClick(hoverPlacement.row, hoverPlacement.col, hoverPlacement.isHorizontal); + } + }} /> ); - - // Render valid placement indicators - if (validHorizontal && !isOccupied) { - cells.push( -
handlePlacementClick(row, col, true)} - title="Place horizontally" - /> - ); - } - if (validVertical && !isOccupied) { - cells.push( -
handlePlacementClick(row, col, false)} - title="Place vertically" - /> - ); - } } } - // Render dominoes + // Render dominoes (except selected one) dominoes.forEach(d => { - const isSelected = selectedDomino === d.id; + if (d.id === selectedDomino) return; // Hide selected domino + const width = d.isHorizontal ? 96 : 46; const height = d.isHorizontal ? 46 : 96; cells.push(
= ({ showSocialS onClick={() => handleDominoClick(d.id)} >
-
+
); }); + // Render hover preview domino + if (hoverPlacement && selectedDomino !== null) { + const width = hoverPlacement.isHorizontal ? 96 : 46; + const height = hoverPlacement.isHorizontal ? 46 : 96; + + cells.push( +
+
+
+
+
+ ); + } + return cells; };