[javascript] Realizzare un gioco di carte tipo Memory utilizzando jQuery

Obiettivo: realizzare un semplice gioco di carte tipo Memory, utilizzando JavaScript e il framework jQuery.

Per chi non conoscesse il Memory, il gioco consiste nel cercare di indovinare le coppie di carte uguali. All’inizio possono venir mostrate tutte le carte (se vogliamo dare un’aiuto iniziale) che poi vengono coperte; a quel punto si tirano su due carte per volta per vedere se sono uguali: se lo sono le lasciamo scoperte, altrimenti le ricopriamo e procediamo col sollevare un’altra coppia e così via.

La versione giocabile del gioco, realizzato come illustrato nell’articolo, si trova in fondo all’articolo

Il gioco può essere elaborato in diverse varianti, a fini di questo semplice esercizio prendiamo in considerazione le seguenti regole:

  1. Al primo turno vengono mostrate per un attimo tutte le carte, dopodiché vengono nascoste
  2. Quando il giocatore solleva due carte uguali queste vengono lasciate scoperte e vengono assegnati dei punti
  3. Se le carte non sono uguali le ricopriamo nuovamente
  4. Per ogni coppia di carte scoperte assegniamo dei punti, determinati anche in base allo scorrere del tempo (prima si scoprono e più punti si guadagnano); diamo un punteggio maggiorato se le carte vengono trovate uguali in sequenza
  5. Una volta che tutte le carte sono state scoperte il gioco finisce

Prima di procedere oltre nello sviluppo del programma vediamo di cosa avremo bisogno (e cosa ho utilizzato):

Detto questo il risultato che vogliamo ottenere sarà simile a questo qua:

Costruiamo adesso l’idea del programma, che andremo a sviluppare come una singola classe in JavaScript che conterrà tutte le varie funzioni.

Il funzionamento lo potremmo riassumere in questo modo:

Cominciamo quindi costruendo la nostra pagina in HTML che conterrà lo script, per farla utilizziamo il prototipo base di Bootstrap nel modo seguente:

Alla riga 15 abbiamo il pezzo di codice che riguarda il contenitore del gioco, nel mio caso un div. Questa parte si ricollega a quella direttamente utilizzata nel javascript, nel file carte.js.

Affinché la classe funzioni in questo modo dobbiamo far sì che il costruttore accetti per argomento un dizionario e lo utilizzi per parametrizzare le opzioni dell’oggetto. Cominciamo quindi costruendo anche la nostra classe nel modo seguente:

Nel nostro costruttore dichiareremo le impostazioni come una variabile globale this.impostazioni = {}. Faccio notare che, a differenza di altri linguaggi di programmazione, le variabili (eccettuati i casi dei getter e dei setter) non possono essere dichiarate a livello di classe, ma esclusivamente dentro i metodi. Il prefisso this fa sì che la variabile sia globale, sebbene con alcune specifiche eccezioni che vedremo.

Implementiamo ulteriormente la classe nel modo seguente:

Per far sì che le impostazioni dell’utente si sovrappongano alle impostazioni predefinite utilizziamo l’istruzione this.impostazioni = Object.assign({},this.impostazioni,impostazioni). In questo modo uniamo i due dizionari in un nuovo dizionario vuoto e trascriviamo tutto su this.impostazioni. In questo caso è molto importante l’ordine, difatti this.impostazioni viene assegnato prima di impostazioni, dizionario che contiene la parametrizzazione a livello utente. Così le nuove impostazioni andranno a sovrascrivere quelle precedenti, creando il dizionario definitivo delle impostazioni.

Adesso andiamo a creare il metodo di caricamento nella maniera seguente:

Qui stiamo utilizzando due metodi che non abbiamo ancora dichiarato, ovvero this.creazioneStile() e this.creazioneHome(). Con this.contenitore = $(this.impostazioni.contenitore); intercettiamo il contenitore predefinito in precedenza e applichiamo, successivamente gli stili di base. Avrei potuto utilizzare anche un file CSS separato per la parametrizzazione degli stili, ma allo scopo di esercizio ho preferito fare tutto tramite JavaScript all’interno della classe stessa.

Delle istruzioni precedenti è molto importante passare l’opzione this.contenitore.css("position", "relative"); che definirà la posizione del contenitore come relativa. In questo modo potremo utilizzare internamente i riferimenti assoluti per posizionare i vari elementi. Senza la dichiarazione di posizione relativa in modo esplicito, gli elementi interni si sarebbero posizionati rispetto al primo oggetto genitore del contenitore che abbia una posizione dichiarata esplicitamente.

Per il metodo this.creazioneStile() procediamo nel modo seguente:

Sostanzialmente creiamo una sezione <style></style> all’interno del codice dentro la quale andremo ad aggiungere tutti gli stili. Per evitare sovrapposizioni esterne al contenitore anteponiamo ad ogni stile il descrittore in CSS del contenitore con this.impostazioni.contenitore. Infine aggiungiamo il gruppo di stile nell’intestazione con l’istruzione $('html > head').append(stile);

Dentro questo metodo procederemo ad aggiungere via via i vari stili di cui abbiamo bisogno.

Per il metodo this.creazioneHome() procediamo aggiungendo la seguente porzione di codice:

In questo metodo andremo a creare this.creazioneGioco() che verrà richiamato al click su START nella schermata di inizio. Quello che mi interessa in particolare durante questo passaggio è l’utilizzo di this. All’interno dell’evento click this si riferisce all’elemento oggetto del click. Di conseguenza non è più utilizzabile per riferirsi agli oggetti della classe. Per poterlo utilizzare dobbiamo riassegnarlo ad una variabile locale nel metodo genitore, come per esempio var questo = this;

In questo modo dentro l’evento di click potremo utilizzare l’istruzione questo.creazioneGioco(); che richiama un metodo della classe medesima (che dobbiamo ancora creare).

Per la creazione del gioco procediamo nel modo seguente:

Siccome il gioco potrà essere creato diverse volte, per esempio quando si riavvia durante la partita, oppure dopo che si è vinto, ci dobbiamo assicurare che tutte le variabili di gioco vengano inizializzate, ed eventualmente reimpostate, qui.

I metodi che mi interessano in particolare sono:

  1. this.carte = $.merge($.merge([], this.impostazioni.immagini), this.impostazioni.immagini); che ci consente di creare le 16 carte di cui avremo bisogno. Ricordiamoci che le carte sono in coppie quindi le 8 carte iniziali dovranno essere duplicate. Per farlo voglio unire lo stesso dizionario, dentro this.impostazioni.immagini, a se medesimo. Affinché la funzione $.merge non crei un puntatore sul vettore, continuando ad aggiungere le solite immagini ad ogni riavvio successivo e quindi scombinando il gioco, bisogna usare il trucco di chiamare il metodo con un vettore vuoto a cui viene accodato il vettore originale, con l’istruzione $.merge([], this.impostazioni.immagini). Adesso abbiamo creato un vettore completamente nuovo, che potremo poi accodare al solito vettore di prima ripetendo il passaggio una seconda volta. Se non si procede in questo modo al primo riavvio del gioco si rischieranno di avere 3 o 4 carte dello stesso tipo, perché in totale non saranno più 16 ma 32, poi 48 ecc.
  2. this.carte.sort(() => Math.random() - 0.5); che ci permette di ordinare casualmente le carte. Non è un metodo particolarmente efficiente e non produce nemmeno un livello di casualità particolarmente affidabile. Per generare una password non sarebbe quindi molto opportuno, ma per gli scopi che ci servono ai fini del gioco va benissimo, specialmente per la sua brevità di scrittura. Questa scrittura è anche la medesima di this.carte.sort(function(){ return Math.random() - 0.5; });
  3. $('#combo'+this.impostazioni.idunivoco).hide(); che nasconde il contenitore delle combo (poi vedremo meglio)
  4. for(var i = 0; i < 16; i++ ) this.creaCarta(i); che inserisce le carte nell’ordine casuale determinato dal primo punto

Procediamo adesso con la creazione del menu utilizzando this.creazioneMenu();

Faccio notare che il metodo di “restart” è praticamente identico al metodo che abbiamo visto per lo “start” nella home. Stessa procedura. Nel menu abbiamo aggiunto una voce per il punteggio corrente, una per il tempo trascorso e il tasto che consenta di ricominciare.

La creazione del timer implicherà due diversi passaggi, nella maniera seguente:

Il metodo contatoreTimer() si richiamerà su se stesso ogni 500 millisecondi su se stessa, aggiornando lo stato del gioco e dichiarando infine la conclusione dello stesso. In tale contesto andremo anche a calcolare il tempo trascorso e ad aggiornarlo nella visualizzazione.

Arriviamo adesso alla parte più importante, quella dove creiamo le carte e definiamo il funzionamento del gioco. Ricordiamoci che ogni carta dovrà essere cliccabile.

Per gestire la rotazione delle carte stiamo utilizzando jQuery Flip, che ci permette sostanzialmente di ruotare gli elementi sia manualmente che ad ogni click.

Per ogni carta, procedendo in ordine, definiamo quindi le singole proprietà di CSS e attribuiamo la caratteristica flip. Dopodiché al click su ogni carta procediamo con l’impostazione della struttura di gioco. Anzitutto verifichiamo che il gioco sia iniziato e che la carta sia cliccabile. Se la carta è giocabile e non è ancora stata aperta, apriamola con $(this).flip(false). Leggiamo il nome della carta con var cartagiocata = $(this).attr('data-nome'). Se la carta attuale non è ancora stata impostata, allora impostiamola e blocchiamo la carta con $(this).attr('data-giocabile',0). In caso contrario vuol dire che abbiamo già aperto una carta e quindi dobbiamo verificare se il risultato sia corretto o meno. Se la carta attuale è uguale a quella giocata allora vuol dire che è tutto corretto; blocchiamo quindi la carta, aumentiamo il conteggio delle carte aperte consecutivamente con questo.consecutivi++, incrementiamo il punteggio con questo.incrementaPunteggio() e conteggiamo il numero totale di carte aperte (8 coppie trovate equivale alla fine del gioco). Se le carte non sono uguali, allora diamo 800 millisecondi all’utente per poterle vedere entrambe e poi richiudiamole e reimpostiamole giocabili.

Nel suo complesso il codice che avremo creato sarà il seguente (ho incluso alcuni altri commenti specifici nel codice, per spiegare i singoli passaggi):

Per chiunque volesse cimentarsi nel gioco ne riporto di seguito anche la versione giocabile. Inutile dire che ci sarebbero ulteriori possibilità di perfezionamento e che nel gioco ci sono anche alcuni bug che accadono quando si clicca troppo rapidamente tra una carta e l’altra.

Facendo un po’ di prove per ora il meglio che sono riuscito a ottenere, senza usare sotterfugi come screenshot e simili, è stato il seguente risultato:

Vedi articolo

[wordpress] Problema video Revolution Slider 6 con Uncaught TypeError: Cannot read property ‘x’ of undefined

Problema: inserendo in Revolution Slider 6 delle slide con video in HTML5 (file mp4 nel caso particolare) lo slider non riesce ad avviarsi e provoca un loop infinito di errori nella console javascript.

Soluzione: l’errore dipende probabilmente da un altro plugin che provoca incompatibilità nel codice. Nel mio caso specifico l’errore era provocato da Enlighter – Customizable Syntax Highlighter. Disattivando il plugin lo slider torna a funzionare.

Nel caso specifico l’errore che si presenta è il seguente.

Uncaught TypeError: Cannot read property 'x' of undefined
at HTMLVideoElement.computePosition (mootools-core-yc.js?ver=3.10.0:4)
at HTMLVideoElement.setPosition (mootools-core-yc.js?ver=3.10.0:4)
at Object.R (revolution.tools.min.js?ver=6.0:46)
at Object.i._initProps (revolution.tools.min.js?ver=6.0:46)
at Object.i._init (revolution.tools.min.js?ver=6.0:46)
at Object.i.render (revolution.tools.min.js?ver=6.0:46)
at Object.i.render (revolution.tools.min.js?ver=6.0:46)
at Object.E._updateRoot.H.render (revolution.tools.min.js?ver=6.0:46)
at Object.i.dispatchEvent (revolution.tools.min.js?ver=6.0:45)
at s (revolution.tools.min.js?ver=6.0:45)

Oltre a cercare di correggere il file revolution.tools.min.js, cosa che sconsiglio caldamente, conviene verificare quali altri plugin stiano utilizzando mootools, perché probabilmente ci sono delle incompatibilità.

Disattivando il plugin in questione lo slider torna a funzionare correttamente.

Vedi articolo

[apps script] Inviare tramite Gmail un’email con allegato da Drive

Questo esempio è la prosecuzione di quanto già visto in [apps script] Inviare tramite Gmail un’email ad un elenco di contatti in Spreadsheet

Voglio apportare solo una piccola modifica al codice per inviare un allegato salvato su Google Drive a tutti i soggetti nella lista. Per i riferimenti di programmazione rimando alla pagina della guida ufficiale.

Per prelevare un file da Google Drive dobbiamo anzitutto ottenere il suo riferimento univoco. Per farlo ci sono diversi modi, nel mio esempio utilizzerò un file pdf come questo qua. Anzitutto lo carico su Drive e poi cliccandoci sopra col destro scelgo Anteprima.

Dal menu in alto a destra seleziono Apri in un’altra finestra.

A questo punto nella barra dell’indirizzo vedrò qualcosa come https://drive.google.com/file/d/1234567890abcdefghijklmnopqrstuvwxyz/view

Copio il codice alfanumerico che ho evidenziato in rosso, che è l’identificativo univoco per ciascun file. Una volta copiato vado a modificare il mio codice nel modo seguente.

In particolare con la prima istruzione aggiunta prelevo il file da Drive, cosa che richiederà dei permessi aggiuntivi.

Mentre con file.getAs(MimeType.PDF) creo il blob del file in formato PDF.

Fatto questo il mio nuovo script invia un’email a ciascun membro della lista con allegato il suddetto file.

Vedi articolo

[apps script] Aggiungere un nuovo foglio a Spreadsheet controllando quelli esistenti

Vediamo come costruire una funzione che ci permetta di creare da apps script un nuovo foglio su spreadsheet ed aggiungerlo a quelli esistenti.

Notiamo che per prendere il riferimento alla cartella esistente utilizziamo:

Il nome del foglio lo vogliamo gestire nel modo seguente: se il nome che stiamo cercando di aggiungere esiste già, allora posponiamo al nome un contatore numerico scritto come (1), (2)… (n). In pratica se esiste già un foglio chiamato Primo Foglio, allora il foglio aggiunto sarà Primo Foglio (1), se esistono entrambi sarà Primo Foglio (2) ecc.

Infine restituiamo il riferimento al foglio appena creato con:

 

Vedi articolo

[apps script] Creiamo una funzione personalizzata che esegua la somma sull’intervallo di uno Spreadsheet

Oggi vediamo come creare una funzione per Spreadsheet con Google Apps Script che permetta di sommare tutti gli elementi di un intervallo passato per argomento, al pari della funzione SUM().

Faccio notare che abbiamo usato parseFloat() su tutti i valori, in modo che se venissero passati valori non numeri la funzione restituirebbe #NUM!.

Una volta inserita la funzione nello script possiamo testarla nel modo seguente:

Vedi articolo

[apps script] Inviare tramite Gmail un’email ad un elenco di contatti in Spreadsheet

Immaginiamo di avere in Spreadsheet un elenco di indirizzi email a cui vogliamo inviare un messaggio personalizzato.

A tale scopo creiamo un nuovo file con un foglio contenente degli indirizzi nel modo seguente:

Adesso creiamo un bottone al quale collegare lo script che andremo a comporre successivamente. Per aggiungere un pulsante nel foglio di calcolo dobbiamo usare un’immagine, a differenza di quanto accadeva in Excel dove si possono inserire pulsanti da interfaccia. All’immagine assoceremo poi uno script.

Per aggiungere un’immagine andiamo su Inserisci > Immagine…

Prendiamo un’immagine dal nostro computer oppure cerchiamola su Google. Dovremmo arrivare ad una situazione come questa:

A questo punto andiamo su Strumenti > Editor di script e aggiungiamo il nostro script.

Con GmailApp.sendEmail() invieremo l’email utilizzando la nostra casella di posta, mentre con Browser.msgBox() lanceremo un messaggio di conferma delle email inviate.

Fatto questo torniamo nello spreadsheet e clicchiamo col destro sull’immagine. Vedremo comparire in alto a destra dei puntini, clicchiamoci sopra per aprire il menù contestuale.

Scegliamo Assegna script… e nella finestra inseriamo il nome della nostra funzione, ovvero InviaEmailAllaLista

Fatto questo possiamo cliccare sul nostro pulsante e testare il nostro nuovo script.

Se abbiamo fatto tutto bene riceveremo un messaggio di conferma.

Vedi articolo

[javascript] Scrivere righe, colonne e formule su Google Spreadsheet utilizzando Google Apps Script (per esordienti totali)

Oggi voglio proporre un esercizio facile facile su Google Spreadsheet, l’equivalente (si fa per dire!) G Suite a Microsoft Excel.

In Excel è possibile aggiungere macro (o script) ai fogli di calcolo utilizzando VBA, mentre Google ha implementato per il medesimo risultato gli script tramite JavaScript.

Prima di cominciare vediamo il risultato che intendiamo ottenere: creare uno script che generi tre colonne di dati, contenenti rispettivamente una sequenza di ID, un elenco di prodotti pescati casualmente da un vettore, delle quantità casuali; in fondo alla tabella vogliamo scrivere il TOTALE utilizzando una funzione di somma.

Quello di sopra è ciò che vogliamo arrivare a vedere alla fine.

Cominciamo allora subito creando un nuovo foglio, che io ho chiamato test script, poi aggiungiamo uno script andando su Strumenti > Editor di script.

A questo punto si aprirà la schermata degli script dove verrà proposta una funzione base. Cancelliamola e creiamo la nostra funzione in questo modo:

Anzitutto creiamo un oggetto collegato al foglio corrente:

Con getActiveSpreadsheet() prendiamo il riferimento alla cartella di lavoro aperta in questo momento (l’equivalente di Workbook in Excel), mentre con getSheets() prendiamo il vettore di tutti i fogli nella cartella di lavoro.

Puliamo anzitutto il foglio da precedenti contenuti con:

Adesso cambiamo il nome del foglio con:

A questo punto possiamo costruire la nostra funzione per popolare il foglio con i dati come da esempio iniziale. Integrando il tutto dovremmo ottenere qualcosa di simile a questo:

Faccio notare che la somma totale dei prodotti la facciamo con =SUM(C2:C100) che impostiamo nella cella alla riga 101 e colonna 3.

Quando abbiamo fatto tutto premiamo il tasto ESEGUI (play). Se è la prima volta che eseguiamo lo script ci verrà chiesto di autorizzarlo per accedere al foglio di lavoro dal quale siamo partiti. Concediamogli l’autorizzazione.

ATTENZIONE! Comparirà una schermata di avviso come se la connessione non fosse sicura, che ci allerterà che stiamo per eseguire uno script non sicuro, dal momento che è uno script personalizzato da noi e non verificato da Google. Clicchiamo su Avanzate e procediamo.

Se tutto è andato bene avremo eseguito il nostro primo script delle Google Apps Script. 🙂

Vedi articolo

[javascript] Disegnare sistema solare con Three.js e WebGL

Three.js è una fantastica libreria javascript per il rendering interattivo in 2D e 3D su HTML5. Qualche giorno fa mi sono trovato a voler riprodurre dei fittizi sistemi stellari ed ho deciso di riportare di seguito un esempio semplificato per chiunque volesse provare da se. Il risultato che vogliamo ottenere è il seguente (zoom con rotellina del mouse, tasto sinistro per ruotare, tasto destro per spostare):


      

Già che c’ero ho inserito anche un paio di esempi per confronto con sistemi stellari realistici: in particolare il nostro sistema solare con i suoi otto pianeti principali in proporzione, una seconda versione con i pianeti ingranditi, ma proporzionati sempre al Sole ed infine il sistema Glise 581 sempre in proporzione corretta.

Inutile dire che si tratti di una semplificazione estrema (le orbite sono circolari, anziché essere ellittiche, e giacciono tutte sul medesimo piano), ma è sufficiente a darci un’idea della vastità dello spazio. 🙂

Detto questo mettiamoci all’opera.

Anzitutto procuriamoci Three.js e, già che ci siamo, jQuery (non è indispensabile, ma mi divertirò ad unirli insieme).

Adesso creiamo il contenuto della nostra pagina index.htm

Creiamo anche un file main.css per il foglio di stile ed uno main.js per il codice javascript. 

Colleghiamo le librerie jQuery, three.min.jsOrbitControls.jsthree.interaction.js.

Infine inseriamo un div che farà da contenitore per il nostro rendering. 

Potremmo usare anche un canvas, ma Three.js ci permette di aggiungere un rendering anche al comune DOM in HTML.

Fatto tutto questo sistemiamo velocemente il CSS inserendo il seguente codice:

Inutile dire che ci potremmo divertire a personalizzarlo nei modi più disparati, ma per il momento è quanto ci basta per creare un riquadro nero di 800px di lato.

Fatto tutto questo possiamo cominciare a lavorare sullo script. Definiamo anzitutto il minimo indispensabile:

In questo modo abbiamo definito la camera, la scena (è dove aggiungeremo tutti gli oggetti), il renderer che produrrà l’elemento DOM da aggiungere al suddetto div, i controlli che ci permetteranno di muovere la telecamera rispetto alla scena e il sistema di interazione (per sviluppi futuri).

Per far funzionare il tutto creiamo una funzione chiamata init(), il nome è comunque a piacere, che lanciamo all’inizio, ed una funzione animate() che richiamiamo subito dopo.

Grazie a requestAnimationFrame( animate ) animiamo tutto il sistema. Dopo approfondiremo.

Intanto cominciamo disegnando un singolo corpo nello spazio (banalmente una sfera).

Per poter gestire l’oggetto appena creato aggiungiamolo al vettore pianeti che dichiariamo come variabile globale.

Per aggiungere un grosso oggetto al centro ci sarà sufficiente quindi usare, dentro la funzione init() alla riga evidenziata:

Gli oggetto saranno aggiunti su un piano cartesiano tridimensionale, di coordinate x, y e z. La posizione (0,0,0) è quindi all’origine degli assi del piano cartesiano. La telecamera punta direttamente verso questo origine ad una distanza sull’asse z di 10.

Proviamo ad aggiungere una seconda sfera con:

A questo punto vogliamo aggiungere anche il cerchio dell’orbita, che appunto non è altro che una circonferenza (nel nostro caso semplificato eh!):

La nostra funzione accetta come argomento il raggio dell’orbita, che sarà disegnata centrata in (0,0,0).

La circonferenza è composta di 64 segmenti che collegano altrettanti vertici. Creiamo quindi la geometria nella qual inseriamo le coordinate dei vertici, il tutto sarà poi riempito con il materiale di tipo LineBasicMaterial.

Integriamo la funzione in quella per creare i singoli pianeti, utilizzando un argomento apposito per poter decidere se aggiungerla o meno.

Con Math.sqrt(x*x + y*y) calcoliamo il raggio per ciascuna orbita, ossia la distanza del corpo sul piano xy rispetto all’origine degli assi.

Adesso proviamo ad aggiungere i seguenti pianeti:

Dovremmo poter vedere un sistema statico, simile a quello dell’esempio.

Adesso cominciamo ad animarlo, preparando anzitutto la funzione che farà ruotare i pianeti. Per farlo ruotare utilizziamo delle coordinate polari, dove ci sarà sufficiente aumentare l’angolo theta.

La funzione ruota accetta un oggetto m e un valore per la “massa”, che ci permetterà di fare variazioni sulla velocità globale del sistema. Dal momento che la velocità dei pianeti varia con l’inverso della distanza, secondo la seguente formula:

v_{o}\approx {\sqrt {{\frac {GM}{r}}}}

Possiamo approssimare il moto angolare con una variazione di theta come segue:

Quindi applichiamo il movimento per ogni singolo corpo creando una specifica funzione:

In questo modo facciamo due cose. Con:

Facciamo ruotare i corpi attorno a se stessi (rotazione).

Con:

Li facciamo ruotare attorno alla stella (rivoluzione).

Aggiorniamo infine la funzione animate():

Infine aggiungiamo lo sfondo stellato generando dei punti casuali nello spazio tutto intorno con:

Ed impostiamo la telecamera di base:

In questo modo posizioniamo la telecamere con l’inquadratura leggermente inclinata e di lato rispetto al sistema.

L’intero script che utilizziamo è il seguente:

Se abbiamo fatto tutto bene otterremo il risultato di sopra.

Vedi articolo