In [105]:
#Operazioni sulle matrici: Stampa, creazione, controlli vincita, controllo fine partita, inserimento 

def init(val): #Creazione
    return [[val, val, val],[val, val, val],[val, val, val]] 


def ppmatrix(m): #Stampa la matrice
    print ("__________________________________________________")
    for riga in m: 
        string = "|\t"
        for el in riga:
            string = string +  str(el) + "\t | \t"            
        print (string)
        print ("__________________________________________________")
        

def TupleWin(t): #Restituisce Vero se una tupla (riga-colonna-diagonale) contiene una vincita
    return (len(set(t)) == 1) and (not(set(t) == set(['']) )) 

        
def control_r(field, p): #Controlla vincita sulle righe
    for riga in field:
        if (TupleWin(riga) and p in set(riga)) :  return True
    return False


def traspostaM(field): #Trova la trasposta righe-colonne
    i = 0
    j = 0
    r = init('')
    for riga in field:
        i = 0
        for ele in riga:
            r[i][j] = ele
            i = i+1
        j = j +1
    return r        

def control_c(field, p): #Controlla vincita sulle colonne
    r = traspostaM(field) 
    return control_r(r, p)


def control_d(field, p): #Controlla vincita sulle diagonali
    d = [] #Diagonale 1
    d1 = [] #Diagonale 2
    i = 0
    j = 0    
    for i in range(3): #Estrae le diagonali
        if (field[i][i] != p) or (field[i][2-i] != p) :
            return False
        else :
            d  = d  + [ field[i][i]   ]  
            d1 = d1 + [ field[i][2-i] ]
            
    if TupleWin(d) or TupleWin(d1) :   return True
    
    return False


def win(field, p): #Controlla la vincita globale
    return control_r(field, p) + control_c(field, p) + control_d(field, p)


def filled(field): #Controlla se la matrice è piena
    for riga in field:
        if '' in riga : 
            return False
    return True

def insert(field, x, y, player): #Inserisce nella cella 
    x = x
    y = y
    if abs(x) < len(field) and abs(y) < len(field[0]):
        field[x][y] = player
    #ppmatrix(field) 
    
def insert_controlled(field, x, y, player): #Inserisce nella cella SE è vuota
    x = x
    y = y
    if abs(x) < len(field) and abs(y) < len(field[0]):
        if field[x][y] != '': 
            field[x][y] = player
            return True
    return False
    #ppmatrix(field) 

def insert1(field, x, y, player): #Inserisce nella cella 
    x = x-1
    y = y-1
    if abs(x) < len(field) and abs(y) < len(field[0]):
        field[x][y] = player
    #ppmatrix(field)

In [127]:
#Implementaazione IA per il gioco

def check_next(player, field): #Controlla se un determinato Player può vincere con una mossa, ritorna la pos 
    import copy     
    for i in range(3):
        for j in range(3):
            ele = field[i][j]
            if ele == '':
                r = copy.deepcopy(field) #Crea una nuova variabile uguale all'altra, senza copiare solo il puntatore
                r[i][j] = player         #prova a mettere player nella cella
                if win(r, player) :      #se player ha vinto, vuol dire che può vincere con una mossa
                    return [i,j]     # Ritorna la mossa         
                  
    return False

    
def balance(player, field, fieldP, peso): #modifica il Peso delle caselle che stanno in una riga/colonna del player
    j = 0
    i = 0               
    for riga in field:
        i = 0
        for ele in riga:
            if ele == player:
                for c in range(3):
                    if field[j][c] == '' : fieldP[j][c] = fieldP[j][c] + peso
                    if field[c][i] == '' : fieldP[c][i] = fieldP[c][i] + peso
            i = i + 1
        j = j + 1 
        
    
def onlyFree(field, fieldP): #Asegna il peso minimo alle caselle già occupate
    j = 0
    i = 0        
    for riga in field:
        i = 0
        for ele in riga:
            if ele != '' : fieldP[j][i] = -999                
            i = i + 1            
        j = j + 1          
    
    
def choose_best(fieldP): #ritorna la casella con il peso maggiore
    i = 0
    j = 0
    All = []
    
    for j in range(3):
        for i in range(3):
            All = All + [fieldP[j][i]]
            
    Max = max(All)    
    for j in range(3):
        for i in range(3):
            if fieldP[j][i] == Max : return [j,i]
            
            

def count_win(player,field): #conta quante mosse vincenti possibili ha un player
    import copy     
    i = 0
    j = 0
    conta = 0
    for riga in field:
        i = 0
        for ele in riga:
            if ele == '':
                r = copy.deepcopy(field)
                r[j][i] = player
                if win(r, player) : conta = conta + 1                
            i = i+1            
        j = j+1        
    return conta



