La doppia cittadinanza delle macchine…

Non mi sono mai fidato degli strumenti che promettono di essere intuitivi. Non perché l’intuizione sia un difetto, ma perché troppo spesso diventa il nome elegante che diamo alla rinuncia di capire.
Per questo sulla mia scrivania convivono un Mac e ArchLinux. A molti sembrerebbe una contraddizione, quasi una doppia cittadinanza incompatibile. Per me, invece, rappresentano due modi diversi di abitare il pensiero.
Il Mac è una stanza perfettamente illuminata. Ogni cosa è dove ti aspetti che sia. Ti accompagna senza chiederti nulla, trasforma la complessità in un gesto naturale, fa sparire la tecnica dietro l’eleganza dell’esperienza. Non pretende che tu conosca il motore: gli basta che tu sappia guidare.
ArchLinux, invece, ti lascia davanti a una porta socchiusa e una domanda. Non ti conduce. Non ti protegge. Ti costringe a sporcarti le mani, a leggere, a sbagliare, a ricominciare. Ogni comando imparato diventa un pezzo di conoscenza che nessun aggiornamento potrà sottrarti. Ogni errore, una lezione che non si dimentica.
Eppure non riesco a scegliere. Perché non credo che il mondo si divida tra chi preferisce l’una o l’altra filosofia. Credo si divida tra chi considera la tecnologia una magia e chi continua a voler sbirciare dietro il sipario.
Le interfacce moderne fanno di tutto per convincerci che capire sia superfluo. Eliminano gli attriti, cancellano le domande, addomesticano la complessità fino a renderla invisibile. È una conquista straordinaria, purché non ci abitui a pensare che tutto debba restare invisibile.
C’è una forma di libertà che nasce proprio dall’attrito. Dall’aprire un terminale e non sapere ancora quale comando digitare. Dal cercare una soluzione invece di aspettare che qualcuno l’abbia già confezionata. Dal ricordarsi che ogni finestra colorata poggia comunque su una riga di codice scritta da un essere umano. Forse è questo il motivo per cui continuo a tenere entrambi accesi. Uno mi ricorda che la tecnologia, quando è fatta bene, deve scomparire. L’altro che non dovrei mai scomparire io.
Perché il problema non è avere strumenti sempre più intelligenti. È smettere, lentamente, di esserlo noi.

[…]

Ho imparato a programmare quando il computer era un’idea più che un oggetto: matita, carta, e una logica che non perdonava distrazioni. Dal 1964 il BASIC ha aperto una porta, ma oggi rischiamo di attraversarla senza accorgercene. Forse imparare davvero, adesso, significa tornare a togliere: calcolo, strumenti, scorciatoie. Restare soli con il pensiero.

Il secondo Commodore 64: perché Linux è ancora un giocattolo per adulti

Ci sono generazioni che si riconoscono da un rumore.
La mia, per esempio, la riconosci dal suono secco di un tasto “RUN/STOP”, dal gracchiare di un registratore a cassette, da quella riga blu con scritto “READY.” che ti guardava come una sfida più che come un messaggio di cortesia. Prima di avere “i computer”, abbiamo avuto il computer-giocattolo. Che non era un giocattolo nel senso di plastica colorata, ma nel senso serio del termine: un oggetto che ti chiede di essere toccato, smontato, travisato, forzato oltre il manuale d’uso. Il Commodore 64, il TI-99/4A, quegli 8 bit lì. Accendevi, e non c’era la schermata delle app. C’era un prompt. Non «che cosa vuoi fare», ma: «cosa sai dire». Non ti offriva programmi, ti offriva linguaggio.
Poi sono arrivati gli anni “seri”. MS-DOS, i primi PC “per il lavoro”, i software di contabilità, i word processor. Il computer cominciava a parlare la lingua delle fatture, non più quella dei sogni. Non ti chiedeva più di inventare: ti chiedeva di compilare. Uscivi dall’infanzia dell’informatica e entravi nell’età adulta: solida, utile, assolutamente necessaria. Anche un po’ noiosa. In mezzo, un passaggio quasi invisibile: da una macchina che ti invitava a programmare, a una macchina che ti invitava a consumare software. E poi, da qualche parte tra la fine dei ’90 e i primi anni Duemila, è arrivato quel coso strano che era troppo complicato per il grande pubblico e troppo “giocattolo” per l’industria: Linux. Io continuo a pensarci come al “secondo Commodore 64”. Non perché graficamente gli assomigliasse — anzi, spesso non assomigliava a niente di presentabile — ma per il ruolo che ha avuto. Linux non si installava perché “serviva per lavorare”. Per quello c’erano già i sistemi “seri”: Unix commerciale, Windows NT, le cose con le licenze, le brochure patinate e il supporto tecnico a pagamento. Linux lo installavi per vedere cosa c’era sotto il cofano. Per scoprire che faccia ha davvero un sistema operativo quando smetti di guardarlo dall’icona “Risorse del computer” e cominci a parlarci in shell. Era un sistema complicato, pieno di spigoli, spesso ostile. Ma era tuo.
Il gioco non era trovare la “killer app”. Il gioco era il sistema operativo stesso: far riconoscere una scheda di rete, ricompilare il kernel, capire perché quel demone non partiva al boot. Il divertimento era «capire». E questa, per quella generazione, somigliava moltissimo alla felicità.
Col tempo, però, ti accorgi che Linux non era solo quell’esercizio di stile di un ragazzo finlandese geniale. Era una specie di collante che teneva insieme decenni di storia Unix: pezzi di codice nati nelle università, negli AT&T Bell Labs, nei corridoi di Berkeley; strumenti scritti da gente che voleva solo un compilatore decente, un editor migliore, una shell più potente. Quando parlavi di “Linux”, in realtà stavi parlando di un mosaico: il kernel, i tool GNU, il codice di derivazione BSD, linguaggi buttati lì da ricercatori curiosi e rimasti perché “funzionavano”. Era, tecnicamente, un minestrone. Ma di quelli buoni, quelli che vengono da giorni e giorni di ingredienti aggiunti, di pentola che sobbolle, di assaggi e correzioni di sale. Mentre altrove si costruivano cattedrali eleganti e coerenti, con linee di codice scolpite come colonne ioniche, il mondo Linux cresceva come crescono i mercati rionali: disordinato, rumoroso, pieno di roba che non sai neanche bene da dove arrivi, ma nel complesso vivo, potentissimo. E la verità bruta è che ha vinto quello. Ha vinto il minestrone. Non perché fosse più bello, ma perché era più aperto, più rapido, più disposto a sporcarsi le mani. Mentre certi sistemi si prendevano il tempo di essere perfetti, Linux si prendeva il rischio di essere usabile, portabile, adattabile. Smetteva di chiedersi “sono puro?” e cominciava a chiedersi “giro qui? giro là? posso stare anche su quell’architettura?”. E così, quasi per accumulo, da giocattolo per smanettoni è diventato il pavimento su cui appoggiava i piedi mezza Internet. LAMP non è mai stato uno slogan particolarmente poetico, ma ha raccontato una rivoluzione: Linux, Apache, MySQL, PHP. Start-up che nascevano su server che nessuno aveva pagato in licenze, studenti che montavano siti in cameretta usando software che nessun consiglio di amministrazione aveva scelto per loro.
Quando una tecnologia smette di essere “divertente” e diventa “infrastruttura”, succede una cosa strana: vince, ma si mimetizza. Oggi Linux è dappertutto e quasi mai si vede. Sta dietro a router, server, telefoni, televisori, auto, perfino lavatrici. È passato dal feticcio dell’hacker alla condizione atmosferica: è “l’aria di fondo” dell’informatica contemporanea. Ed è proprio lì che un po’ di magia si perde. Perché quando qualcosa diventa indispensabile, smette di sembrare interessante.
I ragazzi di oggi non vedono più il prompt come un invito all’avventura: vedono l’icona della rete che non va, il wifi che cade, il login che non si ricorda la password. Vedono il lato “sistemista” del gioco, non quello esplorativo. L’idea che si possa installare un sistema operativo “solo per vedere come funziona” sembra quasi una stramberia da adulti nostalgici. E forse, in parte, lo è. Ma è una stramberia che mi piacerebbe rivendicare con orgoglio.
Penso che servirebbe tornare a parlare di Linux — e, più in generale, dei sistemi aperti — con un po’ di hype. Non l’hype da keynote con i droni sul palco e le parole “magico”, “incredibile”, “mai visto prima” ripetute come un mantra. Un hype onesto, artigianale: quello negli occhi di chi ti racconta una cosa che ha provato, che conosce, che gli è costata ore di sbattimenti ma gli ha lasciato addosso la sensazione precisa di aver capito qualcosa in più del mondo.
Ogni tanto capita di incontrare persone che, quando parlano di hardware, di driver, di kernel, si illuminano. Non fanno divulgazione per mestiere, non vendono corsi: stanno semplicemente condividendo una gioia, una mania, un pezzo di identità. In quei momenti ti ricordi perché avevi acceso il primo computer non per mandare una mail, ma per vedere cosa succedeva se scrivevi 10 PRINT "CIAO" e poi 20 GOTO 10. E allora ti viene questa idea un po’ assurda: comprarti un portatile non perché ti serve, ma perché vuoi appartenerci di nuovo. Non un ultrabook perfetto per la produttività, non il mostro da gaming con i LED ovunque. Un laptop onesto, smontabile, su cui installare una distribuzione solo per il gusto di vedere cosa va, cosa non va, cosa devi piegare, che incantesimi bisogna recitare per far riconoscere la GPU o far andare lo standby. Non ti serve per lavorare: per quello hai già la macchina solida, ottimizzata, senza sorprese.
Ti serve per giocare sul serio. Per fare quello che facevi a dodici anni, ma con la consapevolezza di adesso: aprire un terminale, tirare giù un sorgente, leggere un man, perdersi in una configurazione, rompere qualcosa e doverlo sistemare. Non perché sia “utile”, non perché ci farai soldi, ma perché credi ancora che dietro quei processi, quei log, quei file in /etc si nasconda una lingua che vale la pena di imparare.
Forse questo, oggi, è il vero gesto controcorrente: usare una macchina potente non per produrre di più, ma per capire di più. E magari, nel farlo, farti vedere da qualcuno più giovane di te. Un figlio, uno studente, un ragazzo che pensa che il computer sia solo la scatola dove girano social e videogiochi. Fargli vedere che esiste un livello in più, sotto i menù e sopra l’hardware, dove le cose non si scaricano soltanto: si costruiscono. Non so se basterà a cambiare qualcosa. Ma so che, per una certa generazione, Linux è stato davvero il secondo Commodore 64. E che forse è arrivato il momento di trattarlo di nuovo così: non come una presenza scontata, ma come un invito.
Accendi, appare il prompt, lampeggia un cursore.
Ti chiede, ancora una volta: non “cosa devi fare”.
Ma: “cosa vuoi imparare a dire”.

…saper anticipare il cambiamento prima che sia troppo tardi.

L’ingresso di DeepSeek nel panorama dell’intelligenza artificiale ha scosso gli equilibri consolidati del settore, lasciando investitori, esperti e aziende occidentali in un misto di stupore, incredulità e inquietudine. La startup cinese, fino a poche settimane fa pressoché sconosciuta, ha presentato due modelli di AI—V3 e R1—che sembrano reggere il confronto con i migliori prodotti di OpenAI e Google DeepMind, ma con un’efficienza di calcolo sorprendente e costi drasticamente inferiori. Se le cifre dichiarate da DeepSeek sono veritiere, la narrazione dominante secondo cui la supremazia nell’AI sarebbe appannaggio esclusivo delle grandi corporation americane viene messa seriamente in discussione. Questo evento segna un possibile cambio di paradigma, non solo nel settore tecnologico, ma anche nell’ambito geopolitico ed economico. L’intelligenza artificiale non è soltanto un tema di innovazione, ma anche un asset strategico che può determinare il primato di un Paese su un altro. Gli Stati Uniti si erano illusi di poter mantenere la Cina in una posizione di rincorsa permanente grazie a severe restrizioni sull’export di chip avanzati. Ma DeepSeek, con un colpo di scena degno della migliore tradizione della tecnologia disruptiva, sembra aver dimostrato che l’AI non è solo una questione di hardware, ma soprattutto di efficienza algoritmica. Ed è proprio su questo punto che si concentrano le domande più pressanti.
L’annuncio di DeepSeek ha generato una reazione a catena di proporzioni storiche. Le azioni delle principali aziende di AI americane, comprese OpenAI e Google, hanno registrato una contrazione significativa, mentre Nvidia, il colosso dei microchip, ha subito una caduta in borsa, segnale evidente di un’improvvisa perdita di fiducia da parte degli investitori. Il motivo è chiaro: se davvero un’azienda con risorse limitate ha ottenuto prestazioni paragonabili ai migliori modelli occidentali usando una frazione dell’hardware e dell’energia, il business dell’AI potrebbe essere radicalmente trasformato. Tuttavia, il quadro è ancora nebuloso. La comunità tecnologica si sta affannando a esaminare ogni riga di codice, ogni parametro di addestramento e ogni dettaglio dell’infrastruttura di DeepSeek per rispondere a due domande fondamentali. La prima riguarda la presunta efficienza senza precedenti. La riduzione dell’uso di chip e il taglio drastico dei costi di addestramento potrebbero dipendere da ottimizzazioni software rivoluzionarie oppure, al contrario, da una sottostima dei costi effettivi. Alcuni analisti suggeriscono che l’azienda potrebbe aver omesso spese legate alla ricerca, ai salari e all’infrastruttura, per creare un effetto mediatico dirompente. Anche se il costo fosse superiore a quello dichiarato, tuttavia, il solo fatto che DeepSeek si sia avvicinata alle prestazioni di OpenAI con un investimento ridotto sarebbe comunque un segnale dirompente. La seconda questione è ancora più delicata: quanto è “originale” DeepSeek?
L’altro grande interrogativo riguarda la provenienza dei dati e delle architetture utilizzate. Alcuni sospettano che DeepSeek possa aver sfruttato, legalmente o meno, tecnologie occidentali per il proprio addestramento. Il rischio di un “free riding tecnologico” è una delle preoccupazioni principali negli Stati Uniti, dove si teme che le restrizioni sui chip imposte alla Cina abbiano generato una risposta non ortodossa: il riuso, o addirittura il furto, delle tecnologie AI sviluppate in Occidente. Se DeepSeek ha veramente trovato un modo per ottenere prestazioni di alto livello con hardware più economico e meno dispendio energetico, il modello di business dell’AI su larga scala potrebbe cambiare per sempre. Ma se i suoi risultati fossero frutto di pratiche poco trasparenti o di un uso massiccio di tecnologia già esistente, allora il suo impatto potrebbe ridimensionarsi rapidamente.
Un altro aspetto fondamentale riguarda la questione dell’open-source nell’AI, un tema che è diventato centrale nel dibattito contemporaneo. Nell’ambito del software tradizionale, il concetto di open-source si riferisce alla possibilità di accedere, modificare e ridistribuire il codice sorgente. Nell’intelligenza artificiale, però, la situazione è molto più complessa. Un sistema di AI non è solo un insieme di istruzioni codificate, ma dipende in modo critico dai dati di addestramento. È proprio qui che nasce il problema: un’AI può essere tecnicamente open-source nel senso che il suo codice è disponibile, ma se i dati utilizzati per l’addestramento rimangono proprietari, la riproducibilità e l’accessibilità reale del modello restano fortemente limitate. Alcuni progetti come Meta Llama o Mistral AI hanno cercato di adottare un approccio più aperto rispetto a OpenAI e Google, ma anche in questi casi i dataset completi non sono resi pubblici, lasciando aperta la questione della vera accessibilità.
La strategia di DeepSeek sembra collocarsi in una posizione ambigua su questo fronte. Se da un lato ha reso pubblica parte della documentazione scientifica sui propri modelli, dall’altro resta il dubbio sulla trasparenza reale dei dati utilizzati per l’addestramento. Se il successo di DeepSeek dipendesse dall’aver sfruttato massicciamente dataset occidentali già esistenti, senza una chiara attribuzione o senza un vero accesso open-source, allora la sua innovazione sarebbe meno rivoluzionaria di quanto si voglia far credere. Al contrario, se DeepSeek avesse sviluppato nuove tecniche di addestramento capaci di ottenere prestazioni elevate con dati meno costosi o meno numerosi, allora il suo contributo all’AI potrebbe risultare una svolta autentica, aprendo la strada a modelli più leggeri ed efficienti accessibili a una gamma più ampia di aziende e istituzioni.
Se la rivoluzione promessa da DeepSeek si confermerà, avremo davanti tre principali conseguenze. La prima riguarda la fine dell’oligopolio dell’AI, con l’emergere di realtà più piccole in grado di competere grazie a innovazioni algoritmiche anziché a pura potenza di calcolo. La seconda conseguenza è geopolitica, con la ridefinizione degli equilibri di potere tra Stati Uniti e Cina e la possibilità che il governo americano riconsideri le sue strategie di controllo tecnologico. Infine, la terza riguarda il mercato finanziario, con il rischio di una bolla speculativa sulle aziende AI attualmente dominanti e una possibile ridefinizione del valore del settore.
Siamo di fronte a una svolta epocale o a un fuoco di paglia? DeepSeek rappresenta una rivoluzione tecnologica autentica o solo un abile gioco di marketing? Al momento, le risposte definitive non ci sono. Tuttavia, l’evento ha già avuto un impatto enorme: ha scosso la fiducia delle Big Tech americane, ha acceso il dibattito sul futuro dell’AI e ha sollevato questioni geopolitiche di vasta portata. Se DeepSeek riuscirà a mantenere le promesse e a resistere allo scrutinio globale, avremo la prova che l’efficienza può battere la potenza bruta, e che l’AI avanzata non è più un gioco esclusivo per chi ha miliardi da investire. In caso contrario, resterà comunque l’ammonimento che la superiorità tecnologica non è mai definitiva, e che nessuna nazione o azienda può permettersi di dormire sugli allori in un settore in così rapida evoluzione. La vera intelligenza, forse, sarà quella di saper anticipare il cambiamento prima che sia troppo tardi.

Archlinux…

Oh, damn! I definitely need to shave and get myself a pair of knee-high socks!

Creare un’interfaccia utente in SwiftUI per controllare la torcia del tuo dispositivo iOS

In questa esercitazione, svilupperemo un’app iOS che userà SwiftUI per creare un’interfaccia utente (UI) interattiva per controllare la torcia del tuo dispositivo.

Il codice sarà strutturato in modo da permettere all’utente di accendere e spegnere la torcia premendo un pulsante. Quando la torcia è accesa, mostreremo un’immagine con la dicitura “ON AIR” e quando è spenta, l’immagine diventerà invisibile.

Vediamo il codice passo per passo:

import SwiftUI
import AVFoundation

All’inizio del file, importiamo i framework necessari. SwiftUI ci offre gli strumenti per costruire l’interfaccia utente, mentre AVFoundation ci permette di controllare l’hardware della fotocamera, che include la torcia.

struct ContentView: View {
    @State private var torch = false

Qui definiamo una nuova struct chiamata ContentView che aderisce al protocollo View di SwiftUI. Questa sarà la vista principale della nostra app. L’attributo @State è una proprietà di SwiftUI che permette di creare una variabile reattiva. In questo caso, stiamo usando torch per tracciare se la torcia è accesa (true) o spenta (false).

var body: some View {
        ZStack {
            onAirView

            VStack {
                Spacer()
                actionButton
            }
        }
        .padding()
        .background(Color.black)
        .edgesIgnoringSafeArea(.all)
    }

Il blocco body definisce la struttura principale dell’interfaccia utente. ZStack impila le viste l’una sopra l’altra. La nostra onAirView viene mostrata prima, seguita da un VStack che contiene un pulsante di azione (actionButton).

Notiamo che abbiamo impostato lo sfondo su nero utilizzando .background(Color.black) e abbiamo fatto sì che lo sfondo si estenda fino ai bordi dello schermo con .edgesIgnoringSafeArea(.all).

var onAirView: some View {
        VStack {
            Image("on_air")
                .resizable()
                .scaledToFit()
                .opacity(torch ? 1.0 : 0.0)
            Spacer()
        }
    }

onAirView è un’altra vista personalizzata. Qui, un’immagine con la dicitura “ON AIR” viene mostrata se la torcia è accesa. La vista Image viene resa ridimensionabile e adatta alla sua contenitore con .resizable() e .scaledToFit(). L’immagine diventa completamente trasparente quando la torcia è spenta, rendendola invisibile, grazie a .opacity(torch ? 1.0 : 0.0). Il Spacer() posiziona l’immagine in alto nello schermo.

var actionButton: some View {
        Button(action: {
            torch.toggle()
            toggleTorch(on: torch)
        }) {
            ZStack {
                if torch {
                    Color.red
                    Image(systemName: "power").foregroundColor(.white)
                }
                else {
                    Color.blue.opacity(0.1)
                    Image(systemName: "power").foregroundColor(.secondary)
                }
            }.frame(maxWidth:50, maxHeight: 50)
            .cornerRadius(15)
        }
    }

actionButton è il pulsante che l’utente preme per accendere o spegnere la torcia. Il colore e l’icona del pulsante cambiano in base allo stato della torcia. Usiamo la funzione toggleTorch(on:) per cambiare effettivamente lo stato della torcia sul dispositivo.

The Game of Life…

Esporremo brevemente come creare un’applicazione iOS per il Gioco della Vita, un automa cellulare ideato dal matematico britannico John Horton Conway, utilizzando Swift e SwiftUI.

Struttura del codice

Il codice è suddiviso in tre parti principali:

  1. La classe GameOfLife, che gestisce la logica del gioco.
  2. La vista GridView, che visualizza la griglia del gioco.
  3. La vista ContentView, che contiene i controlli del gioco e include GridView.

1. La Classe GameOfLife

La classe GameOfLife si occupa della logica e dello stato del gioco. Utilizza l’annotazione @Published per segnalare a SwiftUI quando determinate proprietà cambiano, provocando il re-rendering dell’interfaccia utente.

  • Inizializzazione: Genera una griglia di dimensioni specificate, con ogni cellula settata in modo casuale a vivente o morta.
  • toggleCell(x: Int, y: Int): Cambia lo stato di una cellula specifica (viva diventa morta, morta diventa viva).
  • startOrStop(): Inizia o ferma l’evoluzione del gioco.
  • reset(): Ferma il gioco e genera una nuova griglia casuale.
  • nextGeneration(): Calcola la prossima generazione della griglia in base alle regole del Gioco della Vita.
  • aliveNeighbours(x: Int, y: Int): Conta i vicini vivi di una determinata cellula.

2. La Vista GridView

Questa vista visualizza la griglia del gioco. Utilizza un VStack di HStacks per creare la griglia, con un rettangolo per ogni cellula. Il colore del rettangolo dipende dallo stato della cellula (nero per vivente, bianco per morto). Un tap su un rettangolo inverte lo stato della cellula corrispondente.

3. La Vista ContentView

ContentView è la vista principale dell’app. Contiene una GridView e due pulsanti per controllare il gioco: uno per avviare/fermare l’evoluzione del gioco e l’altro per resettare il gioco.

La Logica del Gioco della Vita

La logica del Gioco della Vita è implementata nel metodo nextGeneration() della classe GameOfLife. Le regole del gioco sono le seguenti:

  • Una cellula viva con meno di due vicini vivi muore.
  • Una cellula viva con due o tre vicini vivi sopravvive.
  • Una cellula viva con più di tre vicini vivi muore.
  • Una cellula morta con esattamente tre vicini vivi diventa una cellula viva.
func nextGeneration() {
    var newGrid = grid
    for x in 0..<grid.count {
        for y in 0..<grid[x].count {
            let aliveNeighbours = self.aliveNeighbours(x: x, y: y)
            if grid[x][y] {
                if aliveNeighbours < 2 || aliveNeighbours > 3 {
                    newGrid[x][y] = false
                }
            } else if aliveNeighbours == 3 {
                newGrid[x][y] = true
            }
        }
    }
    grid = newGrid
}

Queste regole vengono applicate simultaneamente a tutte le cellule della griglia per calcolare la prossima generazione.

Il peso di un mazzo di fogli di carta…

SwiftUI, il framework di Apple per lo sviluppo di interfacce utente, offre un modello di programmazione dichiarativo che rende semplice la creazione di interfacce utente complesse. In questo articolo, esploreremo come utilizzare SwiftUI per creare un’applicazione che calcola il peso totale di un mazzo di fogli di carta data la dimensione, la grammatura e il numero di fogli.

Questa applicazione può essere molto utile in vari contesti. Ad esempio, può essere utilizzata in un ufficio per stimare il peso di un mazzo di documenti prima di spedirli, o in una tipografia per calcolare il peso di un lotto di carta prima di stamparlo. Inoltre, può essere utilizzata in ambito educativo per insegnare concetti di matematica e fisica, come l’area, la densità e il peso.

import SwiftUI

struct ContentView: View {
    @State private var length = ""
    @State private var width = ""
    @State private var grammage = ""
    @State private var numberOfSheets = ""
    @State private var weight: String = "0"

