// MODIBU - Board (40 tiles + center panel) const { useState: useStateB, useEffect: useEffectB, useMemo: useMemoB, useRef: useRefB } = React; // Map tile index → grid position (row, col) on 11x11 grid // Map tile index → grid position (row, col) on 9x9 grid (32 tiles) function tileGridPosition(i) { // Bottom row: i = 0..8 → row 9, col = 9 - i if (i <= 8) return { row: 9, col: 9 - i }; // Left col: i = 9..15 → col 1, row = 17 - i if (i <= 15) return { row: 17 - i, col: 1 }; // Top row: i = 16..24 → row 1, col = i - 15 if (i <= 24) return { row: 1, col: i - 15 }; // Right col: i = 25..31 → col 9, row = i - 23 return { row: i - 23, col: 9 }; } function tileRotation(i) { if (i <= 8) return 0; if (i <= 15) return 90; if (i <= 24) return 180; return 270; } // Group label color per type const TYPE_INFO = { edukasi: { bg: 'var(--c-edukasi)', deep: 'var(--c-edukasi-deep)', short: 'EDUKASI' }, fakta: { bg: 'var(--c-fakta)', deep: 'var(--c-fakta-deep)', short: 'FAKTA' }, tantangan: { bg: 'var(--c-tantangan)', deep: 'var(--c-tantangan-deep)', short: 'TANTANGAN' }, refleksi: { bg: 'var(--c-refleksi)', deep: 'var(--c-refleksi-deep)', short: 'REFLEKSI' }, kesempatan: { bg: 'var(--c-kesempatan)', deep: 'var(--c-kesempatan-deep)', short: 'KESEMPATAN' }, hukuman: { bg: 'var(--c-hukuman)', deep: 'var(--c-hukuman-deep)', short: 'HUKUMAN' }, start: { bg: 'var(--c-start)', deep: 'var(--c-start-deep)', short: 'START' }, finish: { bg: 'var(--c-finish)', deep: 'var(--c-finish-deep)', short: 'FINISH' }, penjara: { bg: '#495057', deep: '#212529', short: 'PENJARA' }, bonus: { bg: '#FAB005', deep: '#F08C00', short: 'BONUS' }, }; function BoardTile({ tile, players, isCurrent }) { const info = TYPE_INFO[tile.type] || TYPE_INFO.edukasi; const isStart = tile.i === 0; const isCorner = [0, 8, 16, 24].includes(tile.i); const cornerTile = isCorner; // Pawn slots on tile const here = (players || []).filter(p => p && p.position === tile.i); return (
Ronde {round || 1} · {sessionCode}