def control_spec(IA, vs, field, fieldP): #Fulcro dell'IA, controlla se ha una mossa vincente fino a 3 livelli avanti
    import copy
    peso = 10
    peso1 = 100
    for j in range(3):
        for i in range(3):
            copia = copy.deepcopy(field) #Crea un primo livello 
            if (copia[j][i] == ""): 
                copia[j][i] = IA #Inserisce il giocatore se la casella è vuota
                if count_win(IA,copia) > 1 : 
                    fieldP[j][i] = fieldP[j][i] + peso1 #Se ha due vincite possibili, ha vinto metendolo lì
                
                move = check_next(IA, copia)  
                if  move != False : #Se ha una sola possibilità, l'avversario DOVRA' metterlo lì il prossimo turno. 
                    copia[move[0]][move[1]] = vs #Inseerisce la mossa dell'avversario (secondo livello)
                    
                    for j1 in range(3):
                        for i1 in range(3):
                            copia1 = copy.deepcopy(copia) #Crea il terzo livello                            
                            if (copia1[j1][i1] == ""): #Prova le caselle vuote                                
                                copia1 = copy.deepcopy(copia)
                                copia1[j1][i1] = IA  
                                vs_move = check_next(vs, copia1) #Vede se l'avversario può vincere in una sola mossa
                                
                                if not(vs_move) :   #Se l'avversario non può vincere                  
                                    if count_win(IA, copia1) == 2: #Se l'IA ha due caselle vincenti
                                        fieldP[j][i] = fieldP[j][i] + peso  #Aggiunge un peso 10 alla casella iniziale livello 1                                   
      
    
    
def IA_move( IA, vs, field):
    fieldP = init(0)    #Crea una matrice contenente i pesi
    
    balance(vs, field, fieldP, -2) #Diminuisce il peso vicino all'avversario

    balance(IA, field, fieldP, 2)  #Aumenta il peso vicino a se stessa
    
    fieldP[1][1] = fieldP[1][1] + 3   #Aumenta il peso in centro (casella con più mosse vincenti) (se libera, sarà la prima mossa)
    
    
    onlyFree(field, fieldP)           #Toglie peso alle caselle occupate, in modo da non poter essere scelte
    
    control_spec(IA, vs, field, fieldP)  #Esegue un controllo al di vincita al 3o livello di gioco
    
    ppmatrix(fieldP) # Stampa i pesi
    return choose_best(fieldP) #Ritorna la mossa con il peso maggiore


 

def IAPlay(IA, vs, field): #Fa giocare l'IA
    move = check_next(IA, field)  #Controlla se può vincere con una sola mossa    
    print(move ,"liv 1")
    if not(move):                      #Se non può vincere in una mossa, controlla se l'avversario potrebbe vincere in una sola mossa
        move = check_next(vs, field)
        print(move,"liv 2")
        if not(move):                  #Se neanche l'avversario può vincere, pesa la matrice e sceglie la posizione migliore
            move = IA_move(IA, vs, field)
    insert(field, move[0], move[1], IA) #Muove

In [128]:
#Inizializzazione Gioco
field = init('')   
IA1 = "X"
me  = "O"  
ppmatrix(field)


__________________________________________________
|		 | 		 | 		 | 	
__________________________________________________
|		 | 		 | 		 | 	
__________________________________________________
|		 | 		 | 		 | 	
__________________________________________________

In [134]:
#Alternare inserimento utente (scegliendo la posizione con i aprametri) e l'istruzione seguente (mossa IA)
insert1(field, 2,1, me)
ppmatrix(field)


__________________________________________________
|	X	 | 		 | 	O	 | 	
__________________________________________________
|	O	 | 	O	 | 		 | 	
__________________________________________________
|	X	 | 		 | 		 | 	
__________________________________________________

In [135]:
#Mossa dell'IA, una volta eseguita si può rieseguire l'istruzione precedente per fare la propria mossa
IAPlay(IA1, me, field)
ppmatrix(field)


(False, 'liv 1')
([1, 2], 'liv 2')
__________________________________________________
|	X	 | 		 | 	O	 | 	
__________________________________________________
|	O	 | 	O	 | 	X	 | 	
__________________________________________________
|	X	 | 		 | 		 | 	
__________________________________________________

In [ ]:
#Far giocare l'IA al posto proprio
IAPlay(me, IA1, field)
ppmatrix(field)

In [7]:
def partita():
    field = init("")
    p1 = "X"
    p2 = "O"
    p = ""
    vs = ""
    while (not(filled(field)) and not(win(field, p))):
        #Inverte i giocatori ogni turno
        if p == p1 : 
            p = p2
            vs = p1
        else :
            p = p1
            vs = p2               
           
        IAPlay(p, vs, field) #fa la mossa
        ppmatrix(field) #stampa il campo           
        
    
    if    (win(field, p1)):    print("Ha vinto " + p1)   
    elif  (win(field, p2)):    print("Ha vinto " + p2)        
    else :                     print("partita patta")

In [50]:


In [46]:
range(3)


Out[46]:
[0, 1, 2]

In [ ]: