← al gioco

Come si gioca

Prima volta? Guarda come si gioca: un minuto di lezione animata, su un esempio tutto suo. Vuoi una mano col primo puzzle? 🎓 Il tutorial lo risolve con te, passo per passo (attenzione: spoiler!).

Le regoleI gestiCondividere

Le regole

  1. 1 · Un sudoku di lettereLa griglia è 6×6, divisa in sei riquadri da 2×3. Ci sono sei lettere: ognuna va una volta sola in ogni riga, in ogni colonna e in ogni riquadro.
  2. 2 · Tre parole nascosteIn alto ci sono tre parole, ognuna con il suo colore: rosso, verde, blu. Una parola parte dalla casella con il quadratino del suo colore e si legge una lettera dopo l'altra, passando ogni volta a una casella accanto: su, giù, a destra o a sinistra, mai in diagonale.
  3. 3 · Lettere fisseLe lettere che metti tu hanno il bordo sottile, come A. Alcune lettere sono già in griglia quando il puzzle parte, e hanno il bordo più spesso, come S: quelle restano dove sono (se le trascini, ne parte una copia).

C'è una sola soluzione, e ci si arriva ragionando: non serve tirare a indovinare. Quando la griglia è giusta e le tre parole ci sono tutte, hai vinto.

I gesti

Sotto ogni gesto c'è una piccola griglia vera: provalo lì. Il primo puzzle è sempre ITALIA · PASTA · ALPI, e qui non si salva niente. ↺ da capo la rimette com'era.

Scorri verso sinistra per il gesto dopo →

Condividere una partita

Quando risolvi un puzzle, sotto Evviva! 🥳 c'è 📤 condividi: copia (o manda, sul telefono) un messaggio come questo, che racconta come hai giocato senza dire dove vanno le lettere.

Chi non ha giocato vede solo palline. Chi ha giocato capisce con quale parola hai cominciato, quanto sudoku ti restava e dove hai sbagliato.

← al gioco

## Come si gioca a Parloku: prima le regole, poi i gesti. Pagina `istruzioni.html`, aperta dal menu del gioco.
import std/[json, os]
import nimib
import style

nbInit
nb.doc.filename = currentSourcePath().parentDir.parentDir / "istruzioni.html"
nb.doc.context["title"] = %"Parloku: come si gioca"
nb.doc.context["stylesheet"] = %(pageStyle & """
<style>
.howto h1{font-size:clamp(36px,9vw,56px);margin:14px 0 6px}
.howto .back{display:inline-block;margin:10px 0 4px;font-weight:700;color:var(--ink)}
.howto h2{font-size:24px;margin:26px 0 10px}
.howto ol,.howto ul{padding-left:0;list-style:none;margin:0;display:flex;flex-direction:column;gap:10px}
.howto li{background:var(--card);border:var(--border) solid var(--line);border-radius:14px;padding:10px 14px;line-height:1.45}
.howto li b{display:block;font-family:var(--font-head);font-size:18px}
.howto .k{display:inline-grid;place-items:center;width:1.7em;height:1.7em;border-radius:50%;border:1.5px solid var(--ink);
  font:var(--glyph-weight) 1em/1 var(--font-glyph);vertical-align:-.32em;margin:-.2em .1em 0;padding-bottom:.14em;box-sizing:border-box}   /* a round tile, as in the game */
.howto .k.g0{background:var(--g0)} .howto .k.g1{background:var(--g1)} .howto .k.g2{background:var(--g2)}
.howto .k.given{border-width:3.5px}
.howto .w0{color:var(--w0);font-weight:800} .howto .w1{color:var(--w1);font-weight:800} .howto .w2{color:var(--w2);font-weight:800}
.howto .start{background:var(--card);border:var(--border) solid var(--line);border-radius:14px;padding:10px 14px;line-height:1.45;margin:8px 0 0}
.howto .start a{color:var(--ink);font-weight:700}
.howto .note{color:var(--muted);font-size:15px;margin-top:14px}
.howto ul.cases{list-style:disc;padding-left:1.2em;margin:4px 0;display:block}
.howto ul.cases li{background:none;border:0;border-radius:0;padding:0;margin:2px 0}
.howto .do{display:block;margin-top:8px;font-weight:600}
.howto .try{margin:10px -4px 2px;display:flex;flex-direction:column;align-items:center;gap:6px}
.howto .try iframe{width:min(100%,330px);height:600px;border:var(--border) solid var(--line);border-radius:14px;background:var(--bg)}
.howto .toc{display:flex;flex-wrap:wrap;gap:8px;margin:14px 0 0}
.howto .toc a{font:700 15px var(--font-body);border:var(--border) solid var(--ink);background:var(--card);color:var(--ink);border-radius:999px;padding:5px 14px;text-decoration:none}
.howto h2{scroll-margin-top:12px}
/* the gestures: a gallery, one card at a time, swiped from right to left */
.howto ul.gallery{flex-direction:row;overflow-x:auto;scroll-snap-type:x mandatory;gap:12px;margin:0 -16px;padding:4px 16px 10px;
  -webkit-overflow-scrolling:touch;scrollbar-width:thin}
.howto ul.gallery>li{flex:0 0 86%;scroll-snap-align:center;box-sizing:border-box}
.howto .swipe{color:var(--muted);font-size:14px;margin:6px 0}
.howto .share{font-size:22px;line-height:1.2;letter-spacing:1px;white-space:pre-line;background:var(--card);border:var(--border) solid var(--line);
  border-radius:14px;padding:10px 14px;margin:8px 0}
.howto .share small{display:block;font-size:14px;letter-spacing:0;color:var(--muted)}
.howto .again{font:700 14px var(--font-body);border:var(--border) solid var(--ink);background:var(--card);color:var(--ink);border-radius:999px;padding:5px 14px;cursor:pointer}
</style>""")
nb.doc.context["highlight"] = %""
nb.doc.context["disableHighlightJs"] = %true
func pageHeader(blk: JsonNode, nb: Nb): string = ""
nb.backend.partials["header"] = pageHeader

nbRawHtml: """
<div class="howto">
<a class="back" href="index.html">← al gioco</a>
<h1>Come si gioca</h1>
<p class="start">Prima volta? <a href="index.html?learn">Guarda come si gioca</a>: un minuto di lezione animata, su un esempio
tutto suo. Vuoi una mano col primo puzzle? <a href="index.html?tutorial">🎓 Il tutorial</a> lo risolve con te, passo per passo
(attenzione: spoiler!).</p>
<p class="toc"><a href="#regole">Le regole</a><a href="#gesti">I gesti</a><a href="#condividere">Condividere</a></p>

<h2 id="regole">Le regole</h2>
<ol>
<li><b>1 · Un sudoku di lettere</b>La griglia è 6×6, divisa in sei riquadri da 2×3. Ci sono sei lettere: ognuna va
una volta sola in ogni riga, in ogni colonna e in ogni riquadro.</li>
<li><b>2 · Tre parole nascoste</b>In alto ci sono tre parole, ognuna con il suo colore:
<span class="w0">rosso</span>, <span class="w1">verde</span>, <span class="w2">blu</span>.
Una parola parte dalla casella con il quadratino del suo colore e si legge una lettera dopo l'altra,
passando ogni volta a una casella accanto: su, giù, a destra o a sinistra, mai in diagonale.</li>
<li><b>3 · Lettere fisse</b>Le lettere che metti tu hanno il bordo sottile, come <span class="k" style="background:var(--g0);color:var(--i0)">A</span>.
Alcune lettere sono già in griglia quando il puzzle parte, e hanno il bordo più spesso, come <span class="k given" style="background:var(--g4);color:var(--i4)">S</span>:
quelle restano dove sono (se le trascini, ne parte una copia).</li>
</ol>
<p class="note">C'è una sola soluzione, e ci si arriva ragionando: non serve tirare a indovinare.
Quando la griglia è giusta e le tre parole ci sono tutte, hai vinto.</p>

<h2 id="gesti">I gesti</h2>
<p class="note">Sotto ogni gesto c'è una piccola griglia vera: provalo lì. Il primo puzzle è sempre ITALIA · PASTA · ALPI, e qui
non si salva niente. <i>↺ da capo</i> la rimette com'era.</p>
<p class="swipe">Scorri verso sinistra per il gesto dopo →</p>
<ul class="gallery">
<li><b>Mettere una lettera</b>Trascina una delle sei lettere in basso su una casella vuota. Le lettere già in griglia non vengono mai coperte.
<span class="do">Prova: porta la I sulla casella con il quadratino rosso, in alto a sinistra.</span><div class="try"><iframe loading="lazy" src="index.html?nosplash&amp;demo&amp;p=AILPST_51S.23L.04P_00ITALIA.20PASTA.40ALPI" title="Mettere una lettera"></iframe><button class="again" type="button">↺ da capo</button></div></li>
<li><b>Copiare una lettera</b>Trascina una lettera della griglia: ne parte una copia, che puoi mettere su un'altra casella.
<span class="do">Prova: trascina la P già in griglia, in alto a destra, e lasciala più in basso.</span><div class="try"><iframe loading="lazy" src="index.html?nosplash&amp;demo&amp;p=AILPST_51S.23L.04P_00ITALIA.20PASTA.40ALPI" title="Copiare una lettera"></iframe><button class="again" type="button">↺ da capo</button></div></li>
<li><b>Spostare una lettera</b>Tienila premuta finché si solleva, poi portala dove vuoi.
<span class="do">Prova: la T in alto è nel posto sbagliato. Tienila premuta e spostala una casella a sinistra.</span><div class="try"><iframe loading="lazy" src="index.html?nosplash&amp;demo&amp;p=AILPST_51S.23L.04P_00ITALIA.20PASTA.40ALPI&amp;g=2T" title="Spostare una lettera"></iframe><button class="again" type="button">↺ da capo</button></div></li>
<li><b>Scrivere una parola</b>Trascina l'ultima lettera di una parola sulle caselle vicine: a ogni passo si aggiunge la lettera
che viene dopo, e tornando indietro la togli. Il contorno colorato cresce con la parola: la prima casella resta velata
del suo colore, e l'ultima lettera, la testa, ha due occhietti che guardano dove va la parola.
<span class="do">Prova: trascina la I di ITALIA verso destra: arrivano la T e la A. Poi torna indietro.</span><div class="try"><iframe loading="lazy" src="index.html?nosplash&amp;demo&amp;p=AILPST_51S.23L.04P_00ITALIA.20PASTA.40ALPI&amp;g=0I" title="Scrivere una parola"></iframe><button class="again" type="button">↺ da capo</button></div></li>
<li><b>Togliere</b>Doppio tocco su una lettera: torna in basso. Se fa parte di una parola, la parola si accorcia lì: tornano in basso
quella lettera e quelle dopo, le prime restano.
<span class="do">Prova: doppio tocco sulla T da sola, al centro. Poi doppio tocco sulla T di ITALIA: resta solo la I.</span><div class="try"><iframe loading="lazy" src="index.html?nosplash&amp;demo&amp;p=AILPST_51S.23L.04P_00ITALIA.20PASTA.40ALPI&amp;g=0I,1T,2A,20T" title="Togliere"></iframe><button class="again" type="button">↺ da capo</button></div></li>
<li><b>Riempire una casella sicura</b>Con un doppio tocco su una casella vuota, la lettera si mette da sola, ma solo in due casi:
<ul class="cases"><li>è la casella con il quadratino, dove parte una parola: arriva la sua prima lettera;</li>
<li>è l'ultima casella libera di una riga, di una colonna o di un riquadro: arriva la lettera che manca.</li></ul>
Sulle altre caselle il doppio tocco non fa niente: lì la lettera la trovi tu.
<span class="do">Prova: doppio tocco sull'ultima casella della prima riga, sull'ultima libera della terza colonna, sull'ultima libera del riquadro in basso a destra, e poi sul quadratino verde.</span><div class="try"><iframe loading="lazy" src="index.html?nosplash&amp;demo&amp;p=AILPST_51S.23L.04P_00ITALIA.20PASTA.40ALPI&amp;g=0I,1T,2A,3S,8L,14S,20T,26P,27T,28I,33P,34L,35A" title="Riempire una casella sicura"></iframe><button class="again" type="button">↺ da capo</button></div></li>
<li><b>Dov'è una parola?</b>Tocca una parola in alto: sulla griglia il suo quadratino o il suo contorno vibra.
<span class="do">Prova: tocca ALPI.</span><div class="try"><iframe loading="lazy" src="index.html?nosplash&amp;demo&amp;p=AILPST_51S.23L.04P_00ITALIA.20PASTA.40ALPI" title="Dov'è una parola?"></iframe><button class="again" type="button">↺ da capo</button></div></li>
<li><b>Due lettere che si scontrano</b>Se la stessa lettera è due volte nella stessa riga, colonna o riquadro, le due lettere
tremano come biglie inquiete: dondolano a destra e a sinistra, prima piano e poi, per qualche secondo, un po' di più. Niente diventa
rosso e niente ti blocca. Mentre tieni una lettera col dito, non tremano. Basta spostarne o toglierne una e si fermano.
Il gioco ti dice solo quando due lettere si scontrano, non se una lettera è giusta: quello lo scopri ragionando.
<span class="do">Prova: le due A in alto si scontrano. Fai doppio tocco su una delle due.</span><div class="try"><iframe loading="lazy" src="index.html?nosplash&amp;demo&amp;p=AILPST_51S.23L.04P_00ITALIA.20PASTA.40ALPI&amp;g=2A,5A" title="Due lettere che si scontrano"></iframe><button class="again" type="button">↺ da capo</button></div></li>
<li><b>Il menu</b>Nel gioco, tocca uno spazio vuoto sopra la griglia: in alto compaiono <i>istruzioni</i>, <i>ancora!</i> per scegliere un altro puzzle
(quelli già risolti hanno ✓) e <i>rifaccio</i> per ricominciare. Subito dopo, per qualche secondo, puoi ancora
<i>annullare</i> il rifaccio.</li>
</ul>

<h2 id="condividere">Condividere una partita</h2>
<p>Quando risolvi un puzzle, sotto <i>Evviva! 🥳</i> c'è <i>📤 condividi</i>: copia (o manda, sul telefono) un messaggio
come questo, che racconta come hai giocato senza dire dove vanno le lettere.</p>
<p class="share">Parloku 1 🥳🐍 · 37 mosse · 5:55
🔴🟢🔵🟢🟢🟢
🟢🔴🔴⚪⚫🔴
🔴🔴🔵🔵🔵⚪
⚪⚪⚪⚪⚪⚪
⚪⚫⚪⚪⚪⚪
⚪⚪⚪⚪⚪⚪
⚪<small>pietroppeter.github.io/parloku/?p=1</small></p>
<ul>
<li><b>Una pallina per mossa</b>Ogni lettera che metti sulla griglia, o che rimandi in basso, è una mossa: sei palline per riga,
come una riga della griglia.</li>
<li><b>🔴 🟢 🔵 le parole</b>Ogni lettera giusta di una parola prende il colore della parola: ITALIA fa sei palline
<span class="w0">rosse</span>, PASTA cinque <span class="w1">verdi</span>, ALPI quattro <span class="w2">blu</span>.
Conta la lettera che resta: se scrivi una parola nel posto sbagliato e poi la togli, quelle mosse sono ⚪.</li>
<li><b>⚪ ⚫ il resto</b>⚪ è ogni altra lettera messa, ⚫ una lettera rimandata in basso (anche con ↶ annulla).
Oltre le 48 mosse si vedono le prime sette righe, poi … e quante ne mancano.</li>
<li><b>🥳 e la festa</b>Accanto a 🥳 c'è la festa che hai visto: 🌊 le onde, 🐍 i serpenti, 🪀 le lettere.
Il numero dopo Parloku è il puzzle, e ⭐ vuol dire nessuna lettera mossa due volte: tante mosse quante caselle vuote.</li>
</ul>
<p class="note">Chi non ha giocato vede solo palline. Chi ha giocato capisce con quale parola hai cominciato, quanto sudoku ti restava e dove hai sbagliato.</p>
<p><a class="back" href="index.html">← al gioco</a></p>
</div>
"""

nbJsFromCode:
  import std/dom
  proc setSkin(e: Element, v: cstring) {.importjs: "#.dataset.skin = #".}
  proc frameOf(e: Element): Element {.importjs: "#.closest('.try').querySelector('iframe')".}
  proc reload(f: Element) {.importjs: "(f => { f.src = f.src })(#)".}
  proc onHeight(cb: proc (f: Element, h: float)) {.importjs:
    "(cb => addEventListener('message', ev => { const h = ev.data && ev.data.parlokuHeight; if (!h) return; " &
    "for (const f of document.querySelectorAll('.try iframe')) if (f.contentWindow === ev.source) cb(f, h) }))(#)".}
  proc setHeight(f: Element, h: float) {.importjs: "#.style.height = # + 'px'".}
  document.body.setSkin("niki")          # the game's one look
  # each board as tall as its game (words, grid and the six letters): the game in the frame says how tall it is
  onHeight(proc (f: Element, h: float) = f.setHeight(h))
  # ↺ da capo: the practice board starts again from its letters
  for b in document.querySelectorAll(".try .again"):
    b.addEventListener("click", proc (ev: Event) =
      let f = Element(ev.currentTarget).frameOf
      f.reload)

nbSave