#!/usr/bin/perl

use 5.040.3;

$|=1;

# init space to search in
say "Init...";
my $space = 2_888;         # Sucede que el tamaño es relevante. 
say "Space to search in = ", ($space+1)**3, " variable elements";
my $MAGIC = 9999973;       # este es un factor de rareza: no necesita ser un número primo
say "Los puntos no nulos son determinados por la semilla $MAGIC (factor de rareza)";
my $phases = 12;
my $minutes = 20;
say "Se utilizan $phases fases de $minutes minutos";

my @s;
my $total = 0;
my $npremios = 0;
for my $i (0 .. $space){
    for my $j (0 .. $space){
	for my $k (0 .. $space){
	    if ( ($i * $j * $k + $i + $j + $k) % $MAGIC == 0 ){
		$s[$i][$j][$k] = 1000 * rand();                # beneficio        
		$total += $s[$i][$j][$k];
		$npremios++;
		print "\r$npremios";
	    }
	}
    }
}

# call a sub search() until lunch
say "\nSearch...\n";
my $TIMEOUT = $minutes * 60;  #   MINUTES * seconds (v3 por ronda)
my ($collect, $c, $tmp) = (0, 0, 0);
my %h;

my $rand = 73;        # an attempt to reduce rand() calls

my ($x,$y,$z);
for my $j (1 .. $phases){                            # rondas o fases
    my $newtime = time() + $TIMEOUT;
    init ($j);
    while ( time() < $newtime ){               # 10 minutos
	print "\r$c";
	$tmp = search(++$c);    
	if (defined $tmp){
	    $collect += $tmp if (++$h{$tmp} == 1);
	}
    }
    # Resultados de la búsqueda
    say "\n[terminado después de $minutes minutos aprox.]";
    say "Fase   $j\nEsta vez se ha recogido $collect de $total";
    say "El porcentaje de éxito es de ", 100 * $collect / $total, " %";
    say "(el tanto por uno de espacio pisado es ", $c/(($space+1)**3), ")\n";
}

my $string;
my $sum2 = 0;
for my $i (sort keys %h){
    $string .= "$i " if $h{$i} > 1;
    $sum2 += $i * ($h{$i} -1);   # suma de las pasadas múltiples, en exceso de 1  
}
say "Por espacio pisado se entiende las iteraciones con respecto al cubo 3D";

if (defined $string){

    say "Las ocurrencias múltiples no computadas son:\n$string\n";

    say "Y, si pasamos a computarlas, $sum2, la suma queda en ", $collect+$sum2, " un porcentaje";
    say "de ", 100 * ($collect + $sum2) / $total, " % de éxito de recolección\n"; 
}

if ($collect + $sum2 > $total){
    say "\nHa pasado varias veces por el mismo sitio\n";
    say "El porcentaje de eficacia es 100% (con eso se puede estar contento)\n";
    say "(Pero hay un cierto derroche en la búsqueda...)\n";    
}

say "Se ha buscado $npremios en el espacio ", ($space+1)**3, "\n";
say "Con un esfuerzo total de ", $minutes*$phases, " minutos computeros";

exit 2;


sub search {            # realmente esto es lo que importa. Aunque hay que ver los reinicios arriba, también
    if ($_[0] & 10){    # múltiplo de 2
	$x = ($x == $space) ? 0 : ++$x;           # trata de moverse rápido
    }elsif ($_[0] & 11){ # múltiplo de 3
	$z = $rand = int (0.5 + rand($space));           # trata de hacer cosa complicada 1/3 de veces, suficiente??? 
    }elsif ($_[0] & 101){  # múltiplo de 5
	$y = ($y == $space) ? 0 : ++$y;
	$x = $rand;                               # trata de moverse lejos
    }else{   
	($z, $y) = ($x, $rand);
    }
    return $s[$x][$y][$z];
}

sub init ($j) {
    # Aquí se trata de iniciar en $x, $y, $z 
    # la forma más repartida de búsqueda. Si no óptima,
    # puede ser adecuada la configuración de dos 
    # circunferencias perpendiculares orinteadas
    # hacia la diagonal (0,0,0) -> ($space, $space, $space)
    # El radio debe ser menor lo suficiente para que no se 
    # produzcan extroversiones al cubo de búsqueda.
    # Como el centro de esas circunferencias es el centro
    # del cubo, esas dos circunferencias deben hacerse...
    # Corrección: no son dos, son al menos tres y no son 
    # perpendiculares. Otro problema es que sólo necesito 
    # 12 puntos. 4*3 = 12. Con lo que igual convenía no
    # circunferencias sino elipsoides.

    # Es + sencillo que todo eso. Tengo dos puntos 'buenos'
    # x1 = 1/4 space y x2 = 3/4 space
    # Sólo tengo que conseguir 12 estados 'razonables'
    # x1, y1, z1
    # x2, y1, z1
    # x1, y2, z1
    # x1, y2, z2
    # x2, y1, z2
    # x2, y2, z1
    # x2, y2, z2
    # x1, y1, z2
    # ...
    # El caso es que las combinaciones son de 3 for anidados, 9
    # Otras pueden ser: origen, meddio, space**3
    # Total 12 estados
    my ($a, $b);
    if ($j <= 8){	
	$a = int( ($space+1) / 4 );
	$b = int( 3 * ($space+1) / 4 );
    }
    if ($j == 1){
	($x, $y, $z) = ($a, $a, $a);
    }elsif ($j == 2){
	($x, $y, $z) = ($a, $b, $a);
    }elsif ($j == 3){
	($x, $y, $z) = ($a, $a, $b);
    }elsif ($j == 4){
	($x, $y, $z) = ($a, $b, $b);
    }elsif ($j == 5){
	($x, $y, $z) = ($b, $a, $a);
    }elsif ($j == 6){
	($x, $y, $z) = ($b, $a, $b);
    }elsif ($j == 7){
	($x, $y, $z) = ($b, $b, $a);
    }elsif ($j == 8){
	($x, $y, $z) = ($b, $b, $b);
    }elsif ($j == 9){
	($x, $y, $z) = (0, 0, 0);
    }elsif ($j == 10){
	($x, $y, $z) = ( int($space/3), int($space/3), int($space/3) );
    }elsif ($j == 11){
	($x, $y, $z) = ( int(2*$space/3), int(2*$space/3), int(2*$space/3) );
    }else{
	($x, $y, $z) = ($space, $space, $space);
    } 
}








__END__
  
Las estructuras de más de tres dimensiones para resolver algo son raras.
  (pero con los arrays nominales por conveniencia y a costa de la memoria
      se puede hacer lo que se quiera, etc.)
El caso es que siempre interesará que los algoritmos hagan búsquedas locales
  y generales a la vez, para explorar mejor el espacio
  (que hay quien dice que se puede desenrollar en menos dimensiones, lo cual
      es muy interesante porque se utiliza un modelo más autolimitado,
      ya que si no, no sería un modelo, etc.)
Tonces, este ensayo. v.5 lun 08 sep 2025 20:17:54 CEST
En esta versión le añado un algo para saber si pasa dos veces o más por el
  mismo sitio, porque sobre la versión anterior una mejoria general en la 
  búsqueda
  
