# PrimeGenerator

In questo esempio andremo a scrivere una classe che genera dei numeri primi fino a un massimo specificato dall'utente.

### Prima del refactoring

```
<?php

/**
 * Questa classe genera dei numeri primi fino a un massimo specificato dall'utente.
 * L'algoritmo usato è il Setaccio di Eratostene.
 * Eratostene di Cirene fu il primo uomo a calcolare la circonferenza della Terra.
 * Noto anche per aver lavorato sui calendari con anni bisestili e aver gestito la libreria di Alessandria.
 * L'algoritmo è semplice. Dato un array di interi che partono da 2. Elimina tutti i multipli di 2.
 * Trova il prossimo intero disponibile ed elimina tutti i suoi multipli.
 * Ripeti fino ad aver superato la radice quadrata del valore massimo.
 */
class GeneratePrimes
{

    /**
     * @param int $maxValue è il limite della generazione
     *
     * @return int[]
     */
    public static function generate(int $maxValue): array
    {
        // L'unico caso valido
        if ($maxValue >= 2) {
            // Dichiarazioni
            $s = $maxValue + 1; // Dimensione dell'array
            $f = [];

            // Inizializza l'array a true
            for ($i = 0; $i < $s; $i++) {
                $f[$i] = true;
            }

            // Elimina i non-primi
            $f[0] = $f[1] = false;

            // Setaccio
            for ($i = 2; $i < sqrt($s) + 1; $i++) {
                // Se i è primo, elimina i suoi multipli
                if ($f[$i]) {
                    for ($j = 2 * $i; $j < $s; $j += $i) {
                        $f[$j] = false; // Un multiplo non può essere primo
                    }
                }
            }

            // Quanti primi ci sono?
            $count = 0;
            for ($i = 0; $i < $s; $i++) {
                if ($f[$i]) {
                    $count++;
                }
            }

            // Sposto i primi nel risultato
            $primes = [];
            for ($i = 0, $j = 0; $i < $s; $i++) {
                // Se è primo
                if ($f[$i]) {
                    $primes[$j++] = $i;
                }
            }

            return $primes;
        } else { // $maxValue < 2
            return [];
        }
    }
}
```

### Dopo il refactoring

```
<?php

/**
 * Questa classe genera dei numeri primi fino a un massimo specificato dall'utente.
 * L'algoritmo usato è il Setaccio di Eratostene.
 * Dato un array di interi a partire da 2:
 * - trova il primo intero non eliminato ed elimina tutti i suoi multipli
 * - ripeti finché non vi sono più multipli nell'array
 */
class PrimeGenerator
{
    private static $crossedOut = [];
    private static $result = [];

    public static function generate(int $maxValue): array
    {
        if ($maxValue < 2) {
            return [];
        }

        self::uncrossIntegersUpTo($maxValue);
        self::crossOutMultiples();
        self::putUncrossedIntegersIntoResult();

        return self::$result;
    }

    private static function uncrossIntegersUpTo(int $maxValue): void
    {
        for ($i = 0; $i < $maxValue + 1; $i++) {
            self::$crossedOut[$i] = false;
        }
    }

    private static function crossOutMultiples(): void
    {
        $limit = self::determineIterationLimit();
        for ($i = 2; $i <= $limit; $i++) {
            if (self::notCrossed($i)) {
                self::crossOutMultiplesOf($i);
            }
        }
    }

    /**
     * Ogni multiplo nell'array ha un fattore primo che è minore o uguale alla radice
     * delle dimensioni dell'array, così che possiamo evitare di eliminare i multipli
     * dei numeri maggiori di tale radice
     * @return int
     */
    private static function determineIterationLimit(): int
    {
        return (int)sqrt(count(self::$crossedOut));
    }

    private static function notCrossed(int $i): bool
    {
        return self::$crossedOut[$i] === false;
    }

    private static function crossOutMultiplesOf(int $i): void
    {
        for ($multiple = 2 * $i; $multiple < count(self::$crossedOut); $multiple += $i) {
            self::$crossedOut[$multiple] = true;
        }
    }

    private static function putUncrossedIntegersIntoResult()
    {
        for ($j = 0, $i = 2; $i < count(self::$crossedOut); $i++) {
            if (self::notCrossed($i)) {
                self::$result[$j++] = $i;
            }
        }
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mirkorap16.gitbook.io/clean-code/esempi/primegenerator.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
