Programmazione e Divertimento: come realizzare una versione moderna del Gioco del Tris con micro:bit

Riedizione di un classico gioco elettronico realizzato in chiave moderna con la piccola scheda che rende facile imparare a programmare.

Per quanto oggi siamo letteralmente โ€œbombardatiโ€ da ogni tipo di videogame, su console, PC e smartphone, esistono giochi comunque suggestivi anche se semplici; ecco perchรฉ abbiamo deciso di proporre in chiave moderna uno dei passatempi piรน famosi al mondo: il Tris.

Un popolarissimo gioco carta e matita, o gessetto e lavagna o ancora meglio giocabile con un bastoncino sulla sabbia, fatto di poche e semplici regole, ma caratterizzato da tanti aspetti curiosi che vogliamo esporvi prima di passare al progetto.

Il gioco del Tris รจ anche noto in Italia come crocetta e pallino, filetto, cerchi e croci, oppure con simboli del tipo OXO o XOXO che riprendono direttamente i simboli utilizzati nel gioco; considerando che รจ universale, in altre parti del mondo รจ noto con altri nomi, per esempio negli Stati Uniti si chiama tic-tac-toe (oppure tick-tat-toe e tit-tat-toe); in Inghilterra รจ โ€œnoughts and crossesโ€ (zero e croci); in Francia si chiama Morpion (piattola); in Spagna ta-te-ti, tres en raya, gato, equis cero.

Alcune ricerche sostengono che giochi simili fossero giร  diffusi nellโ€™antico Egitto e al tempo dei Romani in cui esisteva un gioco chiamato โ€œterni lapilliโ€ – utilizzato tra i soldati – in cui perรฒ, non venivano usati gli stessi simboli di oggi (X e O).

Il Tris deve sicuramente la sua notorietร  e longevitร  negli anni alla semplicitร  delle sue regole, infatti nella sua accezione piรน generale si gioca su una griglia quadrata di 3×3 caselle e allโ€™inizio del gioco un giocatore sceglie come simbolo una โ€œXโ€, mentre lโ€™avversario un โ€œOโ€ (cerchio); dopodichรฉ a turno, i giocatori scelgono una casella vuota e vi disegnano il proprio simbolo.

Vince il giocatore che riesce a disporre tre dei propri simboli in linea retta orizzontale, verticale od obliqua; per quanto, molto spesso le partite terminano con un pareggio (soprattutto se i giocatori non sono giovanissimi), infatti se la griglia viene riempita senza che nessuno dei giocatori sia riuscito a completare una linea retta di tre simboli, il gioco finisce in paritร  e come accade in altri giochi, tanto per citarne uno quello degli scacchi, nel caso in cui il gioco finisse in paritร , la partita รจ detta โ€œpattaโ€.

Avendo un numero ridotto di situazioni in cui ci si puรฒ trovare a giocare e una griglia 3×3, รจ possibile implementarlo in un programma per microprocessore o microntrollore, come abbiamo fatto.

Vedremo a breve lโ€™implementazione su Microbit che tuttavia non sarร  fatta con un giocatore โ€œumanoโ€ contro Microbit ma per semplificare ulteriormente lโ€™implementazione ed evitare di confrontarsi con un dispositivo che non perderร  mai una partita, abbiamo pensato di realizzare il gioco del Tris con una doppia partecipazione umana, ovvero come in origine con carta e matita.

l’hardware per il tris con micro:bit

Prima di passare allโ€™implementazione software, vediamo il necessario hardware per la corretta gestione di questo progetto, dove utilizziamo micro:bit e un display LCD da 1.8 pollici della Waveshare Electronics mostrato in Fig. 1.

Fig. 1 La scheda micro:bit con applicato il display LCD

 

Questo display รจ facilmente assemblabile perchรฉ ha solo ed esclusivamente il connettore dโ€™interfaccia da collegare al micro:bit e nullโ€™altro, in piรน offre unโ€™ampio display se confrontato con altre soluzioni simili e il driver per la sua gestione รจ direttamente su scheda.

Sulla scheda del display LCD รจ incorporato il controller a interfaccia SPI (Serial Peripheral Interface): si tratta di un chip Sitronix ST7735S che permette di pilotare 162 e 132 canali RGB al fine di abilitare o disabilitare qualsiasi pixel del display LCD.

