diff --git a/src/components/KnightsPuzzle.tsx b/src/components/KnightsPuzzle.tsx index b7f528b..f22768c 100644 --- a/src/components/KnightsPuzzle.tsx +++ b/src/components/KnightsPuzzle.tsx @@ -6,32 +6,25 @@ import { RefreshCw, RotateCcw, ExternalLink, ArrowLeft } from "lucide-react"; import { toast } from "sonner"; import SocialShare from "@/components/SocialShare"; import { useSearchParams, useNavigate } from "react-router-dom"; - type Piece = 'white' | 'black' | null; -type Position = { row: number; col: number }; - +type Position = { + row: number; + col: number; +}; interface KnightsPuzzleProps { showSocialShare?: boolean; } - -const KnightsPuzzle = ({ showSocialShare = false }: KnightsPuzzleProps) => { +const KnightsPuzzle = ({ + showSocialShare = false +}: KnightsPuzzleProps) => { const [searchParams] = useSearchParams(); const navigate = useNavigate(); const isFromPuzzles = searchParams.get('from') === 'puzzles'; // Initial state: white knights at top corners, black knights at bottom corners - const initialBoard: Piece[][] = [ - ['white', null, 'white'], - [null, null, null], - ['black', null, 'black'] - ]; + const initialBoard: Piece[][] = [['white', null, 'white'], [null, null, null], ['black', null, 'black']]; // Target state: black knights at top corners, white knights at bottom corners - const targetBoard: Piece[][] = [ - ['black', null, 'black'], - [null, null, null], - ['white', null, 'white'] - ]; - + const targetBoard: Piece[][] = [['black', null, 'black'], [null, null, null], ['white', null, 'white']]; const [board, setBoard] = useState(initialBoard); const [selectedSquare, setSelectedSquare] = useState(null); const [moveCount, setMoveCount] = useState(0); @@ -39,37 +32,29 @@ const KnightsPuzzle = ({ showSocialShare = false }: KnightsPuzzleProps) => { const [moveHistory, setMoveHistory] = useState([]); // Knight move offsets - const knightMoves = [ - [-2, -1], [-2, 1], [-1, -2], [-1, 2], - [1, -2], [1, 2], [2, -1], [2, 1] - ]; - + const knightMoves = [[-2, -1], [-2, 1], [-1, -2], [-1, 2], [1, -2], [1, 2], [2, -1], [2, 1]]; const isValidPosition = (row: number, col: number): boolean => { return row >= 0 && row < 3 && col >= 0 && col < 3; }; - const getValidMoves = (fromRow: number, fromCol: number): Position[] => { const validMoves: Position[] = []; - knightMoves.forEach(([dRow, dCol]) => { const newRow = fromRow + dRow; const newCol = fromCol + dCol; - if (isValidPosition(newRow, newCol) && board[newRow][newCol] === null) { - validMoves.push({ row: newRow, col: newCol }); + validMoves.push({ + row: newRow, + col: newCol + }); } }); - return validMoves; }; - const isValidMove = (from: Position, to: Position): boolean => { const rowDiff = Math.abs(from.row - to.row); const colDiff = Math.abs(from.col - to.col); - - return (rowDiff === 2 && colDiff === 1) || (rowDiff === 1 && colDiff === 2); + return rowDiff === 2 && colDiff === 1 || rowDiff === 1 && colDiff === 2; }; - const checkWinCondition = (currentBoard: Piece[][]): boolean => { for (let row = 0; row < 3; row++) { for (let col = 0; col < 3; col++) { @@ -80,32 +65,32 @@ const KnightsPuzzle = ({ showSocialShare = false }: KnightsPuzzleProps) => { } return true; }; - const handleSquareClick = (row: number, col: number) => { const piece = board[row][col]; - if (selectedSquare) { const from = selectedSquare; - const to = { row, col }; - + const to = { + row, + col + }; + // If clicking on the same square, deselect if (from.row === to.row && from.col === to.col) { setSelectedSquare(null); return; } - + // If clicking on an empty square and it's a valid knight move if (piece === null && isValidMove(from, to)) { const newBoard = board.map(r => [...r]); const movingPiece = newBoard[from.row][from.col]; newBoard[from.row][from.col] = null; newBoard[to.row][to.col] = movingPiece; - setBoard(newBoard); setMoveCount(moveCount + 1); setMoveHistory([...moveHistory, [from, to]]); setSelectedSquare(null); - + // Check win condition if (checkWinCondition(newBoard)) { setIsComplete(true); @@ -113,16 +98,21 @@ const KnightsPuzzle = ({ showSocialShare = false }: KnightsPuzzleProps) => { } } else if (piece !== null) { // Select a different piece - setSelectedSquare({ row, col }); + setSelectedSquare({ + row, + col + }); } else { setSelectedSquare(null); } } else if (piece !== null) { // Select a piece - setSelectedSquare({ row, col }); + setSelectedSquare({ + row, + col + }); } }; - const resetPuzzle = () => { setBoard(initialBoard); setSelectedSquare(null); @@ -130,42 +120,33 @@ const KnightsPuzzle = ({ showSocialShare = false }: KnightsPuzzleProps) => { setIsComplete(false); setMoveHistory([]); }; - const undoLastMove = () => { if (moveHistory.length === 0) return; - const lastMove = moveHistory[moveHistory.length - 1]; const [from, to] = lastMove; - const newBoard = board.map(r => [...r]); const movingPiece = newBoard[to.row][to.col]; newBoard[to.row][to.col] = null; newBoard[from.row][from.col] = movingPiece; - setBoard(newBoard); setMoveCount(moveCount - 1); setMoveHistory(moveHistory.slice(0, -1)); setSelectedSquare(null); setIsComplete(false); }; - const getSquareClass = (row: number, col: number): string => { const baseClass = "w-16 h-16 border-2 border-outline flex items-center justify-center cursor-pointer transition-all duration-200"; const isSelected = selectedSquare?.row === row && selectedSquare?.col === col; const validMoves = selectedSquare ? getValidMoves(selectedSquare.row, selectedSquare.col) : []; const isValidMoveTarget = validMoves.some(move => move.row === row && move.col === col); - let bgClass = (row + col) % 2 === 0 ? "bg-surface" : "bg-surface-variant"; - if (isSelected) { bgClass = "bg-accent"; } else if (isValidMoveTarget) { bgClass = "bg-accent/30 ring-2 ring-accent"; } - return `${baseClass} ${bgClass}`; }; - const renderPiece = (piece: Piece) => { if (piece === 'white') { return ; @@ -174,21 +155,14 @@ const KnightsPuzzle = ({ showSocialShare = false }: KnightsPuzzleProps) => { } return null; }; - - return ( -
+ return
{/* Back to Puzzles button - only show when coming from puzzles */} - {isFromPuzzles && ( -
- -
- )} +
} {/* Green: Title and Description - Centered */}
@@ -214,17 +188,9 @@ const KnightsPuzzle = ({ showSocialShare = false }: KnightsPuzzleProps) => {
- {board.map((row, rowIndex) => - row.map((piece, colIndex) => ( -
handleSquareClick(rowIndex, colIndex)} - > + {board.map((row, rowIndex) => row.map((piece, colIndex) =>
handleSquareClick(rowIndex, colIndex)}> {renderPiece(piece)} -
- )) - )} +
))}
{/* Controls */} @@ -233,12 +199,7 @@ const KnightsPuzzle = ({ showSocialShare = false }: KnightsPuzzleProps) => { Reset - @@ -249,49 +210,9 @@ const KnightsPuzzle = ({ showSocialShare = false }: KnightsPuzzleProps) => { {/* Purple: Initial and Target positions side by side */}
- -
- Initial -
- -
- {initialBoard.map((row, rowIndex) => - row.map((piece, colIndex) => ( -
- {piece === 'white' ? '♘' : piece === 'black' ? '♞' : ''} -
- )) - )} -
-
-
+ - - - Target Position - - -
- {targetBoard.map((row, rowIndex) => - row.map((piece, colIndex) => ( -
- {piece === 'white' ? '♘' : piece === 'black' ? '♞' : ''} -
- )) - )} -
-
-
+
{/* Red: Game rules */} @@ -314,12 +235,7 @@ const KnightsPuzzle = ({ showSocialShare = false }: KnightsPuzzleProps) => {

Puzzle source:{" "} - + @neuwirthe.bsky.social @@ -327,14 +243,7 @@ const KnightsPuzzle = ({ showSocialShare = false }: KnightsPuzzleProps) => {

{/* Social Share Section */} - {showSocialShare && ( - - )} -
- ); + {showSocialShare && } +
; }; - export default KnightsPuzzle; \ No newline at end of file