Paramètrages
Notre zone s'étend sur 200 zones
-34-33-32-31-30-29-28-27-26-25-24-23-22-21-20-19-18-17-16-15-14-13-12-11-10-9-8-7-6-5-4-3-2-1012
-10                                   -10
-9                                   -9
-8                                   -8
-7                                   -7
-6                                   -6
-5                                   -5
-4                                   -4
-3                                   -3
-2                                   -2
-1                                   -1
0                                   0
1                                   1
2                                   2
3                                   3
4                                   4
5                                   5
6                                   6
7                                   7
8                                   8
9                                   9
10                                   10
11                                   11
12                                   12
-34-33-32-31-30-29-28-27-26-25-24-23-22-21-20-19-18-17-16-15-14-13-12-11-10-9-8-7-6-5-4-3-2-1012
        Afficher le codeMasquer le code
        <!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Génération de zone maspero.blue</title>
    <style>
        table{
            padding: 2em;
            border-spacing: 0;
            background: lightgrey;
        }

        #espace:checked ~ table{
            border-spacing: 1px;
        }

        tr:last-child, tr:first-child, td:first-child, td:last-child{
            visibility: hidden;
        }

        #regle:checked ~ label ~ table tr:last-child, 
        #regle:checked ~ label ~ table tr:first-child, 
        #regle:checked ~ label ~ table td:first-child, 
        #regle:checked ~ label ~ table td:last-child{
            visibility: visible;
        }

        td{
            width: 1em;
            height: 1em;
            line-height: 0;
            font-size: 1em;
            background: green;           
        }

        td.zone{
            background-color: brown;
        }

        td.rivage{
            background-color: sandybrown;
        }

        label{
            display: block;
        }

        pre{
            position: relative;
            padding: 1em 2em;
        }


        code{
            width: 100%;
            height: 50em;
            display: none;
            border: 1px solid black;
            overflow: auto;
            margin: 2em 0;
        }
        
        code:target{
            display: block;
        }

        pre a{
            position: absolute;
            left: 4em;
        }

        a[href="#top"] {
            display: none;
        }

        pre:target > code {
            display: block;
        }
        
        pre:target > a:nth-child(1) {
            display: none;
        }
        
        pre:target > a:nth-child(2) {
            display: inherit;
        }
 
    </style>    