Tramite il protocollo di comunicazione SPI o con unโ€™interfaccia parallela da 8bit a 18bit รจ possibile comunicare con un microprocessore esterno e salvare i dati nella memoria RAM disponibile di 132x168x18 bit.

Il controller consente anche di minimizzare i consumi energetici realizzando operazioni di scrittura/lettura senza alcun clock (segnale di temporizzazione) esterno, ma per maggiori dettagli si faccia riferimento al sul datasheet scaricabile on-line.

Per quanto lโ€™architettura del sistema sembri semplice, le tecnologie di micro:bit e del display LCD mascherano la complessitร  astraendo mediante varie librerie software la complessitร  dellโ€™hardware

Le librerie per micro:bit

A questo punto passiamo direttamente allโ€™implementazione software del sistema.

Tra i software utilizzabili, abbiamo deciso di utilizzare la piattaforma Make Code Block e di importare le librerie messe a disposizione dal produttore del display, per avere tutte le sue funzionalitร  immediatamente utilizzabili.

Procedendo per ordine, vediamo come aggiungere tali librerie al programma, con riferimento alla Fig. 2: innanzitutto dallโ€™interfaccia utente bisogna cliccare sul pulsante a forma dโ€™ingranaggio e poi, dal menu cui dร  accesso, cliccare su โ€œEstensioniโ€ (a); nella finestra cui accederete digitate il path https://github.com/waveshare/PXT-WSLCD1in8 (b) ed infine aggiungete la libreria LCD1in8 dedicata a micro:bit v2.

Fatto ciรฒ, la nuova libreria LCD1IN8 comparirร  nel pannello principale (c).

Fig. 2 Aggiunta Librerie

 

Prima di procedere oltre รจ opportuno conoscere le funzioni della libreria che utilizzeremo, per interagire correttamente con il display e che รจ possibile visionare dalla piattaforma di sviluppo tramite un click sul nome della libreria LCD1IN8.

Vediamo quali sono le varie funzioni e i parametri da definire:

  • LCD1IN8 Init: consente di inizializzare il display;
  • Clear Drawing cache: cancella tutti i dati in RAM;
  • Filling Color: consente di definire il colore di background del display;
  • LCD Clear: cancella i dati in RAM mostrati su display;
  • Show Full Screen: aggiorna il display con i dati disponibili in memoria RAM;
  • Set back light level: definisce il livello di intensitร  luminosa della retroilluminazione;
  • Draw Point: consente di scrivere in memoria RAM le informazioni relative ad un โ€œpuntoโ€ del quale devono essere definiti i seguenti parametri: coordinata x, y, colore, dimensioni del punto tramite un menรน a tendina;
  • Draw Line: consente di scrivere in memoria RAM le informazioni relative ad una linea attraverso la definizione di due punti: coordinata โ€˜xโ€™ iniziale, โ€˜yโ€™ iniziale, โ€˜xโ€™ finale, โ€˜yโ€™ finale, (si aggiungono anche: colore, dimensioni e spessore della linea tramite un menรน a tendina);
  • Draw Rectangle: consente di scrivere in memoria RAM le informazioni relative ad un rettangolo del quale devono essere forniti i vertici estremi in termini di coordinate x e y: coordinata โ€˜xโ€™ iniziale, โ€˜yโ€™ iniziale, โ€˜xโ€™ finale, โ€˜yโ€™ finale, (altre informazioni che รจ necessario definire sono: colore, il tipo di riempimento del rettangolo, spessore della linea tramite un menรน a tendina);
  • Draw Circle: consente di scrivere in memoria RAM le informazioni relative ad un cerchio del quale devono essere forniti il centro in termine di coordinate x, y ed il raggio: coordinata โ€˜xโ€™, โ€˜yโ€™, raggio, (in piรน: colore, il tipo di riempimento del cerchio, spessore della linea tramite un menรน a tendina);
  • Show Number: consente di scrivere in memoria RAM le informazioni relative ad un numero del quale deve essere fornita la posizione in termine di coordinate x, y ed il colore: coordinata โ€˜xโ€™, โ€˜yโ€™, colore;
  • Show String: consente di scrivere in memoria RAM le informazioni relative ad un carattere del quale deve essere fornita la posizione in termine di coordinate x, y ed il colore: coordinata โ€˜xโ€™, โ€˜yโ€™, colore.

