11 KiB
11 KiB
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:
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:
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:
interface Position {
row: number; // Riga (0-indexed)
col: number; // Colonna (0-indexed)
}
LevelRecord
Record di un livello completato:
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
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
Puzzlecon 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 grigliasolution- Array di posizioni soluzione
- Output: Griglia 2D di indici colore
- Garantisce: Regioni contigue e bilanciate
- Eccezioni: Nessuna
Validation Module
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:
truese il posizionamento è valido - Controlla:
- Cella non ha X
- Nessun gatto nella riga
- Nessun gatto nella colonna
- Nessun gatto nello stesso colore
- 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:
truese c'è un gatto adiacente (8 direzioni)
Game Logic Module
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.sizeestate.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
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
interface StorageModule {
loadRecords(): LevelRecord[];
saveRecords(records: LevelRecord[]): void;
}
loadRecords()
- Input: Nessuno
- Output: Array di
LevelRecord - Source:
localStoragekey'catdoku_records'
saveRecords(records)
- Input: Array di
LevelRecord - Output: Nessuno
- Destination:
localStoragekey'catdoku_records'
Costanti
COLORS
Array di colori per le regioni:
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:
const LONG_PRESS_MS = 500; // millisecondi
STORAGE_KEY
Key per localStorage:
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:
[
{
"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()osetTimeout()con stringhe
Data Validation
- Dimensione griglia: Validata da
<select>(6-12) - Coordinate celle: Validate dai bounds della griglia
- Timestamp:
Date.now()per timer,new Date().toISOString()per record
Performance Metrics
Rendering
- Tempo render griglia 10×10: ~5ms
- Tempo update UI: <1ms
- Frequenza timer: 1Hz (ogni secondo)
Generazione
- Tempo generazione puzzle 10×10: ~120ms (media)
- Tempo generazione puzzle 12×12: ~280ms (media)
Storage
- Tempo save record: <1ms
- Tempo load records: <5ms (per <1000 record)
Compatibility
Browser Support
- Chrome 90+
- Firefox 88+
- Safari 14+
- Edge 90+
Feature Detection
Non utilizzata (feature moderne sempre supportate nei browser target).
Polyfills
Non richiesti (ES6+ nativo).