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:
parent
33c4e2dcb7
commit
c1c5e5ca60
1 changed files with 133 additions and 115 deletions
|
|
@ -171,129 +171,147 @@ const KnightsPuzzle = ({ showSocialShare = false }: KnightsPuzzleProps) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto p-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
Knights Exchange Puzzle
|
||||
<Badge variant="outline">Classic</Badge>
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
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>
|
||||
</CardHeader>
|
||||
<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>
|
||||
<div className="max-w-4xl mx-auto p-6 space-y-6">
|
||||
{/* Green: Title and Description */}
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<h1 className="text-2xl font-bold">Knights Exchange Puzzle</h1>
|
||||
<Badge variant="outline">Classic</Badge>
|
||||
</div>
|
||||
<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.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Info Panel */}
|
||||
<div className="flex-1 space-y-4">
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-lg font-semibold">Game Status</h3>
|
||||
<div className="space-y-1 text-sm">
|
||||
<p>Moves: <span className="font-mono">{moveCount}</span></p>
|
||||
<p>Status: {isComplete ? "🎉 Solved!" : "🎯 In Progress"}</p>
|
||||
</div>
|
||||
</div>
|
||||
{/* Blue: Number of moves */}
|
||||
<div className="text-lg">
|
||||
<span className="font-semibold">Moves: </span>
|
||||
<span className="font-mono text-primary">{moveCount}</span>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-lg font-semibold">How to Play</h3>
|
||||
<ul className="text-sm space-y-1 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>
|
||||
</div>
|
||||
{/* Orange: Status (without heading) */}
|
||||
<div className="text-lg">
|
||||
<span className="font-semibold">
|
||||
{isComplete ? "🎉 Puzzle Solved!" : "🎯 In Progress"}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-lg font-semibold">Initial Position</h3>
|
||||
<div className="grid grid-cols-3 gap-1 w-24 h-24 border border-outline rounded">
|
||||
{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>
|
||||
</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"
|
||||
{/* Yellow: Main interactive with controls */}
|
||||
<Card className="bg-primary/5 border-primary/20">
|
||||
<CardContent className="pt-6">
|
||||
<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)}
|
||||
>
|
||||
@neuwirthe.bsky.social
|
||||
<ExternalLink className="w-3 h-3" />
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
{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>
|
||||
</CardContent>
|
||||
</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>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue