|
il Filetto
Chiamato anche Tris,
Tria, Tela
o Tavola Mulino, è un gioco antichissimo.
Ancor prima dei Romani, che lo chiamavano Triodo, veniva giocato in
Asia Minore centinaia d'anni prima di Cristo. Tavolieri simili a quelli del moderno
Filetto e anche più complessi, sono stati trovati,
insieme ad altri giochi, in templi Egizi.
Si gioca in due (Bianco
e Nero) con un campo di gioco sul quale sono disegnati 3 quadrati
concentrici, collegati a metà di ogni lato da una linea retta.
Esistono numerose varianti del gioco: nella versione analizzata le pedine sono
poste (alternativamente dai due giocatori) sulle intersezioni delle linee
che formano i quadrati, cercando di realizzare un Tris o Filetto, ovvero una fila
di tre pedine dello stesso colore, in orizzontale o in verticale; vince chi realizza per primo un tris
(non si fa filetto se le pedine sono in fila, ma in diagonale)
Terminate le 12 pedine a testa senza alcun tris, la partita è Pari,
ma, come vedremo, ciò non accade mai (se il primo giocatore gioca bene)
Strategia di Gioco
Per vincere occorre costruire una situazione tale da
avere più di una possibilità di tris contemporaneamente, in modo che
l'avversario non possa bloccarle.
Per scegliere la mossa migliore possiamo assegnare un punteggio ad ogni casella vuota,
in base alla situazione delle pedine sulle due linee adiacenti, inserendo tutte le possibili
combinazioni in una tabella: risulta più
conveniente giocare in una casella che massimizza la somma dei due
punteggi così calcolati
Come dimostrato dal
programma, chi gioca per primo ha una strategia vincente; il gioco quindi NON
è equo. La variante più diffusa del gioco utilizza solo nove pedine a testa,
per poi
spostarle sul campo da gioco fino a formare un tris; ad ogni tris formato
si toglie una pedina all'avversario fino a ridurlo nell'impossibilità di
giocare. In questo caso il programma dimostra che chi gioca per primo fa
sicuramente il primo tris con le prime nove
pedine (il seguito della partita ad un altro programma).
Struttura dati
int
Tavola[24] |
La tavola di gioco ( 24 nodi) viene allocata in un vettore di interi;
ogni casella vale 0 se vuota, 1 se occupata dal giocatore 1, 2 se occupata dal giocatore 2. |
int Nvuote |
Numero delle caselle vuote a disposizione |
int Who |
Giocatore che deve muovere: 1(primo) o 2(secondo) |
int DoveGioco |
mossa da fare da parte di Who
(casella da 0 a 23) |
int
QuantoVale |
valore della mossa da
fare (vista da Who):
-1 = sconfitta, 0 = pareggio, +1 = vittoria |
int
Giocatori |
Giocatori selezionati:
0 = Umano-Umano, 1 = Computer-Umano, 2
= Umano-Computer |
Algoritmo
Il programma accetta le mosse da tastiera, oppure le
sceglie tramite una funzione ricorsiva di Valutazione
Esatta.
La funzione innanzi tutto elenca tutte le mosse possibili (le caselle
vuote) assegnando a ciascuna un valore euristico (tramite la tabella PuntiMossa[
])
L'elenco delle mosse viene ordinato in base al valore, e si comincia a
provare ad una ad una tutte le mosse partendo da quella con punteggio
maggiore.
-
Se la mossa è vincente, decreta la mossa come
Mossa Migliore e interrompe la valutazione, assegnando +1 alla
posizione attuale;
-
altrimenti, se non ci sono altre caselle libere,
assegna 0 alla posizione attuale;
-
altrimenti, chiama ricorsivamente la funzione di
valutazione sulla tavola creata con la mossa: il punteggio ottenuto
(valutazione dell'avversario) verrà cambiato di segno (algoritmo
Neg-Max).
Il metodo usato per l'ordinamento delle mossa è
irrilevante ai fini del tempo complessivo.
Per migliorare le prestazioni, a sei mosse dalla fine
viene abbandonata la funzione ricorsiva, per utilizzare funzioni
particolari:
-
sei caselle vuote:
la routine elenca le caselle vuote, cercando una mossa vincente; se
non la trova, prova ad una ad una tutte le mosse, chiamando la
funzione di valutazione a 5 vuote, cui passa l'elenco delle caselle
vuote.
-
cinque caselle vuote:
la routine prova le 5 mosse, chiamando la funzione di valutazione a 4
vuote, cui passa l'elenco delle caselle vuote.
-
quattro caselle vuote:
la routine prova le 4 mosse, chiamando la funzione di valutazione a 3
vuote, cui passa l'elenco delle caselle vuote.
-
tre caselle vuote:
dapprima cerca, tra le mosse possibili, quella vincente; se non ne
trova, riprova ogni mossa con le contromosse; se la mossa crea una contromossa
vincente per l'avversario, è considerata perdente; se l'avversario non ha la mossa vincente, non
l'avrà dopo la mossa di Who.
Who occupa la prima casella M1; la scacchiera cambia per Who che potrebbe ora avere una mossa vincente, se
l'avversario non la blocca: la scacchiera è quindi vincente solo se si sono formate due mosse vincenti.
Viceversa la mossa è pari. Se non trova la vittoria, Who riprova con M2 e M3.
Alfa-Beta
Il numero dei percorsi possibili nel Filetto è
proporzionale a 24! = 1023 (circa); considerando che molti rami
si interrompono per strada, il numero dei percorsi si riduce a
"solo" 1013, ovvero alcuni mesi di calcolo sul mio
PC.
Per ridurre i tempi di
valutazione, diventa indispensabile l'adozione del taglio
Alfa-Beta, che riduce drasticamente il numero dei rami di
valutazione possibili ed è tanto più efficace quanto migliore è la
valutazione euristica preliminare: il numero dei rami è diventato dell'ordine
di 107, ovvero 30 secondi di calcolo al massimo.
Codice Sorgente in C
Per la codifica ho utilizzato il linguaggio C: il codice
riportato è per Borland BC 3.1 su DOS, ma è facilmente adattabile ad
un qualsiasi compilatore per altri S.O. (eliminare i riferimenti alla
longword 0x046C del timer e le funzioni gotoxy()).
Potete scaricare direttamente l'eseguibile di
solo 21 Kb.
L'interfaccia utente è davvero spartana, e non usa né mouse né tasti
cursore: volendo può essere arricchita (o, meglio, rifatta) da qualche
volenteroso programmatore.
Per ora, l'unico scopo del programma è di verificare la parità del
gioco.
Considerazioni finali
Il programma consente tre modalità di gioco:
-
F1 : Umano - Umano
-
F2 : Computer - Umano
-
F3 : Umano -
Computer
Il giocatore inserisce le mosse con le lettere
dell'alfabeto da A a X
(maiuscolo o minuscolo) e, al suo turno, può chiedere aiuto con il tasto F5. Il
programma è stato testato su un Athlon XP 2600 (2083 Mhz) e indica come
vincente qualsiasi prima mossa in meno di 30 secondi.
Dopo le prime tre mosse la risposta del computer è praticamente
istantanea e porta alla vittoria del primo giocatore in meno di 18 mosse.
Se il computer gioca per secondo, riconosce subito di essere perdente ma
è pronto ad approfittare di un'eventuale distrazione dell'umano.
Provando il programma su altri computer (fino a un Pentium 133), si evince
che l'unico parametro influente sul tempo di calcolo è la frequenza
di clock del processore
|