Gioco di memoria con 3 livelli di difficoltà, animazioni 3D CSS e statistiche persistenti, costruito con Python/Flask e JavaScript vanilla.
MemoryLab è una web app single-page che implementa il classico gioco del memory: una griglia di carte coperte da abbinare a coppie. L'obiettivo è trovare tutte le coppie nel minor tempo e col minor numero di mosse.
Divisione dei compiti: il backend Python genera e mescola la board; tutto il resto — flip, match, timer, punteggio, statistiche — vive nel JavaScript del browser.
Flask invece di Django
Il backend ha un solo compito: generare e mescolare la board. Django sarebbe over-engineering. Flask permette di avere un server funzionante in ~20 righe mantenendo app.py leggibile e autoesplicativo.
localStorage invece di un database
MemoryLab è una single-player app locale: i dati appartengono al browser dell'utente. localStorage offre persistenza zero-setup senza dati trasmessi in rete. Lo svantaggio — i dati si perdono svuotando il browser — è accettabile per un'app di gioco personale.
JavaScript vanilla invece di React/Vue
Per una SPA con una sola schermata, una griglia e un pannello statistiche, il DOM nativo è più che sufficiente. Scrivere JS vanilla dimostra padronanza reale del linguaggio: gestione eventi con addEventListener, manipolazione DOM con querySelector, fetch nativa con async/await. Zero configurazione, zero npm install.
CSS puro invece di Tailwind
Le animazioni flip 3D richiedono transform-style: preserve-3d, perspective, backface-visibility e rotateY coordinati su più classi. Con Tailwind si perderebbero in utility classes non standard o si dovrebbe estendere la config. Con CSS scritto a mano ogni dettaglio è sotto controllo totale e debuggabile nei DevTools.
Browser Flask Server
│ │
│── GET /api/board?difficulty=easy ──▶│
│ │ random.shuffle() sulle coppie
│◀─────── JSON { cards, cols } ─────│
│ │
│ Tutto il gioco avviene nel browser:
│ - renderBoard() costruisce il DOM
│ - onCardClick() gestisce i flip
│ - checkMatch() confronta pair_id
│ - onVictory() salva in localStorage
│ - renderStats() legge localStorage
Generazione board (generate_board)
Il backend genera gli indici di coppia mescolati (pair_id da 0 a N), non le emoji — quelle sono hardcodate nel frontend. Questo evita di duplicare la lista in due posti.
Flip 3D (onCardClick → flipCard)
Al click aggiunge .flipped alla carta, che attiva transform: rotateY(180deg) sull'.card-inner. Il fronte è già ruotato di 180° via CSS, quindi diventa visibile mentre il retro scompare: effetto flip 3D puro, zero librerie.
Match check (checkMatch)
Quando state.flipped contiene due id, confronta i pair_id corrispondenti. Se uguali: aggiunge .matched (bordo verde pulsante). Se diversi: blocca i click con state.isLocked, aggiunge .wrong (shake animation), poi dopo 800ms rimuove .flipped e sblocca.
Formula del punteggio
score = (coppie × 1000) − (mosse × 10) − (secondi × 2) [minimo 0]
Una partita perfetta in Easy (8 coppie, 8 mosse, 30 secondi) vale circa 7920 punti.
localStorage
Chiave separata per ogni difficoltà (memorylab_history_easy, ecc.). Ogni partita aggiunge { date, difficulty, time, moves, score } all'array, troncato alle ultime 20 voci.
cd memorylab
pip install -r requirements.txt
python app.pyApri il browser su http://localhost:5001.
memorylab/
├── app.py ← Flask: route / e /api/board
├── requirements.txt ← dipendenze (solo flask)
├── README.md
└── templates/
└── index.html ← SPA: HTML + CSS + JS tutto inline