Refactor parity bits game
- Changed parity indicators to display the count of black cells instead of "odd" or "even". - Made yellow highlights translucent to allow visibility of underlying black cells. - Added a "Random Start" option to initialize the grid with a random subset of black cells.
This commit is contained in:
parent
6813e73b97
commit
5c407b8b7f
1 changed files with 68 additions and 10 deletions
|
|
@ -27,6 +27,8 @@ const ParityBitsGame = ({ showSocialShare = true }: ParityBitsGameProps) => {
|
||||||
showColParity: boolean;
|
showColParity: boolean;
|
||||||
rowParities: boolean[];
|
rowParities: boolean[];
|
||||||
colParities: boolean[];
|
colParities: boolean[];
|
||||||
|
rowCounts: number[];
|
||||||
|
colCounts: number[];
|
||||||
}>({
|
}>({
|
||||||
isAnimating: false,
|
isAnimating: false,
|
||||||
currentRow: -1,
|
currentRow: -1,
|
||||||
|
|
@ -34,7 +36,9 @@ const ParityBitsGame = ({ showSocialShare = true }: ParityBitsGameProps) => {
|
||||||
showRowParity: false,
|
showRowParity: false,
|
||||||
showColParity: false,
|
showColParity: false,
|
||||||
rowParities: [],
|
rowParities: [],
|
||||||
colParities: []
|
colParities: [],
|
||||||
|
rowCounts: [],
|
||||||
|
colCounts: []
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reset game when grid size changes
|
// Reset game when grid size changes
|
||||||
|
|
@ -113,17 +117,23 @@ const ParityBitsGame = ({ showSocialShare = true }: ParityBitsGameProps) => {
|
||||||
// Calculate all parities first
|
// Calculate all parities first
|
||||||
const rowParities: boolean[] = [];
|
const rowParities: boolean[] = [];
|
||||||
const colParities: boolean[] = [];
|
const colParities: boolean[] = [];
|
||||||
|
const rowCounts: number[] = [];
|
||||||
|
const colCounts: number[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < gridSize; i++) {
|
for (let i = 0; i < gridSize; i++) {
|
||||||
const rowBits = parityGrid[i].slice(0, gridSize);
|
const rowBits = parityGrid[i].slice(0, gridSize);
|
||||||
|
const rowCount = rowBits.filter(bit => bit).length;
|
||||||
const expectedParity = calculateParity(rowBits);
|
const expectedParity = calculateParity(rowBits);
|
||||||
rowParities[i] = expectedParity !== parityGrid[i][gridSize];
|
rowParities[i] = expectedParity !== parityGrid[i][gridSize];
|
||||||
|
rowCounts[i] = rowCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let j = 0; j < gridSize; j++) {
|
for (let j = 0; j < gridSize; j++) {
|
||||||
const colBits = parityGrid.slice(0, gridSize).map(row => row[j]);
|
const colBits = parityGrid.slice(0, gridSize).map(row => row[j]);
|
||||||
|
const colCount = colBits.filter(bit => bit).length;
|
||||||
const expectedParity = calculateParity(colBits);
|
const expectedParity = calculateParity(colBits);
|
||||||
colParities[j] = expectedParity !== parityGrid[gridSize][j];
|
colParities[j] = expectedParity !== parityGrid[gridSize][j];
|
||||||
|
colCounts[j] = colCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
setAnimationState({
|
setAnimationState({
|
||||||
|
|
@ -133,7 +143,9 @@ const ParityBitsGame = ({ showSocialShare = true }: ParityBitsGameProps) => {
|
||||||
showRowParity: false,
|
showRowParity: false,
|
||||||
showColParity: false,
|
showColParity: false,
|
||||||
rowParities,
|
rowParities,
|
||||||
colParities
|
colParities,
|
||||||
|
rowCounts,
|
||||||
|
colCounts
|
||||||
});
|
});
|
||||||
|
|
||||||
// Animate through rows
|
// Animate through rows
|
||||||
|
|
@ -171,13 +183,45 @@ const ParityBitsGame = ({ showSocialShare = true }: ParityBitsGameProps) => {
|
||||||
showRowParity: false,
|
showRowParity: false,
|
||||||
showColParity: false,
|
showColParity: false,
|
||||||
rowParities: [],
|
rowParities: [],
|
||||||
colParities: []
|
colParities: [],
|
||||||
|
rowCounts: [],
|
||||||
|
colCounts: []
|
||||||
});
|
});
|
||||||
|
|
||||||
setPhase('detect');
|
setPhase('detect');
|
||||||
};
|
};
|
||||||
|
|
||||||
// Reset the game
|
// Random start - fill random cells
|
||||||
|
const randomStart = () => {
|
||||||
|
if (phase !== 'setup') return;
|
||||||
|
|
||||||
|
const newGrid = Array(gridSize).fill(null).map(() => Array(gridSize).fill(false));
|
||||||
|
|
||||||
|
// Fill about 30-50% of cells randomly
|
||||||
|
const fillPercentage = 0.3 + Math.random() * 0.2; // 30-50%
|
||||||
|
const totalCells = gridSize * gridSize;
|
||||||
|
const cellsToFill = Math.floor(totalCells * fillPercentage);
|
||||||
|
|
||||||
|
const positions: {row: number, col: number}[] = [];
|
||||||
|
for (let i = 0; i < gridSize; i++) {
|
||||||
|
for (let j = 0; j < gridSize; j++) {
|
||||||
|
positions.push({row: i, col: j});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shuffle and take first cellsToFill positions
|
||||||
|
for (let i = positions.length - 1; i > 0; i--) {
|
||||||
|
const j = Math.floor(Math.random() * (i + 1));
|
||||||
|
[positions[i], positions[j]] = [positions[j], positions[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < cellsToFill; i++) {
|
||||||
|
const {row, col} = positions[i];
|
||||||
|
newGrid[row][col] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
setGrid(newGrid);
|
||||||
|
};
|
||||||
const resetGame = () => {
|
const resetGame = () => {
|
||||||
setGrid(Array(gridSize).fill(null).map(() => Array(gridSize).fill(false)));
|
setGrid(Array(gridSize).fill(null).map(() => Array(gridSize).fill(false)));
|
||||||
setParityBitsAdded(false);
|
setParityBitsAdded(false);
|
||||||
|
|
@ -192,7 +236,9 @@ const ParityBitsGame = ({ showSocialShare = true }: ParityBitsGameProps) => {
|
||||||
showRowParity: false,
|
showRowParity: false,
|
||||||
showColParity: false,
|
showColParity: false,
|
||||||
rowParities: [],
|
rowParities: [],
|
||||||
colParities: []
|
colParities: [],
|
||||||
|
rowCounts: [],
|
||||||
|
colCounts: []
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -222,7 +268,7 @@ const ParityBitsGame = ({ showSocialShare = true }: ParityBitsGameProps) => {
|
||||||
${currentGrid[row]?.[col] ? 'bg-foreground' : 'bg-background'}
|
${currentGrid[row]?.[col] ? 'bg-foreground' : 'bg-background'}
|
||||||
${isParityCell ? 'border-primary' : 'border-foreground'}
|
${isParityCell ? 'border-primary' : 'border-foreground'}
|
||||||
${isError ? 'ring-4 ring-green-500 bg-green-500/20' : ''}
|
${isError ? 'ring-4 ring-green-500 bg-green-500/20' : ''}
|
||||||
${shouldHighlightForAnimation ? 'ring-4 ring-yellow-400 bg-yellow-400/30' : ''}
|
${shouldHighlightForAnimation ? 'ring-2 ring-yellow-400 bg-yellow-400/15' : ''}
|
||||||
${phase === 'setup' && !isParityCell ? 'hover:bg-accent cursor-pointer' : ''}
|
${phase === 'setup' && !isParityCell ? 'hover:bg-accent cursor-pointer' : ''}
|
||||||
${phase === 'parity' ? 'hover:bg-accent cursor-pointer' : ''}
|
${phase === 'parity' ? 'hover:bg-accent cursor-pointer' : ''}
|
||||||
`}
|
`}
|
||||||
|
|
@ -242,12 +288,13 @@ const ParityBitsGame = ({ showSocialShare = true }: ParityBitsGameProps) => {
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
{Array(gridSize).fill(null).map((_, row) => {
|
{Array(gridSize).fill(null).map((_, row) => {
|
||||||
const hasOddParity = animationState.rowParities[row];
|
const hasOddParity = animationState.rowParities[row];
|
||||||
|
const count = animationState.rowCounts[row];
|
||||||
const showLabel = row === animationState.currentRow;
|
const showLabel = row === animationState.currentRow;
|
||||||
return (
|
return (
|
||||||
<div key={`row-${row}`} className="w-12 h-12 flex items-center justify-center">
|
<div key={`row-${row}`} className="w-12 h-12 flex items-center justify-center">
|
||||||
{showLabel && (
|
{showLabel && (
|
||||||
<span className={`text-xs font-medium ${hasOddParity ? 'text-red-500' : 'text-foreground'}`}>
|
<span className={`text-xs font-medium ${hasOddParity ? 'text-red-500' : 'text-foreground'}`}>
|
||||||
{hasOddParity ? 'odd' : 'even'}
|
{count}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -260,10 +307,11 @@ const ParityBitsGame = ({ showSocialShare = true }: ParityBitsGameProps) => {
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
{Array(gridSize).fill(null).map((_, row) => {
|
{Array(gridSize).fill(null).map((_, row) => {
|
||||||
const hasOddParity = animationState.rowParities[row];
|
const hasOddParity = animationState.rowParities[row];
|
||||||
|
const count = animationState.rowCounts[row];
|
||||||
return (
|
return (
|
||||||
<div key={`row-${row}`} className="w-12 h-12 flex items-center justify-center">
|
<div key={`row-${row}`} className="w-12 h-12 flex items-center justify-center">
|
||||||
<span className={`text-xs font-medium ${hasOddParity ? 'text-red-500' : 'text-foreground'}`}>
|
<span className={`text-xs font-medium ${hasOddParity ? 'text-red-500' : 'text-foreground'}`}>
|
||||||
{hasOddParity ? 'odd' : 'even'}
|
{count}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -278,12 +326,13 @@ const ParityBitsGame = ({ showSocialShare = true }: ParityBitsGameProps) => {
|
||||||
<div className="flex gap-1">
|
<div className="flex gap-1">
|
||||||
{Array(gridSize).fill(null).map((_, col) => {
|
{Array(gridSize).fill(null).map((_, col) => {
|
||||||
const hasOddParity = animationState.colParities[col];
|
const hasOddParity = animationState.colParities[col];
|
||||||
|
const count = animationState.colCounts[col];
|
||||||
const showLabel = col === animationState.currentCol;
|
const showLabel = col === animationState.currentCol;
|
||||||
return (
|
return (
|
||||||
<div key={`col-${col}`} className="w-12 h-6 flex items-center justify-center">
|
<div key={`col-${col}`} className="w-12 h-6 flex items-center justify-center">
|
||||||
{showLabel && (
|
{showLabel && (
|
||||||
<span className={`text-xs font-medium ${hasOddParity ? 'text-red-500' : 'text-foreground'}`}>
|
<span className={`text-xs font-medium ${hasOddParity ? 'text-red-500' : 'text-foreground'}`}>
|
||||||
{hasOddParity ? 'odd' : 'even'}
|
{count}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -296,10 +345,11 @@ const ParityBitsGame = ({ showSocialShare = true }: ParityBitsGameProps) => {
|
||||||
<div className="flex gap-1">
|
<div className="flex gap-1">
|
||||||
{Array(gridSize).fill(null).map((_, col) => {
|
{Array(gridSize).fill(null).map((_, col) => {
|
||||||
const hasOddParity = animationState.colParities[col];
|
const hasOddParity = animationState.colParities[col];
|
||||||
|
const count = animationState.colCounts[col];
|
||||||
return (
|
return (
|
||||||
<div key={`col-${col}`} className="w-12 h-6 flex items-center justify-center">
|
<div key={`col-${col}`} className="w-12 h-6 flex items-center justify-center">
|
||||||
<span className={`text-xs font-medium ${hasOddParity ? 'text-red-500' : 'text-foreground'}`}>
|
<span className={`text-xs font-medium ${hasOddParity ? 'text-red-500' : 'text-foreground'}`}>
|
||||||
{hasOddParity ? 'odd' : 'even'}
|
{count}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -358,6 +408,14 @@ const ParityBitsGame = ({ showSocialShare = true }: ParityBitsGameProps) => {
|
||||||
Add Parity Bits
|
Add Parity Bits
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
onClick={randomStart}
|
||||||
|
disabled={phase !== 'setup'}
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
|
Random Start
|
||||||
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
onClick={identifyFlip}
|
onClick={identifyFlip}
|
||||||
disabled={phase !== 'flip' || animationState.isAnimating}
|
disabled={phase !== 'flip' || animationState.isAnimating}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue