Files
catdoku/docs/api.md
T

11 KiB
Raw Blame History

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 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

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

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

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: 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:

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() o setTimeout() 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).