Strategie evolutive
torneo singolo: spiegazioni

Come configurare le strategie

Per configurare le strategie, bisogna modificate il file partecipanti.js che viene fornito assieme a tutti gli altri file nel pacchetto .ZIP alla pagina di download.
Nel file si possono configurare:
1. numero partecipanti al torneo
2. numero mosse per ogni partita
3. strategie di gioco dei partecipanti

Aprite il file con un editor di testo (Notepad o simili), troverete subito due parametri:

tot=7; // numero partecipanti
cicli=20; // numero mosse per partita

per togliere o aggiungere partecipanti, basta modificate il primo numero (di default è 7).
per aumentare il numero di giocate per partita basta modificate il secondo numero (di default è 20), ma state attenti a non sovracaricare troppo il vostro PC.

Vediamo in dettaglio il primo partecipante al torneo:

spiega[1]="strategia che collabora, a meno che l'altro non abbia defezionato";
nome[1] = "Tit for Tat";
DNA[1] = "AAATTTAG";

Tutti i parametri racchiusi tra "virgolette" sono modificabili.
La voce: spiega è la spiegazione che appare nelle tabelle riassuntive del torneo, nome è il nome della strategia, il DNA fornisce i dati delle caratteristiche.

La variabile DNA (dall'inglese DeoxyriboNucleic Acid), è liberamente ispirata al DNA reale e sono usate le lettere:
A = adenina
T = timina (solo per il DNA)
U = uracile (solo per l'RNA)
C = citosina
G = guanina
che normalmente indentificano i nucleotidi, per indicare gli stati possibili.

Prima tripletta del DNA

Prendiamo come esempio la prima strategia Tit for Tat.

La prima lettera indica il colore nella tabella (AAATTTAG)
A=verde sono strategie molto buone,
T=rosso sono strategie molto cattive
C=giallo sono strategie tendenzialmente buone, ma non sempre,
G=arancione sono strategie tendenzialmente cattive, ma non sempre
Nulla vieta di configurare i colori senza considerare le indicazioni.

La seconda lettera viene usata solo per i tornei a generazioni (AAATTTAG)
Per riconoscerla subito, è stata usata la lettera U (nomrmalmente presente nell'RNA) per indicare che la strategia è stata mutata dopo essersi estinta, qualsiasi altra lettera (A,T,C,G) che è una strategia originale impostata da noi in questo file. Non usato per il torneo singolo.

La terza lettera indica la prima giocata (AAATTTAG)
A=collabora, la strategia inizia sempre la partita collaborando
T=collabora, la strategia inizia sempre la partita collaborando
C=defeziona,la strategia inizia sempre la partita defezionando
G=casuale, la strategia inizia la partita in modo casuale

Seconda tripletta del DNA

Il gruppo che va dalla quarta alla sesta lettera, indica la strategia che seguirà il partecipante durante il gioco (AAATTTAG)
Ogni strategia corrisponde a un partecipante, ed è configurata subito sotto le linee che abbiamo appena visto:

function tit_for_tat ()
{
// gene TTT

if (attenzione=="A"){
if (giocoB1==0){giocoA=0}
else {giocoA=1}
}
else {
if (giocoA1==0){giocoB=0}
else {giocoB=1}
}
}

Ora bisogna entrare in dettaglio al funzionamento di un JavaScript, ma è abbastanza semplice:
Questa funzione è la stessa parte del programma che si attiva sia se la strategia gioca una partita come partecipante A, sia che la giochi come B (es A=1 contro B=2 oppure A=5 contro B=1).
La variabile chiamata "attenzione" semplicemente si attiva nel caso Tit for Tat sia il partecipante A, dicendo: Se Tit for tat è il partecipante A allora fai tutto quello che è racchiuso tra queste parentesi graffe:

if (attenzione=="A"){

altrimenti fai quello che è racchiuso tra queste altre

else {

Consideriamo il caso che Tit for Tat sia il giocatore A, troviamo un'altra condizione:

if (giocoB1==0){giocoA=0}
else {giocoA=1}

gioco B1 è la variabile che contiene la mossa precedente dell'avversario, se è uguale a 0 (giocoB1==0), significa che aveva defezionato, quindi per la mossa attuale che è contenuta nella variabile giocoA, Tit for Tat gioca 0 defezionando {giocoA=0}.
in tutti gli altri casi else l'avversario non aveva defezionato (quindi aveva collaborato giocando 1) e Tit for Tat gioca allora 1 collaborando a sua volta {giocoA=1}.
Anche le altre strategie sono impostate con una serie di condizionali if, e funzionano in modo simile.

Terza tripletta del DNA

Il gruppo che va dalla settima alla nona lettera, è libero e potete impostarlo come preferite (AAATTTAG) - ultima lettera non indicata
Per esempio, potrebbe indicare una propensione al tradimento, oppure ogni quante mosse tradire, oppure ancora potrebbe indicare una forma di pregiudizio, vedendo il colore dell'avversario, potrebbe decidere a torto o a ragione, di usare una strategia cattiva o buona.
Al momento non sono usate.

Come funziona lo script del torneo

Il programma vero e proprio è dentro al file torneo.js che viene fornito assieme a tutti gli altri file nel pacchetto .ZIP alla pagina di download.
Nel file si possono configurare:
1. Le corrispondenze del DNA con colori, strategie di gioco

Il primo problema per impostare questo programma, è stato di preparare una funzione che permettesse di far "combattere" tutte le strategie partecipanti contro se stesse e contro le altre, impostandolo in modo che fosse semplice aggiungere o togliere partecipanti senza dover cambiare tutte le volte la funzione.

Ecco la soluzione adottata:

function torneo ()
{
for (numero=1; numero<=tot;numero++) {punti[numero]=0};
puntiA=0;puntiB=0;

var giocoA=new Array(5);
giocoA5=3;giocoB5=3;giocoA4=3;giocoB4=3;giocoA3=3;
giocoB3=3;giocoA2=3;giocoB2=3;giocoA1=3;giocoB1=3;

for (x = 1; x <= tot; x++) {
partita=partita+1;
scontro(a=x,b=x);
punti[x]=punti[x]+puntiA+puntiB
puntiA=0;puntiB=0;

for (i = 1; i < tot+1; i++) {
if (x<=tot-i) {
partita=partita+1;
scontro(a=x,b=x+i)

punti[x]=punti[x]+puntiA;
punti[x+i]=punti[x+i]+puntiB;
puntiA=0;puntiB=0;
}
}
}
}

Le variabili giocoA da 1 a 5 e giocoB da 1 a 5 rappresentano l memoria delle ultime 5 mosse, in modo che i concorrenti possano usarla per pianificare la loro strategia.

Il ciclo:
for (x = 1; x <= tot; x++)
si ripete per un valore da 1 al numero totale di concorrenti, all'interno contiene a sua volta il ciclo:
for (i = 1; i < tot+1; i++)
In questo modo, al primo passaggio quando x sarà uguale a 1 si avrà:
scontro(a=x,b=x);
Vedremo la funzione scontro piu` avanti, per ora è sufficiente tenere a mente che è la partita tra i due concorrenti chiamati A e B, e visto che x ora = 1 avremo:
a=1 contro b=1 (la strategia numero contro se stessa)
andando aventi troviamo il secondo ciclo:
for (i = 1; i < tot+1; i++)
dove i assume il valore da 1 al numero massimo di partecipanti, al primo passaggio avremo x=1 e i=1 quindi:
scontro(a=x,b=x+i)
corrisponde a a=1 contro b=2
i continua a incrementare e quindi si avranno tutte le combinazioni di scontri che coinvolgono la strategia numero 1:
a=1 contro b=3, a=1 contro b=4 ecc.
finito il ciclo, si incrementa x e si riprende con x=2 avendo prima:
a=2 contro b=2 (la strategia numero 2 contro se stessa)
poi entrando nel ciclo di i:
scontro(a=x,b=x+i)
corrisponde a a=2 contro b=3
i continua a incrementare e quindi si avranno tutte le combinazioni di contri che coinvolgono la strategia numeo 2 eccetto 2 contro 1 che è già stata coperta quando x era uguale a 1:
Continuando in questo modo tutti combattono contro tutti.

Dopo ogni partita si incrementano i punti di ciascuna strategia in questo modo:
punti[x]=punti[x]+puntiA;
punti[x+i]=punti[x+i]+puntiB;

e si riazzerano i punti per la partita seguente:
puntiA=0;puntiB=0;

La funzione dello scontro

function scontro (a,b)
{
document.write("<b>A ="+a+" contro B = "+b+"<\/b><br>");

apertura ();
punteggio ();

for (xx = 2; xx <= cicli; xx++) {
strategia ();
punteggio ();
}
}

Con:
document.write(
scriviamo sullo schermo i partecipanti allo scontro, poi si effettua la mossa di apertura che vedremo tra poco, e si calcola il punteggio per la prima mano.
A seguire, per la mano che va dalla 2 a "cicli" (il numero di mani per partita) si continua la gara sino alla fine.

Ecco la funzione per la prima mossa di ogni partita, richiamata durante lo scontro indicato sopra:

function apertura ()
{
giocoA=DNA[a].substr(2,1);
switch (giocoA)
{case "A": giocoA=1;
break
case "T": giocoA=1;
break
case "C": giocoA=0;
break
case "G": giocoA=Math.floor(Math.random()*2);
break
default: document.write("<br>* Errore g3 su DNA di "+[a]+" * ");
}

giocoB=DNA[b].substr(2,1); // estrae il 3 carattere
switch (giocoB)
{case "A": giocoB=1;
break
case "T": giocoB=1;
break
case "C": giocoB=0;
break
case "G": giocoB=Math.floor(Math.random()*2);
break
default: document.write("<br>* Errore g3 su DNA di "+[b]+" * ");
}
}

La prima mossa, dipende dal terzo caratere del DNA del partecipante. La riga:

giocoB=DNA[a].substr(2,1);

Col numero 2 si estrae 1 carattere a pertire dalla terza posizione, si iniza a contare da zero.

La lettera estratta corrisponderà al gioco con questo criterio:
Se è A la variabile giocoA che contiene la mossa del concorrente A diventa 1 che corrisponde a collabora.
Se è T, giocoA sarà ancora 1
Se è C, giocoA sarà 0 e come prima mossa il concorrente giocherà defeziona
Se invece è G il concorrente giocherà una mossa a caso tra 1 e 0, estratta dalla seguente riga:

Math.floor(Math.random()*2);

Stessa procedura per il concorrente B

Dopo la prima mossa di apertura, per quelle seguenti si applicherà la strategia di gioco peculiare per ogni partecipante, contenuta nel DNA

function strategia ()
{

giocoA5=giocoA4;giocoB5=giocoB4;
giocoA4=giocoA3;giocoB4=giocoB3;
giocoA3=giocoA2;giocoB3=giocoB2;
giocoA2=giocoA1;giocoB2=giocoB1;
giocoA1=giocoA;giocoB1=giocoB;

strategia[a]=DNA[a].substr(3,3);
attenzione="A";
switch (strategia[a])
{case "TTT": tit_for_tat ();
break
case "TTG": tit_for_2tat ();
break
case "AAG": collabora_sempre ();
break
case "AAA": defeziona_sempre ();
break
case "TTA": tit_for_tat_TRD ();
break
case "TTC": tit_for_tat_RIM ();
break
case "AAC": casuale_sempre ();
break
default: document.write("<br><b>* Errore 4,5,6 su DNA di "+[a]+" *<\/b> ");
}

strategia[b]=DNA[b].substr(3,3);
attenzione="B";
switch (strategia[b])
{ case "TTT": tit_for_tat ();
break
case "TTG": tit_for_2tat ();
break
case "AAG": collabora_sempre ();
break
case "AAA": defeziona_sempre ();
break
case "TTA": tit_for_tat_TRD ();
break
case "TTC": tit_for_tat_RIM ();
break
case "AAC": casuale_sempre ();
break
default: document.write("<br><b>* Errore 4,5,6 su DNA di "+[b]+" *<\/b>");
}
}

Si comincia riempiendo la memoria delle giocate precedenti, che era stata inizializzata all'inizio.
Poi con un procedimento simile a quello della mossa di apertura, si estraggono i tre caratteri del DNA che indicano la strategia che, secondo il contenuto sarà:

TTT per la strategia richiamata dall funzione tit_for_tat ();
TTG per tit_for_2tat ();
AAG per collabora_sempre ();
AAA per defeziona_sempre ();
TTA per tit_for_tat_TRD ();
TTC per tit_for_tat_RIM ();
AAC per: casuale_sempre ();

Se il DNA non corrisponde, sullo schermo appare un messaggio di errore che indica la riga:

document.write("<br><b>* Errore 4,5,6 su DNA di "+[b]+" *<\/b>")

Infine, la funzione che determina il punteggio:

function punteggio ()
{
if (giocoA=="1" && giocoB=="0") {puntiB=puntiB+5};
if (giocoA=="0" && giocoB=="1") {puntiA=puntiA+5};
if (giocoA=="1" && giocoB=="1") {puntiA=puntiA+3;puntiB=puntiB+3};
if (giocoA=="0" && giocoB=="0") {puntiA=puntiA+1;puntiB=puntiB+1};
document.write(" A gioca="+giocoA+" B gioca="+giocoB+" --> Punti A ="+puntiA+" Punti B = "+puntiB+"<br>")
}

Come da tabella, assegna i punti secondo le giocate degli avversari e le visualizza sullo schermo.

Tornate all'indice generale di questo articolo

Andate ai tornei per generazioni

Tornate in biblioteca: www.steppa.net