Edward Lorenz e il butterfly effect.

Il modello di Lorenz è un sistema di equazioni differenziali ordinarie (EDO) che descrive il movimento di fluidi in riscaldamento. Fu sviluppato da Edward Lorenz nel 1963 come semplificazione di modelli più complessi del tempo atmosferico. Il modello è noto per il suo comportamento caotico, che era un fenomeno poco compreso all’epoca.

Il sistema di Lorenz è definito dalle seguenti tre equazioni differenziali non-lineari per le variabili x, y e z, che rappresentano lo stato del sistema in funzione del tempo t:

dx/dt = σ(y – x)
dy/dt = x(ρ – z) – y
dz/dt = xy – βz

Le costanti σ, ρ e β sono parametri positivi. Nella scoperta originale di Lorenz, σ (sigma) rappresentava il numero di Prandtl, che è un parametro senza dimensioni utilizzato in fluidodinamica, ρ (rho) rappresentava la differenza di temperatura tra l’alto e il basso della colonna d’aria e β (beta) era proporzionale al rapporto tra l’altezza e la larghezza della colonna d’aria.

Per risolvere numericamente il sistema di Lorenz, si utilizzano metodi numerici per le equazioni differenziali, come il metodo di Euler, il metodo di Runge-Kutta o altri metodi più avanzati. Questi metodi approssimano la soluzione del sistema di equazioni avanzando passo dopo passo nel tempo. A ogni passo, le derivate vengono stimate dalle equazioni del sistema e utilizzate per calcolare i valori delle variabili al passo successivo.

Per esempio, nel metodo di Euler (il più semplice), i passaggi sarebbero i seguenti:

  1. Iniziare con valori iniziali per x, y, z e t.
  2. Calcolare le derivate dx/dt, dy/dt e dz/dt utilizzando le equazioni del sistema.
  3. Aggiornare i valori di x, y e z utilizzando le derivate e un piccolo passo di tempo Δt: x = x + dx/dt * Δt, y = y + dy/dt * Δt, z = z + dz/dt * Δt.
  4. Aggiornare il tempo t = t + Δt.
  5. Ripetere i passaggi 2-4 per il numero desiderato di passi.

Questo metodo produce un’approssimazione della traiettoria del sistema nel tempo. Tuttavia, a causa del comportamento caotico del sistema di Lorenz, piccole differenze nelle condizioni iniziali o negli errori di arrotondamento possono portare a grandi differenze nei risultati, un fenomeno noto come “effetto farfalla“. Pertanto, è necessario scegliere attentamente il passo di tempo Δt e gestire accuratamente gli errori di arrotondamento quando si risolve numericamente il sistema di Lorenz.

Di seguito, si propone un semplice script in Python per integrare numericamente il sistema di equazioni di Lorenz:

import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# Definizione del sistema di Lorenz
def lorenz_system(current_state, t, sigma, beta, rho):
    x, y, z = current_state
    dx_dt = sigma * (y - x)
    dy_dt = x * (rho - z) - y
    dz_dt = x * y - beta * z
    return [dx_dt, dy_dt, dz_dt]

# Parametri del sistema di Lorenz
sigma = 10.0
beta = 8.0 / 3.0
rho = 28.0

# Condizioni iniziali
initial_state = [1.0, 1.0, 1.0]

# Creazione di un array di punti temporali per l'integrazione
t = np.arange(0.0, 50.0, 0.01)

# Risoluzione del sistema di Lorenz con odeint
solution = odeint(lorenz_system, initial_state, t, args=(sigma, beta, rho))

# Estrazione delle soluzioni x, y, z
x = solution[:, 0]
y = solution[:, 1]
z = solution[:, 2]

# Creazione di un plot 3D dei risultati
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot(x, y, z)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.set_title('Lorenz Attractor')

plt.show()