    var body: some View {
        Form {
            Section(header: Text("Dimensioni del foglio")) {
                TextField("Lunghezza in cm", text: $length, onEditingChanged: { _ in weight = "0" })
                    .keyboardType(.decimalPad)
                TextField("Larghezza in cm", text: $width, onEditingChanged: { _ in weight = "0" })
                    .keyboardType(.decimalPad)
            }
    
            Section(header: Text("Grammatura")) {
                TextField("Grammatura in g/m^2", text: $grammage, onEditingChanged: { _ in weight = "0" })
                    .keyboardType(.decimalPad)
            }
    
            Section(header: Text("Numero di fogli")) {
                TextField("Numero di fogli", text: $numberOfSheets, onEditingChanged: { _ in weight = "0" })
                    .keyboardType(.decimalPad)
            }
    
            Section(header: Text("Peso totale dei fogli")) {
                TextField("", text: $weight)
                    .disabled(true)
            }
    
            Button(action: calculatePaperWeight) {
                Text("Calcola Peso")
            }
        }
    }
    
    func calculatePaperWeight() {
        guard let length = Double(length), let width = Double(width), let grammage = Double(grammage), let numberOfSheets = Double(numberOfSheets) else {
            weight = "0"
            return
        }
    
        // Convert cm to m
        let lengthInM = length / 100
        let widthInM = width / 100
    
        let area = lengthInM * widthInM
        let weightValue = area * grammage * numberOfSheets
    
        // Convert weight to kilograms
        let weightInKg = weightValue / 1000
    
        weight = String(format: "%.2f", weightInKg)
    }

}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

L’interfaccia utente dell’applicazione è composta da quattro sezioni per l’inserimento dei dati e un pulsante per attivare il calcolo. Le sezioni sono create utilizzando l’oggetto Section di SwiftUI, che consente di raggruppare logicamente i controlli dell’interfaccia utente. Le prime tre sezioni contengono TextField per l’inserimento della lunghezza e della larghezza del foglio di carta, la grammatura del foglio e il numero di fogli. La quarta sezione contiene un TextField disabilitato che visualizza il peso totale dei fogli di carta in chilogrammi.

Il pulsante “Calcola Peso” è creato utilizzando l’oggetto Button di SwiftUI. Quando l’utente preme questo pulsante, viene chiamata la funzione calculatePaperWeight, che calcola il peso totale dei fogli di carta.

SwiftUI utilizza un modello di gestione dello stato reattivo. In questo caso, utilizziamo la proprietà @State per creare delle variabili di stato per la lunghezza, la larghezza, la grammatura, il numero di fogli e il peso totale dei fogli. Queste variabili sono collegate ai TextField corrispondenti nell’interfaccia utente tramite il meccanismo di binding di SwiftUI, che consente di mantenere sincronizzati lo stato dell’applicazione e l’interfaccia utente.

Il peso totale dei fogli di carta viene calcolato utilizzando la formula:

Peso totale = Area * Grammatura * Numero di fogli

dove l’Area è calcolata come Lunghezza * Larghezza (in metri quadrati), la Grammatura è data in grammi per metro quadrato (g/m^2), e il Numero di fogli è il numero di fogli nel mazzo. Questo calcolo viene eseguito nella funzione calculatePaperWeight, che viene chiamata quando l’utente preme il pulsante “Calcola Peso”.

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.

Bug…

Il primo bug…

…alla ricerca degli errori presenti nei miei programmi.