# API e Struttura Dati ## Panoramica Questo documento descrive la struttura dei dati, le interfacce e i moduli del gioco CatDoku. Essendo un'applicazione client-side, non ci sono API REST, ma il documento descrive le interfacce interne e la struttura di storage. ## Struttura Dati Principali ### Game State Oggetto principale che contiene tutto lo stato del gioco: ```typescript interface GameState { size: number; // Dimensione griglia (6-12) grid: Cell[][]; // Griglia 2D delle celle solution: Position[]; // Array delle posizioni soluzione errors: number; // Errori rimanenti (0-3) maxErrors: number; // Errori massimi (3) catsPlaced: number; // Numero gatti piazzati totalCats: number; // Numero totale gatti (= size) level: number; // Livello corrente (1+) score: number; // Punteggio totale accumulato hints: number; // Suggerimenti rimanenti (0-3) gameOver: boolean; // Flag game over won: boolean; // Flag vittoria livello playerName: string; // Nome/alias del giocatore levelStartTime: number; // Timestamp inizio livello (ms) levelTime: number; // Tempo trascorso (secondi) sessionRecords: LevelRecord[]; // Record della sessione corrente } ``` ### Cell Rappresenta una singola cella della griglia: ```typescript interface Cell { color: number; // Indice colore (0-11) hasCat: boolean; // Contiene un gatto? hasX: boolean; // Contiene una X (marcatura giocatore)? isSolution: boolean; // È parte della soluzione? } ``` ### Position Coordinate di una cella: ```typescript interface Position { row: number; // Riga (0-indexed) col: number; // Colonna (0-indexed) } ``` ### LevelRecord Record di un livello completato: ```typescript interface LevelRecord { playerName: string; // Nome giocatore level: number; // Livello completato gridSize: number; // Dimensione griglia usata time: number; // Tempo impiegato (secondi) score: number; // Punteggio ottenuto errors: number; // Errori commessi hintsUsed: number; // Suggerimenti utilizzati date: string; // Data ISO 8601 } ``` ## Interfacce dei Moduli ### Generator Module ```typescript interface GeneratorModule { generatePuzzle(size: number): Puzzle; generateSolution(size: number): Position[]; generateColors(size: number, solution: Position[]): number[][]; } interface Puzzle { grid: Cell[][]; solution: Position[]; } ``` #### generatePuzzle(size) - **Input**: `size` - Dimensione griglia (6-12) - **Output**: Oggetto `Puzzle` con griglia e soluzione - **Effetti collaterali**: Nessuno - **Eccezioni**: Nessuna (ha fallback deterministico) #### generateSolution(size) - **Input**: `size` - Dimensione griglia - **Output**: Array di `Position` (lunghezza = size) - **Garantisce**: Soluzione valida (rispetta tutte le regole) - **Eccezioni**: Nessuna #### generateColors(size, solution) - **Input**: - `size` - Dimensione griglia - `solution` - Array di posizioni soluzione - **Output**: Griglia 2D di indici colore - **Garantisce**: Regioni contigue e bilanciate - **Eccezioni**: Nessuna ### Validation Module ```typescript interface ValidationModule { isValidPlacement(row: number, col: number): boolean; getCatCountInRow(row: number): number; getCatCountInCol(col: number): number; getCatCountInColor(color: number): number; isCatAdjacent(row: number, col: number): boolean; } ``` #### isValidPlacement(row, col) - **Input**: Coordinate della cella - **Output**: `true` se il posizionamento è valido - **Controlla**: 1. Cella non ha X 2. Nessun gatto nella riga 3. Nessun gatto nella colonna 4. Nessun gatto nello stesso colore 5. Nessun gatto adiacente (8 direzioni) #### getCatCountInRow(row) - **Input**: Numero riga - **Output**: Numero di gatti nella riga (0-1) #### getCatCountInCol(col) - **Input**: Numero colonna - **Output**: Numero di gatti nella colonna (0-1) #### getCatCountInColor(color) - **Input**: Indice colore - **Output**: Numero di gatti nel colore (0-1) #### isCatAdjacent(row, col) - **Input**: Coordinate della cella - **Output**: `true` se c'è un gatto adiacente (8 direzioni) ### Game Logic Module ```typescript interface GameLogicModule { initGame(): void; placeCat(row: number, col: number): void; toggleX(row: number, col: number): void; useHint(): void; startTimer(): void; stopTimer(): void; saveLevelRecord(): void; } ``` #### initGame() - **Input**: Nessuno (usa `state.size` e `state.playerName`) - **Output**: Nessuno - **Effetti**: - Resetta stato livello - Genera nuovo puzzle - Avvia timer - Renderizza griglia #### placeCat(row, col) - **Input**: Coordinate della cella - **Output**: Nessuno - **Effetti**: - Se gatto già presente: lo rimuove - Se posizionamento valido: piazza gatto - Se posizionamento invalido: decrementa errori, flash errore - Se errori = 0: game over - Se tutti i gatti piazzati: vittoria #### toggleX(row, col) - **Input**: Coordinate della cella - **Output**: Nessuno - **Effetti**: - Se cella ha gatto: nessuna azione - Altrimenti: toggle stato X #### useHint() - **Input**: Nessuno - **Output**: Nessuno - **Effetti**: - Se hints = 0: mostra popup premium - Altrimenti: piazza gatto soluzione, decrementa hints #### startTimer() - **Input**: Nessuno - **Output**: Nessuno - **Effetti**: Avvia setInterval per aggiornamento tempo #### stopTimer() - **Input**: Nessuno - **Output**: Nessuno - **Effetti**: Ferma timer #### saveLevelRecord() - **Input**: Nessuno (usa stato corrente) - **Output**: Nessuno - **Effetti**: - Crea record livello - Salva in `state.sessionRecords` - Salva in `localStorage` ### UI Module ```typescript interface UIModule { renderGrid(): void; updateUI(): void; updateTimeDisplay(): void; showModal(title: string, message: string, btnText: string, callback: Function): void; hideModal(): void; showPremiumPopup(): void; showNameInput(): void; hideNameInput(): void; } ``` #### renderGrid() - **Input**: Nessuno (usa `state.grid`) - **Output**: Nessuno - **Effetti**: Ricostruisce DOM griglia con event listeners #### updateUI() - **Input**: Nessuno (usa `state`) - **Output**: Nessuno - **Effetti**: Aggiorna tutti i contatori e indicatori UI #### showModal(title, message, btnText, callback) - **Input**: Testo modal e callback - **Output**: Nessuno - **Effetti**: Mostra modal overlay #### hideModal() - **Input**: Nessuno - **Output**: Nessuno - **Effetti**: Nasconde modal overlay #### showPremiumPopup() - **Input**: Nessuno - **Output**: Nessuno - **Effetti**: Mostra popup premium con countdown 5s #### showNameInput() - **Input**: Nessuno - **Output**: Nessuno - **Effetti**: Mostra modal input nome #### hideNameInput() - **Input**: Nessuno - **Output**: Nessuno - **Effetti**: Nasconde modal input nome ### Storage Module ```typescript interface StorageModule { loadRecords(): LevelRecord[]; saveRecords(records: LevelRecord[]): void; } ``` #### loadRecords() - **Input**: Nessuno - **Output**: Array di `LevelRecord` - **Source**: `localStorage` key `'catdoku_records'` #### saveRecords(records) - **Input**: Array di `LevelRecord` - **Output**: Nessuno - **Destination**: `localStorage` key `'catdoku_records'` ## Costanti ### COLORS Array di colori per le regioni: ```javascript const COLORS = [ '#6abf69', // Verde '#4a90d9', // Blu '#e8a838', // Arancione '#c06dbf', // Viola '#e06060', // Rosso '#40b8c8', // Ciano '#d4c830', // Giallo '#8b6b4a', // Marrone '#7088a0', // Grigio-blu '#d04080', // Rosa '#5060b0', // Blu scuro '#30a080' // Verde acqua ]; ``` ### LONG_PRESS_MS Durata pressione per attivare gatto: ```javascript const LONG_PRESS_MS = 500; // millisecondi ``` ### STORAGE_KEY Key per localStorage: ```javascript const STORAGE_KEY = 'catdoku_records'; ``` ## Eventi UI ### Grid Cell Events | Evento | Azione | Condizione | |--------|--------|------------| | `mousedown` | Avvia timer long press | Button 0 (sinistro) | | `mouseup` | Toggle X o place cat | Se long press non attivato → X | | `mouseleave` | Cancella timer | Sempre | | `touchstart` | Avvia timer long press | Prevent default | | `touchend` | Toggle X o place cat | Se long press non attivato → X | | `touchcancel` | Cancella timer | Sempre | | `contextmenu` | Prevent default | Sempre (no menu contestuale) | ### Button Events | Button | Evento | Azione | |--------|--------|--------| | `btn-new-game` | click | Reset partita, mostra input nome | | `btn-hint` | click | Usa suggerimento o mostra premium | | `btn-eraser` | click | Cancella tutte le X | | `btn-back` | click | Naviga a leaderboard.html | | `name-submit-btn` | click | Conferma nome, inizia gioco | | `premium-btn` | click | Chiudi popup, aggiungi hint | | `modal-btn` | click | Chiudi modal, esegui callback | ## LocalStorage Schema ### Key: `catdoku_records` **Type**: JSON string **Structure**: Array di `LevelRecord` **Example**: ```json [ { "playerName": "Mario", "level": 1, "gridSize": 8, "time": 125, "score": 35, "errors": 1, "hintsUsed": 2, "date": "2026-06-15T18:30:00.000Z" }, { "playerName": "Mario", "level": 2, "gridSize": 8, "time": 98, "score": 40, "errors": 0, "hintsUsed": 1, "date": "2026-06-15T18:35:00.000Z" } ] ``` **Limiti**: - Dimensione massima: ~5MB (limite browser) - Persistenza: Fino a cancellazione manuale o cache clear - Scope: Per-browser, per-origin ## Error Handling ### Errori di Gioco Gestiti tramite decremento `state.errors` e flash visivo. ### Errori di Sistema - **Generazione fallita**: Fallback a posizionamento deterministico - **localStorage pieno**: Nessun handling specifico (raro per questo uso) - **Input invalido**: Trim e maxlength su nome giocatore ## Security Considerations ### Input Sanitization - **Nome giocatore**: `trim()` + `maxlength="20"` nell'HTML - **Nessun eval()**: Tutto il codice è statico - **No dynamic code**: Nessun `Function()` o `setTimeout()` con stringhe ### Data Validation - **Dimensione griglia**: Validata da `