Refine Bulgarian Solitaire columns
Adjusted column width in Bulgarian Solitaire to be just wider than block width. Implemented sorting of columns by height (tallest to left) after simulation starts. Added visual feedback: highlighting top boxes red, animating their movement to form the last column, and then visually displaying the sorting process.
This commit is contained in:
parent
cb484c418e
commit
8944a5e485
1 changed files with 40 additions and 6 deletions
|
|
@ -21,6 +21,8 @@ const BulgarianSolitaire: React.FC<BulgarianSolitaireProps> = ({ showSocialShare
|
|||
const [draggedBox, setDraggedBox] = useState<number | null>(null);
|
||||
const [step, setStep] = useState(0);
|
||||
const [isComplete, setIsComplete] = useState(false);
|
||||
const [highlightedBoxes, setHighlightedBoxes] = useState<Set<number>>(new Set());
|
||||
const [isAnimating, setIsAnimating] = useState(false);
|
||||
|
||||
const totalBoxes = (n * (n + 1)) / 2;
|
||||
|
||||
|
|
@ -115,6 +117,18 @@ const BulgarianSolitaire: React.FC<BulgarianSolitaireProps> = ({ showSocialShare
|
|||
stepCount++;
|
||||
setStep(stepCount);
|
||||
|
||||
// Highlight top boxes that will be moved
|
||||
const topBoxes = new Set<number>();
|
||||
currentColumns.forEach(col => {
|
||||
if (col.length > 0) {
|
||||
topBoxes.add(col[col.length - 1]);
|
||||
}
|
||||
});
|
||||
|
||||
setHighlightedBoxes(topBoxes);
|
||||
setIsAnimating(true);
|
||||
await sleep(800); // Show highlighting
|
||||
|
||||
// Create new pile from non-empty columns
|
||||
const newPile: number[] = [];
|
||||
const updatedColumns = currentColumns.map(col => {
|
||||
|
|
@ -136,7 +150,21 @@ const BulgarianSolitaire: React.FC<BulgarianSolitaireProps> = ({ showSocialShare
|
|||
break;
|
||||
}
|
||||
|
||||
currentColumns = updatedColumns;
|
||||
// Clear highlighting and animation
|
||||
setHighlightedBoxes(new Set());
|
||||
setIsAnimating(false);
|
||||
|
||||
// Sort columns by height (tallest to left)
|
||||
const columnData = updatedColumns.map((col, index) => ({ col, originalIndex: index }))
|
||||
.filter(item => item.col.length > 0)
|
||||
.sort((a, b) => b.col.length - a.col.length);
|
||||
|
||||
const sortedColumns = Array.from({ length: updatedColumns.length }, () => []);
|
||||
columnData.forEach((item, index) => {
|
||||
sortedColumns[index] = item.col;
|
||||
});
|
||||
|
||||
currentColumns = sortedColumns;
|
||||
setColumns(currentColumns);
|
||||
|
||||
// Update box positions
|
||||
|
|
@ -149,7 +177,7 @@ const BulgarianSolitaire: React.FC<BulgarianSolitaireProps> = ({ showSocialShare
|
|||
return box;
|
||||
}));
|
||||
|
||||
await sleep(1000); // Wait 1 second between steps
|
||||
await sleep(1200); // Wait to see the sorted result
|
||||
}
|
||||
|
||||
setIsComplete(isTriangularConfiguration(currentColumns));
|
||||
|
|
@ -172,6 +200,8 @@ const BulgarianSolitaire: React.FC<BulgarianSolitaireProps> = ({ showSocialShare
|
|||
setStep(0);
|
||||
setIsComplete(false);
|
||||
setIsPlaying(false);
|
||||
setHighlightedBoxes(new Set());
|
||||
setIsAnimating(false);
|
||||
};
|
||||
|
||||
const containerBoxes = boxes.filter(box => box.columnIndex === null);
|
||||
|
|
@ -233,22 +263,26 @@ const BulgarianSolitaire: React.FC<BulgarianSolitaireProps> = ({ showSocialShare
|
|||
)}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-4 md:grid-cols-6 lg:grid-cols-8 gap-2 max-w-4xl mx-auto">
|
||||
<div className="flex justify-center gap-1 flex-wrap max-w-2xl mx-auto">
|
||||
{columns.map((column, index) => (
|
||||
<div
|
||||
key={index}
|
||||
onDragOver={handleDragOver}
|
||||
onDrop={(e) => handleDrop(e, index)}
|
||||
className="border border-muted-foreground rounded-lg min-h-[100px] p-2 bg-background/50 flex flex-col-reverse gap-1"
|
||||
className="border border-muted-foreground rounded-lg min-h-[100px] w-12 p-1 bg-background/50 flex flex-col-reverse gap-1 transition-all duration-500"
|
||||
>
|
||||
<div className="text-xs text-center text-muted-foreground mb-2">
|
||||
<div className="text-xs text-center text-muted-foreground mb-1 transform rotate-0">
|
||||
{index + 1}
|
||||
</div>
|
||||
{column.map((boxId, boxIndex) => (
|
||||
<div
|
||||
key={boxId}
|
||||
onDoubleClick={() => handleDoubleClick(boxId)}
|
||||
className="w-6 h-6 bg-primary rounded cursor-pointer hover:bg-primary/80 transition-colors flex items-center justify-center text-primary-foreground text-xs font-medium mx-auto"
|
||||
className={`w-8 h-8 rounded cursor-pointer transition-all duration-300 flex items-center justify-center text-xs font-medium mx-auto ${
|
||||
highlightedBoxes.has(boxId)
|
||||
? 'bg-red-500 text-white shadow-lg scale-110'
|
||||
: 'bg-primary text-primary-foreground hover:bg-primary/80'
|
||||
} ${isAnimating && highlightedBoxes.has(boxId) ? 'animate-pulse' : ''}`}
|
||||
title="Double-click to return to container"
|
||||
>
|
||||
{boxId + 1}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue