# Studio di fattibilità — App di riconoscimento carte FARAWAY

**Data:** 13 giugno 2026
**Obiettivo dello studio:** capire *se* e *come* un'app (prima webapp, poi app native iOS/Android) può, da una foto, riconoscere le carte di un giocatore a FARAWAY (le 8 Regioni + gli eventuali Santuari) come base per il futuro calcolo automatico del punteggio.

> **Verdetto in una riga:** ✅ **È fattibile, con accuratezza alta e costo quasi nullo.** Anzi, è già stato fatto da altri (vedi §7), il che conferma la fattibilità ma sposta la vera sfida su *qualità del riconoscimento, UX e costruzione del database delle carte*.

---

## 1. L'intuizione chiave (perché è più facile di quanto sembri)

Il problema **non** è "insegnare all'app a capire le illustrazioni delle carte". Ogni carta **Regione** ha in alto a sinistra un **numero univoco da 1 a 68**, grande e ad altissimo contrasto. Quindi:

```
foto → individua le carte → leggi il numero (1–68) → cerca tutto nel database → (futuro) calcola il punteggio
```

Leggere un numero a 1–2 cifre è il compito più facile che esista per un OCR. Una volta letto il numero, **l'app sa già tutto della carta** (colore/bioma, giorno/notte, simboli, quest, punti) perché lo legge da un database costruito una volta sola. Non serve riconoscere il disegno.

I **Santuari** sono l'eccezione: non hanno il numero 1–68. Vanno identificati in altro modo (icona + formula di punteggio, o un piccolo classificatore visivo). Sono ~45 in tutto e in una partita un giocatore ne ha pochi.

---

## 2. Prova empirica sulla TUA foto (`IMG_6527.HEIC`)

Non è teoria: ho fatto i test sulla foto reale che hai messo nella cartella.

| Test | Metodo | Esito |
|---|---|---|
| **Lettura degli 8 numeri Regione** | Modello multimodale (vision) | ✅ **8/8 corretti**: `5, 7, 23, 33, 4, 26, 32, 43` |
| **Robustezza alla riduzione** | Stessa lettura su foto ridotta a **768 px** di lato | ✅ ancora 8/8 leggibili (vedi `docs/img/foto-768px.jpg`) |
| **Santuari vs Regioni** | Riga alta = 6 carte senza numero, con formula `=N` | ✅ distinguibili nettamente |
| **Giorno/Notte dal badge** | Oro+sole = giorno, bianco+luna = notte | ✅ leggibile (dato ridondante: è già nel DB una volta letto il numero) |
| **Segmentazione automatica carte** | OpenCV, maschera sul feltro verde (metodo banale) | ⚠️ ~13/14 carte isolate (vedi `docs/img/segmentazione.jpg`) — in produzione si fa molto meglio |
| **OCR classico "grezzo"** | Tesseract sull'angolo intero | ⚠️ rumoroso: prende `43`, `26` ma sbaglia altri |

**Lettura del montaggio dei badge** (`docs/img/badge-montaggio.jpg`): conferma che numeri, icone giorno/notte e simboli sono nitidi.

Due conclusioni operative da questi test:
1. **Un modello vision legge tutto al primo colpo**, anche su foto fortemente ridotta → la via cloud è banale ed economica.
2. L'OCR classico (Tesseract) sull'angolo "così com'è" è rumoroso **perché va prima isolato il badge**. Con un OCR serio (Apple Vision / ML Kit) e un ritaglio stretto sul numero, l'accuratezza sale molto. Tesseract resta solo un ripiego per il browser.

---

## 3. Il gioco in numeri (dimensione del DB e complessità del punteggio)

Dati verificati su regolamento ufficiale (Catch Up Games / Pandasaurus), BGG e Board Game Arena.

**Componenti — gioco base:**
- **68 carte Regione**, numerate **1–68, numero univoco** (chiave perfetta per il lookup).
- **45 carte Santuario** (senza numero 1–68).
- **Totale DB base: 113 carte.**
- Tableau di un giocatore: **8 Regioni** + un numero variabile, piccolo ma **non fisso**, di Santuari (non c'è un tetto a 4: con molti Indizi se ne prendono di più).

**Sistema di punteggio (per il *futuro* motore di calcolo):**
- Si conta **da destra a sinistra** (ordine inverso di gioco): si scopre una carta alla volta dalla più recente, e ogni carta conta **solo ciò che è già scoperto alla sua destra**. → Il punteggio **non** è leggibile carta per carta: va **calcolato** sulla sequenza ordinata. Questo è il vero (e unico) punto di complessità algoritmica.
- I Santuari sono scoperti per tutta la fase di conteggio e contano per ogni Regione.
- Famiglie di simboli da modellare nel DB: **4 biomi/colori** (blu/rosso/verde/giallo) + grigio, **3 risorse** (animale = *okiko chimera*, minerale = *uddu stones*, vegetale = *goldlog thistle*), **flag giorno/notte**, **indizi**, **quest** (predicato + payout), **formule Santuario** `X = N`.

**Espansioni (importante per la strategia di riconoscimento):**
- *People From Below*: +9 Regioni, +8 Santuari, 5° bioma grigio "Mystical Havens", fino a 7 giocatori. ⚠️ Non è confermato pubblicamente se le 9 nuove Regioni siano numerate 69+ o riusino numeri bassi — **da verificare sulle carte fisiche** prima di supportarle.
- *Under Starry Skies* (Meteoriti): +15 carte che **riusano deliberatamente i numeri 1–68**, con marker "**palla di fuoco rosa**" in basso a sinistra, e una meccanica "stessa ultima cifra".

> **Conseguenza progettuale:** la "chiave numero = identità univoca" è **perfetta solo per il gioco base**. Se in futuro vuoi supportare le espansioni, serve un disambiguatore visivo (la palla di fuoco rosa) e l'identificazione a icona per Santuari/Meteoriti. **Per l'MVP: solo gioco base.**

---

## 4. Approcci a confronto

| Approccio | Come funziona | Accuratezza | Costo/foto | Offline | Sforzo dev | Note |
|---|---|---|---|---|---|---|
| **A. Vision LLM cloud** ⭐ (per MVP) | Foto → API multimodale (Gemini Flash-Lite / GPT-4o-mini / Haiku) → JSON `{regioni:[...], santuari:[...]}` | **Molto alta** (>95% su foto nitide) | **~0,0001–0,002 $** | ❌ | **Basso** | Gestisce layout, numeri e icone in un colpo. Output JSON forzato. |
| **B. OCR on-device** ⭐ (per app native) | Apple Vision (iOS) / ML Kit (Android): rileva carta → ritaglia badge → OCR numero → lookup | **Alta** (compito facile) | **0 €** | ✅ | Medio | Gratis, privato, nessun costo ricorrente. Richiede codice nativo (o wrapper). |
| **C. CV classica** (OpenCV + Tesseract) | Segmentazione + OCR fatti a mano | Media | 0 € | ✅ | Alto | Tanta messa a punto, risultati peggiori di A/B. Sconsigliato come via principale. |
| **D. Ibrido** (consigliato a regime) | On-device come default + fallback cloud sulle letture a bassa confidenza | **Massima** | quasi 0 | parziale | Medio-alto | Il meglio dei due, ma da fare dopo. |

**Raccomandazione:**
- **MVP webapp → Approccio A (cloud vision).** Nessun modello da spedire, accuratezza alta, costo irrilevante, si parte in giorni.
- **App native → Approccio B (on-device).** Azzera i costi ricorrenti e i problemi di privacy; la logica di punteggio e il DB si riusano identici.
- A regime, **D (ibrido)** per la massima robustezza.

**Da NON fare:** chiedere al modello vision di "calcolare direttamente il punteggio". Il riconoscimento deve produrre **solo la lista ordinata di ID carte**; il punteggio lo calcola un **motore deterministico** in TypeScript (riusabile su web e native). Più affidabile, spiegabile e testabile.

---

## 5. Modello di costo (via cloud)

Solo i **token dell'immagine** contano (l'output JSON è minuscolo). Riducendo la foto a ~768–1024 px prima dell'invio (vedi §2) si abbattono i token di ~50×.

| Modello | $ / 1000 foto (stima) |
|---|---|
| Gemini 2.5 Flash-Lite | **~0,15–0,25 $** |
| GPT-4o-mini | ~0,10–0,35 $ |
| Claude Haiku 4.5 | ~1,6–2,3 $ |
| (frontier: Opus 4.8 / GPT-5.5 / Gemini Pro) | 5–28 $ — **sovradimensionato** |

A volume hobby/familiare il costo è **prossimo a zero**; molti provider hanno anche un free tier (es. Google Vision: prime 1000 unità/mese gratis). Con l'app nativa on-device il costo diventa **letteralmente 0**.

---

## 6. Architettura consigliata (MVP webapp → app native)

**Stack MVP (settimane, non mesi):**
- **Next.js (PWA) su Vercel.** Shell installabile + API serverless + hosting gratuito.
- **Cattura foto:** `<input type="file" accept="image/*" capture="environment">` — affidabile su mobile (il `getUserMedia` live è instabile nelle PWA installate su iOS; eventualmente come miglioria su Android/desktop).
- **Riconoscimento:** la PWA ridimensiona/comprime la foto lato client (⚠️ limite body Vercel 4,5 MB) e la invia a una **function serverless** che chiama il modello vision e ritorna gli ID carta in JSON.
- **DB carte:** semplice **JSON statico** (113 carte: id, bioma, giorno/notte, simboli, regola di punteggio) incluso nell'app.
- **Motore di punteggio:** **TypeScript puro** (`score(tableau, cardDB)`), riusabile 1:1 nell'app nativa.
- **Persistenza:** `localStorage`/IndexedDB. Niente account, niente foto salvate.

**Passo di sicurezza fondamentale (UX):** dopo il riconoscimento, mostrare **"Conferma/Correggi le carte rilevate"** prima di calcolare. È la singola feature più importante per l'affidabilità: copre i casi di riflessi/sfocature/carte sovrapposte.

**App native (fase successiva):** **Expo / React Native** — riusa lo stesso motore TS e lo stesso JSON, resta in un solo linguaggio, e per l'OCR on-device usa `react-native-vision-camera` + plugin ML Kit (iOS→Apple Vision, Android→ML Kit). (Flutter darebbe più code-share ma in Dart, perdendo il riuso del codice web.)

**Modello dati per il "gioco completo" (tuo obiettivo a regime):**
```
Game   { id, data, players[] }
Player { id, nome, tableau }
Tableau{ fotoRef?, regioni: CardId[]  (ordinate sx→dx), santuari: CardId[] }
punteggio = funzione pura  score(tableau, cardDB)   // ricalcolabile, non va "salvato"
```
Stesso schema su PWA e native. Flusso: crea partita → aggiungi N giocatori → per ciascuno fotografa il tableau → riconosci → **conferma/correggi** → calcola → classifica comparata.

**Privacy/Store:** foto inviata al cloud e **subito scartata** = *non* considerata "raccolta" (regole Apple); on-device = storia di privacy ancora più pulita e vendibile. In entrambi i casi: stringa di permesso fotocamera chiara e coerente con la privacy policy.

---

## 7. ⚠️ Realtà di mercato: esiste già

Va detto chiaramente, perché cambia la decisione *go/no-go*:

- **`faraway-solver.com`** è una **webapp (PWA) già online** che fa esattamente questo: *"scatta una foto del tuo tavolo Faraway e lascia che l'app rilevi le carte e calcoli il punteggio"*. Ha un flusso con passo di correzione manuale (segno che il riconoscimento non è ancora perfetto al 100%), storico e statistiche. Closed-source.
- **`MathisNcl/faraway`** (GitHub) è una **pipeline open-source** che implementa *la stessa strategia* qui valutata: object detection (RT-DETR) per ritagliare le carte + **PaddleOCR** per leggere il numero + lookup su CSV. Gestione Santuari parziale. ⚠️ **Senza licenza** = tutti i diritti riservati di default: utile come riferimento, **non** riusabile liberamente.
- Esistono inoltre **un CSV open delle 68 Regioni** (stesso repo, niente Santuari, senza licenza) e **molti calcolatori a inserimento manuale** (iOS/Android/web).