Questo script risolve il sistema di Lorenz per un intervallo di tempo da 0 a 50 con un passo di 0.01, partendo dalle condizioni iniziali (1,1,1). Viene quindi generato un plot 3D che mostra l’attrattore di Lorenz, ovvero la traiettoria del sistema nel tempo. Le forme a spirale complesse che vedi nel grafico sono tipiche dei sistemi caotici come il sistema di Lorenz.

Generare segnali acustici con frequenze variabili in Python

Creare un segnale acustico con frequenza variabile può essere utile in molte situazioni, come ad esempio la calibrazione dell’audio o la creazione di effetti sonori. In questo articolo, esploreremo come generare un segnale acustico che varia linearmente tra 20 Hz e 20.000 Hz utilizzando Python e la libreria sounddevice. Spiegheremo anche il funzionamento del codice, che può essere facilmente modificato per adattarsi alle esigenze specifiche del progetto.

Per iniziare, è necessario installare le librerie sounddevice e numpy. Queste librerie possono essere installate utilizzando pip:

pip install sounddevice numpy

Di seguito è riportato il codice completo in Python per generare un segnale acustico con frequenza variabile tra 20 Hz e 20.000 Hz:

import numpy as np
import sounddevice as sd
import time

sample_rate = 44100  # Campioni al secondo
duration = 0.1  # Durata di ogni suono in secondi
freq_start = 20  # Frequenza iniziale in Hz
freq_end = 20000  # Frequenza finale in Hz
num_steps = 100  # Numero di passi tra la frequenza iniziale e finale

def generate_tone(freq, duration, sample_rate):
    num_samples = int(sample_rate * duration)
    t = np.linspace(0, duration, num_samples, False)
    signal = 0.5 * np.sin(2 * np.pi * freq * t)
    return signal.astype(np.float32)

def play_signal(signal, sample_rate):
    sd.play(signal, sample_rate)
    sd.wait()

for i in range(num_steps):
    freq = freq_start + i * (freq_end - freq_start) / num_steps
    print(f"Frequenza: {freq:.2f} Hz")
    signal = generate_tone(freq, duration, sample_rate)
    play_signal(signal, sample_rate)
    time.sleep(0.05)

Spiegazione del codice:

  1. Importazione delle librerie: Importiamo le librerie numpy per le operazioni matematiche, sounddevice per l’output audio e time per gestire le pause tra i suoni.
  2. Definizione dei parametri: Definiamo alcuni parametri come il sample rate (campioni al secondo), la durata di ogni suono, le frequenze iniziale e finale, e il numero di passi tra le frequenze.
  3. Funzione per generare il segnale sinusoidale: Questa funzione genera un segnale sinusoidale con la frequenza, la durata e il sample rate specificati come input. Calcoliamo il numero di campioni necessari per la durata specificata, generiamo un array di valori di tempo e, infine, calcoliamo il segnale sinusoidale con la frequenza specificata. Il segnale viene convertito nel formato float32 e restituito.
  4. Funzione per riprodurre un segnale: Questa funzione utilizza la libreria sounddevice per riprodurre il segnale audio fornito con il sample rate specificato. La funzione sd.wait() attende la fine della riproduzione del suono.
  5. Riproduzione del segnale acustico e visualizzazione della frequenza: In un ciclo for, calcoliamo la frequenza corrente linearmente interpolando tra freq_start e freq_end. Visualizziamo la frequenza corrente, generiamo il segnale sinusoidale con la funzione generate_tone e lo riproduciamo con la funzione play_signal. Infine, mettiamo in pausa il programma per 0,05 secondi (time.sleep(0.05)) prima di passare al passo successivo.

Introduzione alla programmazione con il gioco del Tris…

Se vuoi avvicinare tuo figlio alla programmazione e stai cercando un progetto interessante e coinvolgente, il gioco del Tris (conosciuto anche come tic-tac-toe) è un’ottima scelta.