La logica

Il progetto, per quanto semplificato a livello hardware richiede unโ€™importante implementazione dal punto di vista software, per cui risulta fondamentale descrivere le logiche di implementazione; per facilitarne la comprensione รจ buona norma realizzare un flow-chart (diagramma di flusso) che nel caso specifico รจ mostrato in Fig. 3.

Fig. 3 Diagramma di flusso Gioco Tris

 

La prima fase del programma consiste nellโ€™inizializzazione del display e delle variabili che verranno descritte nel successivo capitolo cosรฌ da migliorare la lettura del programma.

Il successivo blocco di โ€œTrisGame Initโ€ riguarda le prime istruzioni che guideranno lโ€™utente nella gestione della partita e a tale scopo utilizziamo come riferimento la Fig. 4, che esemplifica ciรฒ che verrร  mostrato dal display.

Fig. 4 Inizializzazione del gioco Tris

 

Il display รจ composto da 160×128 pixel pertanto qualsiasi dato puรฒ essere interpretato come la successione di โ€˜nโ€™ pixel con il fine di mostrare una parola oppure una figura.

Quindi la prima fase del gioco consiste nel mostrare la stringa โ€œTris GAMEโ€ e nel guidare lโ€™utente nella successiva azione, ovvero la pressione del โ€œtasto Aโ€ presente su Microbit. Alla pressione di tale tasto seguono i vari blocchi di inizializzazione partita che consistono nella definizione e scrittura su display della griglia del Tris, del selettore e della prima pedina.

La griglia sarร  composta da nove riquadri (come vedevamo prima una griglia 3×3) allโ€™interno dei quali il selettore (indentificato da un pallino nero) potrร  navigare per definire la successiva posizione della pedina.

Con la pressione del tasto โ€œAโ€ si avrร  quanto riportato in Fig. 5.

Fig. 5 InizializzAazione della partita

 

A questo punto il programma attende la successiva azione utente che consiste nello spostare il selettore e definire la successiva posizione.

La micro:bit rende disponibili due tasti che utilizzeremo per la movimentazione del selettore e il logo touch per confermare lโ€™inserimento della pedina. Il tasto A verrร  utilizzato per il movimento verticale mentre il tasto B per il movimento orizzontale che saranno di tipologia endless (senza fine) cosรฌ da garantire la completa movimentazione allโ€™interno della griglia.

Come visto nellโ€™introduzione, il gioco del Tris si basa sullo scambio di azioni utente che posizionano le loro pedine al fine di realizzare il Tris ovvero tre pedine consecutive in orizzontale, verticale o diagonale.

Pertanto il turno รจ inizializzato dal player 1 che sposta il selettore tramite i tasti A e B nella posizione desiderata e conferma lโ€™inserimento della pedina tramite il logo touch.

Terminata questa operazione, il programma deve controllare se esistono le condizioni di vittoria altrimenti passa il turno al secondo player che potrร  inserire la sua pedina e cosรฌ via.

Le condizioni di vittoria sono indentificate nella Fig. 6 e vengono verificate ogni qual volta una nuova pedina รจ inserita.

I numeri associati ad ogni casella vengono utilizzati per rendere piรน intuiva e semplice la lettura delle combinazioni e torneranno molto utili in fase di implementazione software.

 

Fig. 6 Possibili combinazioni di vittoria partita

 

Le linee tratteggiate indicano la sequenzialitร  delle caselle e quindi di una condizione di vittoria che puรฒ essere interpretata come combinazione di numeri, ad esempio la linea arancio orizzontale rappresenta la sequenza numerica 0-3-6. Quando le condizioni di vittoria sono verificate, con una delle 8 possibili soluzioni vittoria, la partita puรฒ ritenersi conclusa e sul display verrร  mostrato il testo con il vincitore (Fig. 7) altrimenti la partita terminerร  con un pareggio.

 

Fig. 7 Fine Partita

