Refactor Knights Puzzle layout

Restructure the Knights Puzzle layout based on the provided image, including title, description, move counter, status, interactive area, initial/target positions, and game rules.
This commit is contained in:
gpt-engineer-app[bot] 2025-07-21 09:15:54 +00:00
parent 33c4e2dcb7
commit c1c5e5ca60

View file

@ -171,129 +171,147 @@ const KnightsPuzzle = ({ showSocialShare = false }: KnightsPuzzleProps) => {
}; };
return ( return (
<div className="max-w-4xl mx-auto p-6"> <div className="max-w-4xl mx-auto p-6 space-y-6">
<Card> {/* Green: Title and Description */}
<CardHeader> <div className="space-y-2">
<CardTitle className="flex items-center gap-2"> <div className="flex items-center gap-2">
Knights Exchange Puzzle <h1 className="text-2xl font-bold">Knights Exchange Puzzle</h1>
<Badge variant="outline">Classic</Badge> <Badge variant="outline">Classic</Badge>
</CardTitle> </div>
<CardDescription> <p className="text-muted-foreground">
Can the black and white knights swap places using legal chess moves? Move knights by clicking on them, then clicking on a valid destination. Can the black and white knights swap places using legal chess moves? Move knights by clicking on them, then clicking on a valid destination.
</CardDescription> </p>
</CardHeader> </div>
<CardContent>
<div className="flex flex-col lg:flex-row gap-8">
{/* Game Board */}
<div className="flex flex-col items-center gap-4">
<div className="grid grid-cols-3 gap-1 border-2 border-outline rounded-lg p-4 bg-background">
{board.map((row, rowIndex) =>
row.map((piece, colIndex) => (
<div
key={`${rowIndex}-${colIndex}`}
className={getSquareClass(rowIndex, colIndex)}
onClick={() => handleSquareClick(rowIndex, colIndex)}
>
{renderPiece(piece)}
</div>
))
)}
</div>
{/* Controls */}
<div className="flex gap-2">
<Button onClick={resetPuzzle} variant="outline" size="sm">
<RefreshCw className="w-4 h-4 mr-2" />
Reset
</Button>
<Button
onClick={undoLastMove}
variant="outline"
size="sm"
disabled={moveHistory.length === 0}
>
<RotateCcw className="w-4 h-4 mr-2" />
Undo
</Button>
</div>
</div>
{/* Info Panel */} {/* Blue: Number of moves */}
<div className="flex-1 space-y-4"> <div className="text-lg">
<div className="space-y-2"> <span className="font-semibold">Moves: </span>
<h3 className="text-lg font-semibold">Game Status</h3> <span className="font-mono text-primary">{moveCount}</span>
<div className="space-y-1 text-sm"> </div>
<p>Moves: <span className="font-mono">{moveCount}</span></p>
<p>Status: {isComplete ? "🎉 Solved!" : "🎯 In Progress"}</p>
</div>
</div>
<div className="space-y-2"> {/* Orange: Status (without heading) */}
<h3 className="text-lg font-semibold">How to Play</h3> <div className="text-lg">
<ul className="text-sm space-y-1 text-muted-foreground"> <span className="font-semibold">
<li> Click on a knight to select it</li> {isComplete ? "🎉 Puzzle Solved!" : "🎯 In Progress"}
<li> Valid moves will be highlighted</li> </span>
<li> Click on a highlighted square to move</li> </div>
<li> Goal: Swap white and black knights</li>
<li> Knights move in an L-shape (like in chess)</li>
</ul>
</div>
<div className="space-y-2"> {/* Yellow: Main interactive with controls */}
<h3 className="text-lg font-semibold">Initial Position</h3> <Card className="bg-primary/5 border-primary/20">
<div className="grid grid-cols-3 gap-1 w-24 h-24 border border-outline rounded"> <CardContent className="pt-6">
{initialBoard.map((row, rowIndex) => <div className="flex flex-col items-center gap-4">
row.map((piece, colIndex) => ( <div className="grid grid-cols-3 gap-1 border-2 border-outline rounded-lg p-4 bg-background">
<div {board.map((row, rowIndex) =>
key={`init-${rowIndex}-${colIndex}`} row.map((piece, colIndex) => (
className={`flex items-center justify-center text-xs ${ <div
(rowIndex + colIndex) % 2 === 0 ? "bg-surface" : "bg-surface-variant" key={`${rowIndex}-${colIndex}`}
}`} className={getSquareClass(rowIndex, colIndex)}
> onClick={() => handleSquareClick(rowIndex, colIndex)}
{piece === 'white' ? '♘' : piece === 'black' ? '♞' : ''}
</div>
))
)}
</div>
</div>
<div className="space-y-2">
<h3 className="text-lg font-semibold">Target Position</h3>
<div className="grid grid-cols-3 gap-1 w-24 h-24 border border-outline rounded">
{targetBoard.map((row, rowIndex) =>
row.map((piece, colIndex) => (
<div
key={`target-${rowIndex}-${colIndex}`}
className={`flex items-center justify-center text-xs ${
(rowIndex + colIndex) % 2 === 0 ? "bg-surface" : "bg-surface-variant"
}`}
>
{piece === 'white' ? '♘' : piece === 'black' ? '♞' : ''}
</div>
))
)}
</div>
</div>
{/* Attribution */}
<div className="pt-4 border-t border-outline">
<p className="text-xs text-muted-foreground">
Puzzle source:{" "}
<a
href="https://bsky.app/profile/neuwirthe.bsky.social/post/3luhmc7gilc2x"
target="_blank"
rel="noopener noreferrer"
className="text-accent hover:underline inline-flex items-center gap-1"
> >
@neuwirthe.bsky.social {renderPiece(piece)}
<ExternalLink className="w-3 h-3" /> </div>
</a> ))
</p> )}
</div> </div>
{/* Controls */}
<div className="flex gap-2">
<Button onClick={resetPuzzle} variant="outline" size="sm">
<RefreshCw className="w-4 h-4 mr-2" />
Reset
</Button>
<Button
onClick={undoLastMove}
variant="outline"
size="sm"
disabled={moveHistory.length === 0}
>
<RotateCcw className="w-4 h-4 mr-2" />
Undo
</Button>
</div> </div>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
{/* Purple: Initial and Target positions side by side */}
<div className="grid grid-cols-2 gap-6">
<Card className="bg-secondary/20 border-secondary">
<CardHeader className="pb-3">
<CardTitle className="text-lg">Initial Position</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-3 gap-1 w-24 h-24 border border-outline rounded mx-auto">
{initialBoard.map((row, rowIndex) =>
row.map((piece, colIndex) => (
<div
key={`init-${rowIndex}-${colIndex}`}
className={`flex items-center justify-center text-xs ${
(rowIndex + colIndex) % 2 === 0 ? "bg-surface" : "bg-surface-variant"
}`}
>
{piece === 'white' ? '♘' : piece === 'black' ? '♞' : ''}
</div>
))
)}
</div>
</CardContent>
</Card>
<Card className="bg-secondary/20 border-secondary">
<CardHeader className="pb-3">
<CardTitle className="text-lg">Target Position</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-3 gap-1 w-24 h-24 border border-outline rounded mx-auto">
{targetBoard.map((row, rowIndex) =>
row.map((piece, colIndex) => (
<div
key={`target-${rowIndex}-${colIndex}`}
className={`flex items-center justify-center text-xs ${
(rowIndex + colIndex) % 2 === 0 ? "bg-surface" : "bg-surface-variant"
}`}
>
{piece === 'white' ? '♘' : piece === 'black' ? '♞' : ''}
</div>
))
)}
</div>
</CardContent>
</Card>
</div>
{/* Red: Game rules */}
<Card className="bg-destructive/5 border-destructive/20">
<CardHeader className="pb-3">
<CardTitle className="text-lg">How to Play</CardTitle>
</CardHeader>
<CardContent>
<ul className="space-y-1 text-sm text-muted-foreground">
<li> Click on a knight to select it</li>
<li> Valid moves will be highlighted</li>
<li> Click on a highlighted square to move</li>
<li> Goal: Swap white and black knights</li>
<li> Knights move in an L-shape (like in chess)</li>
</ul>
</CardContent>
</Card>
{/* Attribution */}
<div className="pt-4 border-t border-outline">
<p className="text-xs text-muted-foreground">
Puzzle source:{" "}
<a
href="https://bsky.app/profile/neuwirthe.bsky.social/post/3luhmc7gilc2x"
target="_blank"
rel="noopener noreferrer"
className="text-accent hover:underline inline-flex items-center gap-1"
>
@neuwirthe.bsky.social
<ExternalLink className="w-3 h-3" />
</a>
</p>
</div>
</div> </div>
); );
}; };