In questo articolo, presenterò una versione procedurale del gioco del Tris, che ho scelto perché è più accessibile per i principianti rispetto a un approccio orientato agli oggetti. Scopriamo insieme come funziona!

Il gioco del Tris procedurale utilizza la libreria Tkinter di Python, che consente di creare interfacce grafiche in modo semplice e veloce. L’obiettivo del gioco è formare una linea orizzontale, verticale o diagonale di tre simboli uguali (solitamente “X” e “O”) su una griglia 3×3. Il gioco procede a turni, con i due giocatori che inseriscono il proprio simbolo in una cella vuota della griglia. Il primo giocatore che forma una linea di tre simboli uguali vince la partita.

Il codice procedurale del gioco del Tris è composto da diverse funzioni che gestiscono le varie parti del gioco. Di seguito è riportata una breve descrizione di ciascuna funzione:

  • initialize_game(): Questa funzione inizializza le variabili del gioco e crea i pulsanti interattivi per ciascuna cella della griglia. Imposta il turno del primo giocatore e crea una griglia vuota.
  • make_move(i, j): Questa funzione viene chiamata quando un giocatore fa una mossa. Controlla se la cella selezionata è vuota e, se lo è, inserisce il simbolo del giocatore corrente. Dopo ogni mossa, verifica se c’è un vincitore o un pareggio. Se non ci sono vincitori o pareggi, passa il turno all’altro giocatore.
  • check_vittoria(): Questa funzione controlla se c’è un vincitore, verificando se esiste una linea orizzontale, verticale o diagonale di tre simboli uguali. Restituisce True se c’è un vincitore, altrimenti False.
  • check_pareggio(): Questa funzione verifica se tutte le celle della griglia sono piene e nessun giocatore ha vinto. Se è così, restituisce True, altrimenti False.
  • annuncia_vincitore() e annuncia_pareggio(): Queste funzioni vengono chiamate quando il gioco termina con una vittoria o un pareggio. Mostrano una finestra di dialogo con il risultato del gioco e chiedono ai giocatori se vogliono iniziare una nuova partita o uscire dal gioco.
  • disabilita_pulsanti(): Questa funzione disabilita tutti i pulsanti della griglia quando il gioco termina, impedendo ulteriori mosse.
  • reset_board(): Questa funzione viene chiamata quando i giocatori decidono di iniziare una nuova partita. Ripristina lo stato iniziale della griglia, reimpostando i pulsanti e il turno del giocatore.


Un approccio procedurale è spesso più accessibile per i principianti rispetto a un approccio orientato agli oggetti, perché è più facile da comprendere e richiede meno concetti avanzati. Inoltre, un codice procedurale è generalmente più breve e semplice da leggere e modificare, il che può aiutare i principianti a concentrarsi sulle basi della programmazione senza dover affrontare la complessità aggiuntiva delle classi e degli oggetti.

Il gioco del Tris è un progetto semplice ma coinvolgente per avvicinare tuo figlio alla programmazione. La versione procedurale del gioco presentata in questo articolo è ideale per i principianti, poiché offre un approccio più accessibile e comprensibile rispetto a un’implementazione orientata agli oggetti. Attraverso questo progetto, tuo figlio può imparare le basi della programmazione e acquisire familiarità con la creazione di interfacce grafiche utilizzando la libreria Tkinter.

Buon divertimento e buona programmazione!

Tic-tac-toe…

