import React, { useState, useCallback } from 'react'; import { Button } from '@/components/ui/button'; import { Slider } from '@/components/ui/slider'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { RotateCcw, Info } from 'lucide-react'; interface ParityBitsGameProps { showSocialShare?: boolean; } const ParityBitsGame = ({ showSocialShare = true }: ParityBitsGameProps) => { const [gridSize, setGridSize] = useState(3); const [grid, setGrid] = useState(() => Array(gridSize).fill(null).map(() => Array(gridSize).fill(false)) ); const [parityBitsAdded, setParityBitsAdded] = useState(false); const [parityGrid, setParityGrid] = useState([]); const [flippedCell, setFlippedCell] = useState<{row: number, col: number} | null>(null); const [errorDetected, setErrorDetected] = useState<{row: number, col: number} | null>(null); const [phase, setPhase] = useState<'setup' | 'parity' | 'flip' | 'detect'>('setup'); // Reset game when grid size changes const handleGridSizeChange = useCallback((newSize: number[]) => { const size = newSize[0]; setGridSize(size); setGrid(Array(size).fill(null).map(() => Array(size).fill(false))); setParityBitsAdded(false); setParityGrid([]); setFlippedCell(null); setErrorDetected(null); setPhase('setup'); }, []); // Toggle a cell in the main grid const toggleCell = (row: number, col: number) => { if (phase !== 'setup') return; const newGrid = [...grid]; newGrid[row][col] = !newGrid[row][col]; setGrid(newGrid); }; // Calculate parity for a row or column const calculateParity = (bits: boolean[]): boolean => { return bits.filter(bit => bit).length % 2 === 1; }; // Add parity bits to create the extended grid const addParityBits = () => { const extended = Array(gridSize + 1).fill(null).map(() => Array(gridSize + 1).fill(false)); // Copy original grid for (let i = 0; i < gridSize; i++) { for (let j = 0; j < gridSize; j++) { extended[i][j] = grid[i][j]; } } // Calculate row parities for (let i = 0; i < gridSize; i++) { extended[i][gridSize] = calculateParity(grid[i]); } // Calculate column parities for (let j = 0; j < gridSize; j++) { const column = grid.map(row => row[j]); extended[gridSize][j] = calculateParity(column); } // Calculate overall parity const allBits = grid.flat(); const rowParities = Array(gridSize).fill(null).map((_, i) => calculateParity(grid[i])); extended[gridSize][gridSize] = calculateParity([...allBits, ...rowParities]); setParityGrid(extended); setParityBitsAdded(true); setPhase('parity'); }; // Flip a bit in the parity grid const flipBit = (row: number, col: number) => { if (phase !== 'parity' || row >= gridSize || col >= gridSize) return; const newGrid = [...parityGrid]; newGrid[row][col] = !newGrid[row][col]; setParityGrid(newGrid); setFlippedCell({row, col}); setPhase('flip'); }; // Identify the flipped bit using parity check const identifyFlip = () => { if (!parityBitsAdded) return; let errorRow = -1; let errorCol = -1; // Check row parities for (let i = 0; i < gridSize; i++) { const rowBits = parityGrid[i].slice(0, gridSize); const expectedParity = calculateParity(rowBits); if (expectedParity !== parityGrid[i][gridSize]) { errorRow = i; } } // Check column parities for (let j = 0; j < gridSize; j++) { const colBits = parityGrid.slice(0, gridSize).map(row => row[j]); const expectedParity = calculateParity(colBits); if (expectedParity !== parityGrid[gridSize][j]) { errorCol = j; } } if (errorRow >= 0 && errorCol >= 0) { setErrorDetected({row: errorRow, col: errorCol}); } setPhase('detect'); }; // Reset the game const resetGame = () => { setGrid(Array(gridSize).fill(null).map(() => Array(gridSize).fill(false))); setParityBitsAdded(false); setParityGrid([]); setFlippedCell(null); setErrorDetected(null); setPhase('setup'); }; const renderGrid = () => { const currentGrid = parityBitsAdded ? parityGrid : grid; const size = parityBitsAdded ? gridSize + 1 : gridSize; return (
{Array(size).fill(null).map((_, row) => Array(size).fill(null).map((_, col) => { const isParityCell = parityBitsAdded && (row === gridSize || col === gridSize); const isFlipped = flippedCell?.row === row && flippedCell?.col === col; const isError = errorDetected?.row === row && errorDetected?.col === col; const isErrorRow = errorDetected && row === errorDetected.row; const isErrorCol = errorDetected && col === errorDetected.col; return (
); }; return (
Parity Bits Error Detection {/* Instructions */} {phase === 'setup' && 'Set your grid by clicking squares to make them black. Then add parity bits.'} {phase === 'parity' && 'Parity bits added! Now flip exactly one bit in the main grid (not parity cells).'} {phase === 'flip' && 'Bit flipped! Click "Identify Flip" to see error detection in action.'} {phase === 'detect' && 'Error detected! The highlighted cell shows where the bit was flipped.'} {/* Controls */}
{/* Grid */}
{renderGrid()}
{/* Status Information */} {parityBitsAdded && (

Parity cells have colored borders. Each row and column should have an even number of black squares.

{flippedCell && (

Flipped bit at position ({flippedCell.row + 1}, {flippedCell.col + 1})

)} {errorDetected && (

Error detected at position ({errorDetected.row + 1}, {errorDetected.col + 1})!

)}
)} {/* Legend */}

How it works: Parity bits ensure even parity in each row/column.

When a bit flips, the affected row and column will have odd parity, pinpointing the error.

); }; export default ParityBitsGame;