Implementazione del software per micro:bit

Passiamo alla scrittura del codice tramite la piattaforma di sviluppo Make Code Block analizzando passo-passo le funzioni realizzate in linea con il diagramma di flusso mostrato precedentemente in Fig. 3.

Le prime funzioni realizzate sono eseguite allโ€™interno della funzione avvio e riguardano i blocchi di inizializzazione display (Display Init), variabili (Variables Init) e gioco del Tris (TrisGame Init).

Per comprendere al meglio le funzioni implementate, utilizziamo come riferimento la Fig. 8 che mostra alcuni parametri molto importanti per la comprensione delle logiche che andremo a descrivere.

Fig. 8 I parametri relativi alle logiche

 

La creazione della griglia e della pedina si basa sulla definizione delle coordinate x, y che verranno utilizzate come parametri delle funzioni โ€œdisplayโ€:
xI, yI โ€“ indicano le coordinate del pixel dal quale verrร  creata la griglia;
xPx, yPy โ€“ indicano le coordinate del pixel dal quale verrร  creata la pedina;
xSx, ySy โ€“ indicano le coordinate del selettore;
dim โ€“ rappresenta la dimensione in termini di pixel di ogni quadrante della griglia;
offset โ€“ indica il numero di pixel che distanziano la pedina dalla griglia;

Per facilitare la comprensione del testo utilizzeremo il carattere corsivo per le variabili e il grassetto-corsivo per le funzioni.

Inizializzazione del progetto

Riportiamo in Fig. 9 la lista di variabili che andremo ad utilizzare successivamente e le funzioni adottate:

  • Variabili black, blue, white, red e green verranno utilizzate per definire il colore delle pedine e del selettore;
  • Variabili _dim e offset_pedina le abbiamo giร  descritte;
  • Variabili S_base_x e S_base_y sono le coordinate del primo pixel dal quale verrร  creata la griglia del Tris;
  • Le funzioni set_pawn_position, set_selector_position, set_win_position verranno analizzate nel dettaglio;
  • LCD1IN8 Init e Clear Drawing Cache sono funzioni della libreria del display descritte precedentemente, che consentono di configurare i registri interni del dispositivo e di cancellare ogni possibile dato nella memoria volative del display;

Fig. 9 Inizializzazione del gioco

 

Infine utilizziamo la funzione Show String per visualizzare i dati come mostrato nella Fig. 4.

Le funzioni hanno lo scopo di salvare in memoria i dati relativi alle possibili 9 posizioni di pedina e selettore, ma anche le possibili combinazioni di vittoria.

Cominciamo dalla funzione set_pawn_position, in riferimento alla Fig10a, che richiede i parametri start_x, start_y, dim e offset; questi in fase di chiamata verranno identificati rispettivamente con le coordinate della griglia (S_base_x e S_base_y), con la dimensione del quadrante griglia (_dim) ed infine con lโ€™offset_pedina.

Perciรฒ definiamo la funzione e quindi la creazione delle variabili:
S_pos_x2, S_pos_y2 tengono conto della posizione della griglia e dellโ€™offset della pedina;
la lista list_pos_pawn sarร  riempita con le coordinate della pedina, le quali nella Fig. 8 sono scritte in blu relativamente al pixel per la creazione della pedina per ogni quadrante.

La funzione set_selector_position di Fig. 10 (รจ evidenziata dalla lettera b) utilizza lo stesso metodo della funzione set_pawn_position (a) con la differenza che le coordinate in questione saranno identificate al centro di ogni quadrante come indicato dalle frecce rosse di Fig. 8.

Lโ€™ultima funzione set_win_position (la c in Fig. 10) ha lo scopo di raccogliere in un unico array combo_win le possibili combinazioni vittoria con sequenze di tre elementi consecutivi ed in linea con la descrizione definita precedentemente.

Fig. 10 Funzioni di Init

Inizio del gioco

In linea con il diagramma di flusso descritto, attendiamo lโ€™azione utente e quindi la pressione del tasto A che dal punto di vista implementativo si traduce nel trascinare la funzione quando premi pulsante A presente nella sezione Fondamentali e definire una macchina a stati; questโ€™ultima risulta necessaria in quanto, come dicevamo, il tasto A verrร  utilizzato anche per spostare il selettore.

Con riferimento alla Fig. 11 eseguiamo quanto segue.

Fig. 11 Avvio del gioco

 

Aggiungiamo allโ€™interno della sezione relativa alla pressione tasto un if-else con argomento la variabile btn_A_sts, che in corrispondenza della pressione del tasto A avrร  valore 0 e pertanto porterร  allโ€™incremento della medesima variabile e della variabile system_sts che rappresenta lo stato del sistema come suggerisce il nome.

Da questo momento in poi, le successive pressioni del tasto andranno ad identificare lo spostamento verticale del selettore che andremo ad analizzare in seguito.

In parallelo la funzione per sempre risulta sempre attiva pertanto risulta necessario, tramite un blocco di if-else con variabile system_sts, assegnare una prioritร  alle operazioni da effettuare.

Alla pressione del tasto A, la variabile system_sts assume valore 1 con conseguente creazione della griglia (create_game_base), dopo aver ripulito il display dai dati visualizzati.

Al successivo incremento della variabile system_sts viene creato il selettore e mostrato sulla matrice led del Microbit il numero 1 per indicare il turno del giocatore.

Per la creazione della griglia la funzione create_game_base richiede tre argomenti identificati dalle coordinate e dalla dimensione del quadrante. Come in Fig. 5, decidiamo di utilizzare la libreria del display Draw Line e quindi nella definizione di due punti (quattro coordinate) per ogni linea con lo scopo di rappresentare la griglia attraverso quattro linee.

Tra i parametri occorre:

  • impostare Color a 0 (indicativo del colore nero);
  • impostare Width al valore DOT_PIXEL_2 cosรฌ da definire una linea piรน spessa;
  • impostare Style a LINE_SOLID al fine di definire una linea continua.

Procediamo nella realizzazione del selettore con la funzione create_selector e quindi nellโ€™utilizzo della funzione Draw Point (Fig. 12) che non richiede particolari processi implementativi ma lโ€™assegnazione delle corrispondenti variabili e la dimensione del punto Point Size al valore DOT_PIXEL_4.

 

Fig. 12 Creazione di griglia e selettore

 

In fase di chiamata funzione รจ importante esplicitare le coordinate del punto che dovrร  posizionarsi al centro del riquadro (_dim/2) ed il colore che dovrร  essere assegnato alla variabile blu inizialmente dichiarata.

Spostamento del selettore

Con lโ€™implementazione e la creazione del piano di gioco, il sistema rimane in attesa della successiva azione utente che spetterร  al giocatore 1 il quale potrร  spostare il selettore tramite i tasti A e B della micro:bit.

La nuova posizione del selettore viene definita attraverso quattro variabili che hanno la funzione di identificare le nuove coordinate x e y (pos_x_selector, pos_y_selector) ed avere memoria anche di quelle precedenti tramite pos_x_prev_selector e pos_y_prev_selector.

In corrispondenza della pressione tasto A andremo a salvare le attuali coordinate e incrementare (+1) la coordinata y per la movimentazione verticale; la pressione del tasto B implementa le stesse funzionalitร  con la differenza che la variabile da aggiornare (+1) sarร  la coordinata x (Fig. 13).

Se lโ€™incremento eccede del valore 2 per entrambe le coordinate allora verrร  assegnato il valore 0 cosรฌ da simulare la movimentazione endless.

Fig. 13 Posizionamento selettore

 

Lโ€™aggiornamento delle variabili appena descritte determina lโ€™aggiornamento della posizione del selettore, come mostrato in Fig. 14 attraverso la funzione refresh_selector_pos.

 

Fig. 14 Aggiornamento Posizione Selettore

 

Se ricordate, in Fig. 10 (punto b) abbiamo descritto la funzione che consente di creare e riempire la variabile globale list_pos_sel con le possibili coordinate del selettore definendo una lista di 9 elementi contenenti le coordinate x ,y che a questo punto andiamo ad utilizzare allโ€™interno della nostra funzione, tuttavia per comprendere al meglio la logica da implementare consideriamo la Fig. 15.

Fig. 15 Ricerca posizione

 