Il codice (qui puoi scaricare il codice sorgente) implementa il gioco del tris (tic-tac-toe) con un’interfaccia testuale, permettendo a un giocatore umano di sfidare un’intelligenza artificiale (IA) semplificata che sceglie mosse casuali. Ecco il funzionamento del codice, funzione per funzione:

  1. stampa_tabellone(tabellone): Questa funzione prende in input il tabellone di gioco e lo stampa sulla console in un formato leggibile. Il tabellone è una lista di liste che contiene le informazioni sulle caselle occupate dai simboli dei giocatori.
  2. verifica_vittoria(tabellone, simbolo): Questa funzione prende in input il tabellone e un simbolo del giocatore (“X” o “O”) e verifica se il giocatore con quel simbolo ha vinto la partita. Controlla tutte le righe, colonne e le due diagonali per vedere se contengono tre simboli uguali. Se trova una combinazione vincente, restituisce True, altrimenti False.
  3. mossa_ia(tabellone): Questa funzione rappresenta la logica dell’IA semplificata. Prende in input il tabellone e sceglie casualmente una mossa tra le caselle disponibili. Restituisce le coordinate (riga, colonna) della mossa scelta. Nota che questa IA è molto semplice e non segue alcuna strategia per vincere la partita.
  4. gioco(): Questa è la funzione principale che implementa la logica del gioco. Inizialmente, crea un tabellone vuoto e assegna il turno al giocatore umano con il simbolo “X”. Fino a quando ci sono caselle libere, esegue i seguenti passaggi: a. Stampa il tabellone attuale. b. Se è il turno del giocatore umano, chiede in input un numero tra 1 e 9 che corrisponde alla casella da occupare. Converte il numero in coordinate (riga, colonna) del tabellone. c. Se è il turno dell’IA, chiama la funzione mossa_ia() per ottenere le coordinate della mossa scelta dall’IA. d. Controlla se la casella scelta è già occupata. Se lo è, chiede al giocatore di scegliere un’altra casella. e. Altrimenti, occupa la casella con il simbolo del giocatore corrente e decrementa il numero di caselle libere. f. Verifica se il giocatore corrente ha vinto la partita chiamando la funzione verifica_vittoria(). Se ha vinto, stampa il messaggio di vittoria e interrompe il ciclo. g. Se nessuno ha vinto, passa il turno all’altro giocatore.
  5. Se il ciclo termina senza che nessun giocatore abbia vinto, stampa il messaggio di pareggio.

La strategia adottata in questo codice è semplice e non ottimizzata per far vincere l’IA. L’IA sceglie mosse casuali tra le caselle disponibili, senza alcuna strategia per bloccare il giocatore avversario o cercare di vincere la partita. L’obiettivo principale del codice è di fornire un’implementazione di base del gioco del tris, piuttosto che un’intelligenza artificiale avanzata.

Per migliorare l’IA e renderla più competitiva, potresti implementare un algoritmo di ricerca come il Minimax, che analizza tutte le possibili mosse future e sceglie la mossa ottimale per massimizzare il punteggio dell’IA e minimizzare il punteggio del giocatore avversario. Tuttavia, questo richiederebbe una modifica sostanziale della funzione mossa_ia() e l’aggiunta di funzioni aggiuntive per calcolare il punteggio delle mosse e simulare le mosse future.

Creare una GIF animata di un toro 3D utilizzando PyOpenGL e Pygame

In questo tutorial, ti guiderò attraverso la creazione di un programma Python per visualizzare un toro 3D rappresentato con linee e farlo ruotare intorno al suo asse utilizzando PyOpenGL e Pygame. Infine, mostrerò come generare e salvare una GIF animata del toro ruotante.

Prerequisiti:
Prima di iniziare, assicurati di aver installato le seguenti dipendenze:

pip install PyOpenGL PyOpenGL_accelerate numpy pygame imageio imageio[ffmpeg]

Passo 1: Importare le librerie necessarie
Innanzitutto, importiamo le librerie che useremo nel nostro codice:

import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
import numpy as np
import imageio

Passo 2: Creare la funzione per generare il toro

Creiamo una funzione chiamata torus che genera i vertici e gli indici del toro. La funzione accetta quattro argomenti: il raggio del cerchio interno, il raggio del tubo, il numero di segmenti e il numero di segmenti del tubo.