</head>
<body id="top">
<?php
    $taille     = isset($_GET['taille'])   ? $_GET['taille']  : 200;
    $densite    = isset($_GET['densite'])  ? $_GET['densite'] : 2;
    $pixel      = isset($_GET['pixel'])    ? $_GET['pixel'] == 'on' : false;
    $regle      = isset($_GET['regle'])    ? $_GET['regle'] == 'on' : false;
    ?>
    <form action="" method="GET">
    <fieldset>
        <legend>Paramètrages</legend>
        <label>Taille de la zone <input name="taille" type="number" value="<?= $taille ?>" /></label>
        <label>Densité 
            <select name="densite">
                <?php
                    foreach (['Forte - tout se touche)', 'Moins Forte', 'Faible', 'Tres Faible - grande carte'] as $key => $val ){
                        $key++;
                        echo '<option value="' . $key . '" ' . ($key == $densite ? 'selected="selected"' : '') .">$val</option>";
                    }
                ?>
            </select>
        </label>
        <button type="submit" name="submit">Générer la zone</button>
    </fieldset>
    <?php
        // Si on a pas GETé le formulaire, on ne calcul rien
        if(isset($_GET['submit'])){;
            function calculerZone(&$res, &$lat, &$lon, $taille, $densite){
                $valDens = rand(1, 4 * $densite);
                $pasDens = ceil($valDens / 4);
                switch($valDens % 4){
                    case 0: $lat -= $pasDens; break;
                    case 1: $lon -= $pasDens; break;
                    case 2: $lat += $pasDens; break;
                    case 3: $lon += $pasDens; break;
                }
    
                $point = "$lat:$lon";
                
                if(!in_array($point, $res)){ // Existe pas encore, on a un nouveau point
                  $res[] = $point;  
                } else {
                    // Pour debug
                    $point;
                } 
                
                // Si on est en densité, on essaye quand même de trouver une zone proche
                if(count($res)<$taille){
                    $ret = true;
                    if($densite % 2 == 0){
                        $ret = calculerZone($res, $lat, $lon, $taille, $densite - 1);
                    }
                    return $ret;
                }
                
                return false;
            }
    
            $res=[];
            
            // On ne fait pas du recursif au cas ou on depasse le maximum d'imrication, si on demande un "gros" nombre
            $continue   = true;
            $lat        = 0;
            $lon        = 0;
            $antiLoop   = 0;
            
            do{
                if($continue = calculerZone($res, $lat, $lon, $taille, $densite)){
                    $antiLoop = 0;
                }
            }
            while( ++$antiLoop < 1000 && $continue );
    
            if($antiLoop > 1000){
                echo "<h1>Impossible de calculer la totalité de la zone</h1>";
            }
            
            
            //$res = unserialize('a:50:{i:5;s:5:"-1:-2";i:14;s:4:"-1:1";i:15;s:4:"-1:2";i:16;s:4:"-1:3";i:22;s:4:"-1:5";i:18;s:4:"-2:2";i:19;s:4:"-2:3";i:20;s:4:"-2:4";i:21;s:4:"-2:5";i:2;s:4:"0:-1";i:4;s:4:"0:-2";i:13;s:3:"0:1";i:17;s:3:"0:3";i:24;s:3:"0:4";i:23;s:3:"0:5";i:1;s:4:"1:-1";i:3;s:4:"1:-2";i:45;s:4:"1:-3";i:0;s:3:"1:0";i:12;s:3:"1:1";i:25;s:3:"1:3";i:7;s:4:"2:-1";i:6;s:4:"2:-2";i:43;s:4:"2:-3";i:44;s:4:"2:-4";i:10;s:3:"2:0";i:11;s:3:"2:1";i:39;s:3:"2:2";i:26;s:3:"2:3";i:27;s:3:"2:4";i:8;s:4:"3:-1";i:9;s:3:"3:0";i:41;s:3:"3:1";i:40;s:3:"3:2";i:30;s:3:"3:3";i:28;s:3:"3:4";i:47;s:4:"4:-1";i:46;s:3:"4:0";i:42;s:3:"4:1";i:32;s:3:"4:2";i:31;s:3:"4:3";i:29;s:3:"4:4";i:33;s:3:"4:5";i:34;s:3:"4:6";i:48;s:3:"5:0";i:49;s:3:"5:1";i:38;s:3:"5:2";i:37;s:3:"5:3";i:35;s:3:"5:4";i:36;s:3:"5:5";}');
            
    
            // On affiche la "montage"
            // On doit calculer le min-max des deux directions
    
            $tailleLon = [9999, 0];
            $tailleLat = [9999, 0];
    
            foreach($res as $direction){
                $direction = explode(':', $direction);
                $tailleLat[0] = min($tailleLat[0], $direction[0]);
                $tailleLat[1] = max($tailleLat[1], $direction[0]);
                $tailleLon[0] = min($tailleLon[0], $direction[1]);
                $tailleLon[1] = max($tailleLon[1], $direction[1]);
            }
    
    
            
            // On recupère les valeurs de notre tableau de resultat
            $zones = array_values($res);    // On extrait les valeurs 
            natsort($zones); // Pas necessaire mais bien pour le debug, un tri alpha

            // On s'occupe de déterminer les rivages, est un rivage une zone qui a au moins un voisin inconnu, simple et juste à chaque fois
            $rivages=[];
            foreach($zones as $zone){
                $coords         = explode(':', $zone);
                $j              = $coords[0];
                $i              = $coords[1];
                $point          = "$j:$i";
                $voisins['o']   = sprintf("%d:%d", $j-1,$i);
                $voisins['e']   = sprintf("%d:%d", $j+1,$i);
                $voisins['n']   = sprintf("%d:%d", $j,$i-1);
                $voisins['s']   = sprintf("%d:%d", $j,$i+1);
                
                foreach($voisins as $voisin){
                    // Notre point n'est pas dans nos zones connues, c'est un rivage
                    if(!in_array($voisin, $zones)){
                        $rivages[] = $zone;
                        break;
                    }
                }
            }

            

            // On dessine la zone dans un tableau, on ajoute volontairement une serie pour les bordures
            $tailleLon[0]-=2; $tailleLon[1]+=2; 
            $tailleLat[0]-=2; $tailleLat[1]+=2;
    
            //echo '<textarea>' . serialize($zones) . '</textarea>';

            $o   = ['<table>'];
            $o[] = "<caption>Notre zone s'étend sur $taille zones</caption>";
    
    
            for($i=$tailleLon[0];$i<=$tailleLon[1];$i++){
                $o[] ='<tr>';
                for($j=$tailleLat[0];$j<=$tailleLat[1];$j++){
                    $point      = "$j:$i";
                    $content    = "&nbsp;";

                    if($j == $tailleLat[0] || $j == $tailleLat[1]) $content = $i;
                    if($i == $tailleLon[0] || $i == $tailleLon[1]) $content = $j; 

                    $className  = [];
                    // Le point existe dans nos résultats    
                    if(in_array($point, $zones)){
                        $className[] = 'zone';
                    }
                    // Gestion des rivages
                    if(in_array($point, $rivages)){
                        $className[]    = 'rivage';
                    }
    
                    $o[] ='<td title="Coordonnées: ' . $point . '" class="' . implode(' ', $className) . '">' . $content . '</td>';
                }
                $o[] ='</tr>';
                
            }
    
            
            $o[] ='</table>';
            
            echo '<label for="regle">Afficher les règles</label><input id="regle" name="regle" type="checkbox" ' . ($regle ? 'checked="checked"':'') .' />';
            echo '<label for="espace">Espacer les cellules</label><input id="espace" name="pixel" type="checkbox" ' . ($pixel ? 'checked="checked"':'') .' />';
            echo implode('', $o);
        }
    ?>
    </form>
    <pre id="showCode">
        <a href="#showCode">Afficher le code</a><a href="#top">Masquer le code</a>
        <code><?php echo htmlentities(file_get_contents(__FILE__)); ?></code>
    </pre>
</body>
</html>