List_pos_sel puรฒ essere schematizzato come mostrato, mentre le variabili precedentemente definite pos_x_prev_selector, pos_y_prev_selector, pos_x _selector e pos_y _selector possono assumere i valori da 0 a 2 come evidenziato per la griglia base del Tris, pertanto รจ possibile risalire agli elementi della lista sfruttando la relazione coordinata_x * 3 + coordinata_y che lega un oggetto monodimensionale con un altro bidimensionale quale la matrice.

Supponendo che pos_x _selector e pos_y _selector abbiano entrambi valore 1 (coordinata xS4, yS4), il risultato della relazione sarร  4 che trova corrispondenza nella lista list_pos_sel. Quindi ritornando allโ€™ implementazione di Fig. 14 e facciamo quanto segue.

Creiamo lโ€™array get_previous_value che dovrร  contenere gli elementi x,y della lista list_pos_sel in corrispondenza del risultato della relazione definita tramite le variabili pos_x_prev_selector e pos_y_prev_selector. La funzione leggi valore allโ€™indice รจ disponibile allโ€™interno della sezione Array.

Utilizziamo la funzione create_selector (precedentemente descritta) che riceve le coordinate contenute in posizione 0 e 1 del vettore get_previous_value ed il colore associato alla variabile white con lo scopo di andare a rimuovere quella che era la posizione precedente del selettore.

Creiamo lโ€™array get _value che dovrร  contenere gli elementi (x,y) della lista list_pos_sel in corrispondenza del risultato della relazione definita tramite le variabili pos_x_selector e pos_y_selector.

Utilizziamo la funzione create_selector che riceve le coordinate contenute in posizione 0 e 1 del vettore get _value ed il colore associato alla variabile blu con lโ€™intento di aggiornare e quindi scrivere su display la nuova posizione del selettore.

Conferma della posizione della pedina

Quando il giocatore di turno decide, tramite il selettore, la successiva posizione che la pedina dovrร  assumere, dovrร  confermare tale posizione tramite la pressione del logo touch che illustreremo a display attraverso lโ€™implementazione proposta nella Fig. 16.

 

Fig. 16 Conferma Inserimento pedina

 

Sempre nella sezione Fondamentali รจ possibile trascinare il blocco relativo alla funzione del logo e cosรฌ procedere con lโ€™operazione di scrittura su display della corrispondente pedina e nella valutazione delle possibili condizioni vittoria.

Per valutare le condizioni di fine partita dopo lโ€™inserimento di una pedina, รจ necessario avere memoria delle posizioni occupate dalle pedine di entrambi i giocatori.

Dal punto di vista implementativo, procediamo con la creazione della variabile index_sel che รจ indicativa della successiva posizione x,y della pedina tramite la relazione coordinata_x * 3 + coordinata_y e della variabile status_pawn_refresh che assume il valore di ritorno della funzione refresh_pawn_pos che consente di verificare se รจ possibile aggiungere la pedina in corrispondenza della posizione del selettore come evidenziato in Fig. 17.

 

Fig. 17 Conferma inserimento pedina

 

La funzione consiste nella creazione di due vettori che indicheremo con pos_pawn1_busy e pos_pawn2_busy e che hanno lo scopo di tenere traccia delle posizioni (in termini di index_sel) per la pedina del giocatore 1 e del giocatore 2 e quindi:

  • aggiungiamo il blocco di if-else per valutare il turno del giocatore;
  • verifichiamo se il vettore pos_pawn1_busy contiene elementi tramite la funzione lunghezza array disponibile nella sezione Array e successivamente tramite un ulteriore โ€œifโ€ verifichiamo che neanche il secondo vettore pos_pawn2_busy contenga la posizione index_sel.; la funzione restituisce il valore 0 se index_sel รจ presente nel vettore pos_pawn2_busy altrimenti aggiunge index_sel in coda al vettore pos_pawn1_busy e restituisce (return) il valore 1;
  • nel caso in cui il vettore pos_pawn1_busy contenga giร  elementi al suo interno, andiamo a valutare se index_sel รจ giร  presente nei due vettori tramite la funzione trova indice di disponibile nella sezione Array e restituisce il valore 1 se lโ€™elemento non รจ presente aggiungendolo index_sel in coda al vettore pos_pawn1_busy altrimenti restituisce il valore 0;
  • medesime considerazioni possono essere implementate anche per il secondo giocatore utilizzando il vettore pos_pawn2_busy come mostrato in Fig. 17.

In base al valore restituito e al turno del giocatore riconsideriamo lโ€™implementazione di Fig. 9, dove attendiamo che una nuova pedina venga inserita (status_pawn_refresh == 1) cosรฌ da estrarre le coordinate dalla lista list_pos_pawn sulla base dellโ€™ultimo index_sel aggiunto nella lista pos_pawn1_busy per il giocatore 1 oppure pos_pawn2_busy per il giocatore 2.

Le coordinate vengono assegnate alla variabile get_value e sulla base dei valori x e y presenti allโ€™indirizzo 0 ed 1 viene creata la pedina tramite la funzione create_pawn ed associato il colore rosso nel caso del giocatore 1 ed il colore verde per il giocatore 2.

Dopo la creazione della pedina, cambia il turno del giocatore tramite la variabile player_turn ed il numero mostrato sulla matrice di LED.

Verifica del fine gioco

Dopo aver ultimato la valutazione della posizione index_sel allโ€™interno dei vettori pos_pawn1_busy e pos_pawn2_busy ed aggiunto la nuova pedina in base al turno del particolare giocatore, รจ necessario procedere con la valutazione delle condizioni di gioco definite allโ€™interno della funzione verify_end_conditions definita in Fig. 18; tramite essa andremo a valutare se sussistono le condizioni di pareggio o vittoria giocatore 1 o giocatore 2 sulla base delle possibili combinazioni di vittoria.

 

Fig. 18 Verifica condizioni fine partita

 

Il primo passo รจ la creazione della variabile game_sts alla quale verrร  assegnato il valore di ritorno della funzione check_win_conditions, che avrร  il compito di verificare le condizioni di vittoria in base allโ€™implementazione definita in Fig. 19.

 

Fig. 19 Verifica condizioni di vittoria

 

La prima verifica della funzione check_win_conditions รจ analizzare i vettori pos_pawn1_busy e pos_pawn2_busy ed in particolare verificare che il numero di elementi sia pari a 9 come il numero di quadranti della griglia; in tal caso verrร  restituito il valore 0.

Se la prima condizione non รจ rispettata allora รจ necessario verificare che gli elementi dei vettori pos_pawn1_busy e pos_pawn2_busy non contengano una delle combinazioni vittoria definiti (in Fig.10c) tramite il vettore combo_win (con elementi index_sel), che raggruppati in sottoinsiemi di 3 elementi definiscono le combinazioni di vittoria.

Creiamo la variabile win_condition_sts che dovrร  essere inizializzata al valore 255 ed aggiungiamo la funzione ripeti disponibile nella sezione Cicli per esaminare ogni elemento del vettore combo_win. In linea con la struttura del vettore, aggiungiamo un blocco if-else con due seguenti condizioni:

  • la prima valuta che lโ€™indice i del vettore combo_win sia multiplo di 3, indicando lโ€™inizio di un nuovo insieme di elementi; aggiungiamo la funzione resto di disponibile nella sezione Matematica;
  • la seconda si basa sulla valutazione della variabile win_set_index_pawn1, che consente di proseguire con la valutazione del sotto-insieme se una precedente corrispondenza รจ stata riscontrata.

Lo scopo principale della funzione รจ confrontare ogni elemento di una possibile combinazione vittoria con gli elementi del vettore che tengono memoria delle posizioni occupate in termini di index_sel, per ogni giocatore.

Aggiungiamo un blocco ripeti con indice j da 0 alla lunghezza del vettore pos_pawn1_busy, per il giocatore 1 e tramite un blocco if-else, verifichiamo che lโ€™i-esimo elemento del vettore combo_win sia uguale al j-esimo elemento del vettore pos_pawn1_busy.