def torus(radius, tube_radius, num_segments, num_tube_segments):
    vertices = []
    indices = []

    # Calcolare i vertici del toro
    for i in range(num_segments):
        theta = i * 2 * np.pi / num_segments
        for j in range(num_tube_segments):
            phi = j * 2 * np.pi / num_tube_segments

            x = (radius + tube_radius * np.cos(phi)) * np.cos(theta)
            y = (radius + tube_radius * np.cos(phi)) * np.sin(theta)
            z = tube_radius * np.sin(phi)

            vertices.append([x, y, z])

    # Creare gli indici per collegare i vertici
    for i in range(num_segments):
        for j in range(num_tube_segments):
            index1 = (i * num_tube_segments + j) % (num_segments * num_tube_segments)
            index2 = ((i + 1) * num_tube_segments + j) % (num_segments * num_tube_segments)
            index3 = ((i + 1) * num_tube_segments + (j + 1)) % (num_segments * num_tube_segments)
            index4 = (i * num_tube_segments + (j + 1)) % (num_segments * num_tube_segments)

            indices.extend([index1, index2, index3, index4])

    return vertices, indices

Passo 3: Creare la funzione per disegnare il toro

La funzione draw_torus accetta i vertici e gli indici generati dalla funzione torus e utilizza le funzioni OpenGL per disegnare il toro come una serie di linee.

def draw_torus(vertices, indices):
    for i in range(0, len(indices), 4):
        glBegin(GL_LINES)
        glVertex3fv(vertices[indices[i]])
        glVertex3fv(vertices[indices[i + 1]])
        glEnd()

        glBegin(GL_LINES)
        glVertex3fv(vertices[indices[i + 1]])
            glVertex3fv(vertices[indices[i + 2]])
    glEnd()

    glBegin(GL_LINES)
    glVertex3fv(vertices[indices[i + 2]])
    glVertex3fv(vertices[indices[i + 3]])
    glEnd()

    glBegin(GL_LINES)
    glVertex3fv(vertices[indices[i + 3]])
    glVertex3fv(vertices[indices[i]])
    glEnd()

Passo 4: Creare la funzione per catturare i frame OpenGL
Creiamo una funzione chiamata capture_frame che utilizza glReadPixels per catturare i frame direttamente dall’OpenGL e restituisce un array NumPy.

def capture_frame(width, height):
    buffer = (GLubyte * (3 * width * height))()
    glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer)
    return np.frombuffer(buffer, dtype=np.uint8).reshape(height, width, 3)[::-1, :, :]

Passo 5: Creare la funzione principale

Ora creiamo la funzione principale main che inizializza Pygame, configura la finestra e la visualizzazione OpenGL, e crea un ciclo principale che gestisce gli eventi, aggiorna la rotazione del toro, disegna il toro sullo schermo e cattura i frame per generare la GIF animata.

def main():
    pygame.init()
    display = (800, 600)
    pygame.display.set_mode(display, DOUBLEBUF | OPENGL)

    gluPerspective(45, (display[0] / display[1]), 0.1, 50.0)
    glTranslatef(0.0, 0.0, -5)

    glEnable(GL_DEPTH_TEST)

    torus_vertices, torus_indices = torus(0.5, 0.5, 32, 32)

    frames = []
    num_frames = 360
    frame_interval = 10

    # Ruota il toro di 90 gradi
    glRotatef(90, 0, 1, 0)

    for _ in range(num_frames):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        glRotatef(1, 0, 1, 0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        glColor3f(1, 1, 1)
        draw_torus(torus_vertices, torus_indices)

        pygame.display.flip()

        # Cattura il frame corrente e aggiungilo all'array di frame
        frame_data = capture_frame(*display)
        frames.append(frame_data)

        pygame.time.wait(frame_interval)

    # Salva l'array di frame come una GIF animata
    imageio.mimsave('torus_animation.gif', frames, fps=30)

    pygame.quit()

if __name__ == "__main__":
    main()

Convergenza verso una distribuzione gaussiana: un’applicazione pratica del teorema del limite centrale in Python

Il teorema del limite centrale è uno dei concetti fondamentali nella teoria della probabilità e nelle statistiche. Stabilisce che la distribuzione della somma (o della media) di un numero sufficientemente grande di variabili casuali indipendenti e identicamente distribuite tende a una distribuzione normale, anche conosciuta come distribuzione gaussiana. Questo articolo illustra come implementare e dimostrare il teorema del limite centrale utilizzando Python, generando numeri casuali da diverse distribuzioni e sommandoli per creare un istogramma che converge verso una distribuzione gaussiana.

Il teorema del limite centrale ha importanti implicazioni nella pratica, poiché giustifica l’utilizzo della media come stima del valore vero di una misura e mostra che la nostra confidenza nella stima aumenta con l’aumentare del numero di misure. La convergenza verso una distribuzione gaussiana è il risultato dell’effetto combinato di un gran numero di variabili casuali indipendenti, che porta ad una distribuzione simmetrica attorno al valore medio.

Per illustrare il teorema del limite centrale in Python, abbiamo sviluppato un codice che genera numeri casuali da diverse distribuzioni, somma i numeri casuali generati e crea un istogramma dei valori sommati. Con l’aumentare del numero di distribuzioni, l’istogramma diventa sempre più simile a una distribuzione gaussiana.

import numpy as np
import matplotlib.pyplot as plt

def generate_random_numbers(num_distributions, num_samples):
    random_numbers = []
    
    for _ in range(num_distributions):
        distribution = np.random.choice(["uniform", "normal", "exponential"])
        
        if distribution == "uniform":
            numbers = np.random.uniform(-1, 1, num_samples)
        elif distribution == "normal":
            numbers = np.random.normal(0, 1, num_samples)
        elif distribution == "exponential":
            numbers = np.random.exponential(1, num_samples)
        
        random_numbers.append(numbers)
    
    return random_numbers

def sum_random_numbers(random_numbers):
    return np.sum(random_numbers, axis=0)

def plot_histogram(summed_numbers):
    plt.hist(summed_numbers, bins=50, density=True)
    plt.xlabel("Valori sommati")
    plt.ylabel("Densità")
    plt.title("Istogramma della somma di numeri casuali")
    plt.show()

def main():
    num_distributions = 10  # Numero di distribuzioni da sommare
    num_samples = 1000  # Numero di campioni per ciascuna distribuzione

    random_numbers = generate_random_numbers(num_distributions, num_samples)
    summed_numbers = sum_random_numbers(random_numbers)
    plot_histogram(summed_numbers)

if __name__ == "__main__":
    main()

Il codice si basa su due librerie principali: NumPy per la manipolazione dei numeri e la generazione di numeri casuali, e Matplotlib per la creazione dell’istogramma. Il codice è strutturato in quattro funzioni principali: generate_random_numbers, sum_random_numbers, plot_histogram e main.

La funzione generate_random_numbers genera numeri casuali da diverse distribuzioni, quali uniforme, normale ed esponenziale. Questa funzione prende due argomenti: il numero di distribuzioni da sommare e il numero di campioni per ciascuna distribuzione. Restituisce una lista di array NumPy contenente i numeri casuali generati.

La funzione sum_random_numbers somma i numeri casuali generati lungo l’asse 0, ovvero somma i numeri casuali delle diverse distribuzioni. Prende come argomento la lista di array NumPy contenente i numeri casuali generati e restituisce un array NumPy con i numeri sommati.

La funzione plot_histogram crea un istogramma dei numeri sommati utilizzando Matplotlib. Prende come argomento l’array NumPy con i numeri sommati e mostra l’istogramma.

La funzione main gestisce il flusso del programma. Imposta il numero di distribuzioni e il numero di campioni per ciascuna distribuzione, genera i numeri casuali, somma i numeri e crea l’istogramma.

L’esecuzione del codice mostra che, con l’aumentare del numero di distribuzioni sommate, l’istogramma dei valori sommati diventa sempre più simile a una distribuzione gaussiana. Questo risultato è in accordo con il teorema del limite centrale e conferma la sua validità nella pratica.

Questa convergenza verso una distribuzione gaussiana dimostra che la media delle misure è una stima affidabile del valore vero e che la nostra confidenza nella stima aumenta con l’aumentare del numero di misure. Inoltre, l’istogramma simmetrico attorno al valore medio suggerisce che la maggior parte delle misure si trova vicino alla media, il che implica una minore variabilità dei risultati.

L’implementazione del teorema del limite centrale in Python attraverso la generazione di numeri casuali da diverse distribuzioni e la loro somma mostra la convergenza verso una distribuzione gaussiana, confermando l’importanza e l’applicabilità del teorema nella pratica. Questo esempio dimostra l’utilità del teorema per giustificare l’uso della media come stima del valore vero e per mostrare che la nostra confidenza nella stima aumenta con l’aumentare del numero di misure.

Creare un’applicazione PyQt5 per visualizzare lo spazio libero sui dischi del sistema

Nell’articolo di oggi, esploreremo come creare un’applicazione semplice ma utile utilizzando PyQt5 per visualizzare lo spazio libero sui dischi del sistema. PyQt5 è una libreria Python che consente di creare interfacce utente grafiche (GUI) per le applicazioni desktop. Il nostro obiettivo è creare una finestra che mostri le informazioni sullo spazio libero sui dischi e includa un pulsante “Exit” per chiudere l’applicazione.
Prima di iniziare, assicurati di avere installato Python sul tuo sistema e di aver installato i pacchetti PyQt5 e psutil. Per installarli, esegui il seguente comando:

pip install PyQt5 psutil

Importazione dei moduli: All’inizio del codice, importiamo i moduli necessari, tra cui os, sys, psutil e alcuni widget specifici da PyQt5.QtWidgets.

Funzione get_disk_space_info: Questa funzione raccoglie informazioni sullo spazio libero sui dischi utilizzando la libreria psutil. La funzione itera su tutte le partizioni e raccoglie informazioni su dispositivo, punto di montaggio, spazio totale, spazio libero e spazio utilizzato. Restituisce una lista di stringhe con queste informazioni.

Classe DiskSpaceApp: Questa classe estende QWidget e contiene la logica per creare l’interfaccia utente dell’applicazione.

  • Metodo __init__: Il costruttore chiama il costruttore della classe base e inizializza l’interfaccia utente.
  • Metodo init_ui: Questo metodo crea l’interfaccia utente dell’applicazione. Imposta il titolo della finestra e crea un layout verticale (QVBoxLayout). Aggiunge le informazioni sullo spazio libero sui dischi (ottenute dalla funzione get_disk_space_info) come etichette (QLabel) al layout. Infine, crea un pulsante “Exit” (QPushButton) e lo collega al metodo close per chiudere l’applicazione. Il pulsante viene aggiunto al layout e il layout viene impostato come layout della finestra.

Alla fine del codice, creiamo un’istanza dell’applicazione QApplication e un’istanza della nostra classe DiskSpaceApp. Quindi, avviamo l’applicazione con il metodo exec_().

The Game of Life…

The game of life

Il Game of Life, concepito dal matematico britannico John Horton Conway nel 1970, è un automa cellulare a due dimensioni che ha catturato l’immaginazione di matematici, informatici e appassionati di giochi per oltre cinquant’anni. Con le sue semplici regole che governano la nascita, la morte e la sopravvivenza delle cellule su una griglia, il Game of Life genera una sorprendente varietà di pattern e comportamenti complessi. In questo articolo, esploreremo le regole del gioco, alcuni dei suoi pattern più noti e come implementarlo in Python.

Le regole del Game of Life

Il Game of Life si svolge su una griglia bidimensionale di celle quadrate, ognuna delle quali può essere “viva” (1) o “morta” (0). Le celle interagiscono con i loro otto vicini, che sono le celle direttamente adiacenti orizzontalmente, verticalmente e diagonalmente. A ogni passo temporale, o generazione, le seguenti quattro regole vengono applicate simultaneamente a tutte le celle:

  1. Una cella viva con meno di due vicini vivi muore per isolamento.
  2. Una cella viva con due o tre vicini vivi sopravvive alla generazione successiva.
  3. Una cella viva con più di tre vicini vivi muore per sovraffollamento.
  4. Una cella morta con esattamente tre vicini vivi diventa viva per riproduzione.

Pattern interessanti nel Game of Life

Le semplici regole del Game of Life danno origine a una vasta gamma di pattern e comportamenti. Alcuni dei più noti sono:

  1. Configurazioni oscillanti: pattern che si ripetono periodicamente dopo un certo numero di generazioni, come il Blinker, il Toad, il Beacon e il Pulsar.
  2. Navi spaziali: pattern che si spostano attraverso la griglia mentre oscillano, come il Glider e il Lightweight Spaceship (LWSS).
  3. Pattern stabili: configurazioni che non cambiano nel tempo, come il Block e la Beehive.
  4. Cannoni: pattern che producono navi spaziali o altri pattern in modo periodico, come il Glider Gun di Gosper.

Implementazione del Game of Life in Python

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

def inizializza_griglia(n):
    griglia = np.random.choice([0, 1], n*n, p=[0.5, 0.5]).reshape(n, n)
    return griglia

def conta_vicini_vivi(griglia):
    vicini_vivi = np.zeros(griglia.shape, dtype=int)

    for x in range(-1, 2):
        for y in range(-1, 2):
            if x == 0 and y == 0:
                continue
            vicini_vivi += np.roll(np.roll(griglia, y, axis=0), x, axis=1)

    return vicini_vivi

def aggiorna_griglia(griglia):
    nuova_griglia = griglia.copy()
    vicini_vivi = conta_vicini_vivi(griglia)

    nuova_griglia[(griglia == 1) & (vicini_vivi < 2)] = 0
    nuova_griglia[(griglia == 1) & (vicini_vivi > 3)] = 0
    nuova_griglia[(griglia == 0) & (vicini_vivi == 3)] = 1

    return nuova_griglia

def aggiorna_frame(*args):
    global griglia
    griglia = aggiorna_griglia(griglia)
    img.set_array(griglia)
    return [img]

def main():
    global griglia, img
    n = 50  # Dimensione della griglia
    generazioni = 100  # Numero di generazioni

    griglia = inizializza_griglia(n)

    fig, ax = plt.subplots()
    img = ax.imshow(griglia, cmap='binary')
    ax.set_xticks([])
    ax.set_yticks([])

    anim = FuncAnimation(fig, aggiorna_frame, frames=generazioni, interval=200, blit=True)
    plt.show()

if __name__ == '__main__':
    main()

Per implementare il Game of Life in Python, è possibile utilizzare la libreria numpy per rappresentare e manipolare la griglia e la libreria matplotlib per visualizzare l’evoluzione del gioco nel tempo. Il codice può essere organizzato nelle seguenti funzioni:

  1. inizializza_griglia: crea una griglia iniziale con celle viventi e morte casuali.
  2. conta_vicini_vivi: calcola il numero di vicini vivi per ogni cella della griglia.
  3. aggiorna_griglia: applica le regole del Game of Life alla griglia corrente per ottenere la griglia della generazione successiva.
  4. visualizza: mostra la griglia corrente con matplotlib

Inoltre…

Inoltre gli studenti delle Superiori possono acquisire competenze per la vita (life skills) essenziali grazie alla programmazione con Phyton. Per esempio, lo sviluppo del pensiero logico, la capacità di risoluzione dei problemi e l’abilità nell’analisi dei compiti.

Guido van Rossum, Il creatore di Phyton