**Cosa significa per te:**
- ✅ La fattibilità è **confermata sul campo** (qualcuno l'ha spedita).
- 🎯 Il riconoscimento da foto **non è più un fattore differenziante** di per sé: lo diventano **accuratezza, UX, gestione multi-giocatore di una partita, lingua italiana, gratuità, offline/privacy**.
- 🧱 Non puoi semplicemente "riusare" gli asset esistenti (problemi di licenza). **Il DB delle 113 carte va costruito e validato a mano** — ed è, onestamente, **la parte di lavoro più sottovalutata** dell'intero progetto (i dati delle illustrazioni sono coperti da copyright; le *regole/attributi* invece sono fatti di gioco trascrivibili).

---

## 8. Rischi e questioni aperte

| Rischio | Impatto | Mitigazione |
|---|---|---|
| **Costruzione DB carte** (113 voci, regole di punteggio) | Alto (è il grosso del lavoro) | Trascrivere a mano da carte/regolamento; validare contro Board Game Arena; partire dalle 68 Regioni. |
| **Santuari** (no numero) | Medio | Identificazione per icona+formula o mini-classificatore; in MVP si possono inserire/correggere a mano. |
| **Espansioni rompono l'unicità del numero** | Medio (solo se le supporti) | MVP = solo gioco base; per Meteoriti usare il marker palla-di-fuoco. |
| **Foto difficili** (riflessi, sfocatura, carte sovrapposte) | Medio | Linee guida di scatto + **passo di conferma/correzione** + validazione (numeri ∈ 1–68, unicità, conteggio = 8). |
| **Concorrente già attivo** | Strategico | Differenziare su UX/accuratezza/IT/offline; oppure restare a uso personale/familiare. |
| **Copyright illustrazioni** | Legale | Non redistribuire scansioni/immagini; il metodo "numero→DB" non ne ha bisogno. |

---

## 9. Conclusioni e prossimi passi

**Fattibilità: confermata, alta.** Tecnicamente è uno dei casi d'uso più favorevoli possibili per il riconoscimento (numero grande, univoco, ad alto contrasto → dominio chiuso 1–68 che fa anche da correttore d'errore). Costo trascurabile (cloud) o nullo (on-device).

**Percorso consigliato per uno sviluppatore singolo:**
1. **Fase 0 — Proof of concept (1–2 giorni):** una pagina che invia la foto a un modello vision e mostra il JSON `{regioni, santuari}`. Conferma la pipeline end-to-end sulle tue foto.
2. **Fase 1 — MVP webapp (giorni→settimane):** PWA Next.js, cattura foto, riconoscimento cloud, **conferma/correzione carte**, DB JSON (parti dalle 68 Regioni), niente punteggio ancora — solo "vedo correttamente le carte".
3. **Fase 2 — Motore di punteggio + gioco completo:** scoring deterministico TS, multi-giocatore, classifica.
4. **Fase 3 — App native (solo se servono store/offline/zero-costo):** Expo riusando motore + DB, OCR on-device.

**Domanda da decidere prima di partire** (vedi §7): visto che esiste già `faraway-solver.com`, l'obiettivo è *uso personale/familiare* (allora si punta dritti alla semplicità e si può anche valutare se l'esistente basta) oppure *un prodotto pubblico* (allora va definito il differenziatore: accuratezza, UX, italiano, offline)?

---

### Appendice — fonti principali (verificate)
- Regolamento/componenti: rulespal.com/faraway/rulebook · boardgamegeek.com/boardgame/385761 · en.doc.boardgamearena.com/Tips_faraway
- Asset esistenti: faraway-solver.com · github.com/MathisNcl/faraway
- Cloud vision: platform.claude.com/docs (vision) · developers.openai.com/api/docs/guides/images-vision · ai.google.dev/gemini-api/docs/pricing
- On-device: developer.apple.com/documentation/vision/vnrecognizetextrequest · developers.google.com/ml-kit/vision/text-recognition/v2
- Stack: docs.expo.dev · vercel.com/docs/functions/limitations · developer.apple.com/app-store/app-privacy-details