Se non esiste alcuna occorrenza allora si attende il successivo indice del vettore combo_win multiplo di 3, altrimenti la variabile win_set_index_pawn1 viene aggiornata (+1), interrotto il ciclo โ€œforโ€ tramite un break e si prosegue con la valutazione del successivo elemento allโ€™interno del sottogruppo di 3 elementi. Analoga implementazione deve essere fatta per il giocatore 2 e le variabili interessate come win_set_index_pawn2.

Sempre allโ€™interno del ciclo โ€œforโ€ del vettore combo_win, creiamo la variabile index_check_win che verrร  incrementata di 1 per ogni i-esimo elemento di combo_win ed aggiungiamo un blocco if-else che controllerร  il valore di index_check_win uguale a 3, indicando la fine di un sottoinsieme di combinazione vittoria.

Allโ€™interno del blocco, azzeriamo la variabile index_check_win e verifichiamo il contenuto delle variabili win_set_index_pawn1 e win_set_index_pawn2.

Se il valore รจ inferiore a 3, allora si procederร  con il reset al valore zero, altrimenti verrร  aggiornata la variabile win_condition_sts al valore 1 per il giocatore 1 oppure al valore 2 per il giocatore 2, con conseguente interruzione del ciclo โ€œforโ€ (break) e ritorno (return) della variabile win_condition_sts.

Ritornando allโ€™implementazione di Fig. 18, in base al valore della variabile game_sts e quindi al valore restituito dalla funzione check_win_conditions, andiamo a visualizzare su display lโ€™esito della partita. Il primo blocco if-else verifica che il valore della variabile sia diverso da 255 mentre il successivo if-else analizza il risultato della partita ed in particolare:

  • se il valore di game_sts รจ 0 allora saranno presenti le condizioni di pareggio e la variabile str_sts_game verrร  impostata al valore โ€œTIEโ€ e mostrato sulla matrice led del Microbit la lettera T;
  • se il valore di game_sts รจ 1 allora il giocatore 1 avrร  vinto la partita e la variabile str_sts_game verrร  impostata al valore โ€œGIOCATORE 1 WINโ€ e mostrato sulla matrice led del Microbit la lettera W;
  • se il valore di game_sts รจ 2 allora il giocatore 2 avrร  vinto la partita e la variabile str_sts_game verrร  impostata al valore โ€œGIOCATORE 2 WINโ€ e mostrato sulla matrice led del Microbit la lettera W.

Al termine deve essere utilizzata la funzione display Show String con argomento la variabile str_sts_game seguita da Show Full Screen per mostrare su display lโ€™esito della partita.

โ€ฆ E ORA SI GIOCA!

Completata la definizione dei blocchi e quindi lโ€™implementazione software, รจ il momento di giocare. Alcune fasi di gioco sono riportate nella Fig. 20.

Fig. 20 Presentazione gioco del Tris

 

Qui vedete le fasi piรน importanti dellโ€™implementazione descritte nei precedenti paragrafi:

  • in (a) sono mostrate le prime informazioni mostrate su display allโ€™avvio con le indicazioni che lโ€™utente dovrร  seguire (pressione del tasto A) per iniziare la partita;
  • in (b) รจ proposto il risultato dopo la pressione del tasto con la creazione della griglia del gioco Tris ed il posizionamento del selettore;
  • in (c) e in (d) vedete le pedine per il giocatore 1 e 2 dopo la pressione del logo touch.

Infine la Fig. 21 mostra una situazione di fine partita con la vittoria del giocatore 1.

Fig. 21 Fine partita gioco del Tris

Conclusioni

Vi abbiamo guidato nella realizzazione della riedizione โ€œdigitaleโ€ dello storico gioco del Tris, partendo dalla presentazione del display LCD lato hardware e tutta lโ€™implementazione lato software, spiegando nei minimi dettagli tutte le fasi, le funzioni e le variabili utilizzate, per dare lโ€™idea della facilitร  di realizzazione e di utilizzo della scheda micro:bit; infatti permette, attraverso le sue librerie, di astrarre lโ€™utente dalla complessitร  hardware, agevolando soprattutto lโ€™informatizzazione dei giovani/giovanissimi, avvicinandoli cosรฌ al mondo dellโ€™elettronica.

Buon divertimento con questo gioco e con micro:bit.

Lascia un commento

Il tuo indirizzo email non sarร  pubblicato.

Menu