#!/usr/bin/perl

use 5.034;

my $DEBUG = 0;

my $planta = <<EOT;
OIOOIOOIOOIO
OIOOIOOIOOIO
OIOOIOOIOOIO
OIOOIOOIOOIO
OIOOIOOIOOIO
OIII&--&IIIO
EOT
;
$planta =~ s/\s//g;
$planta = $planta x 3;   # son tres plantas
my $P = 3;
my $F = 6;
my $C = 12;
my @caisles = (2, 5, 8, 11); 

my @array;
my @index;
my @w = split "", $planta;
my $pos1="0-6-5"; # nivel 0 esperando fila 5 columna 4
my $pos2="0-6-7"; # segundo ascensor

my $kontador;
my @rindex;
for my $p (1 .. $P){
    for my $fila (1..$F){
	for my $c (1 .. $C){
	    my $k = shift @w;
	    $array[$p][$fila][$c]= $k;
	    say "$p $fila $c -> $k" if $DEBUG;
	    $index[++$kontador] = "$p-$fila-$c";
	    say "index $kontador = $p-$fila-$c" if $DEBUG;
	}
    }	
}
my %rindex = reverse @index;

my $alturas = $P;
my $velocidad = 0.3; # metros/segundo
my $tiempometer = 10; # segundos
my $ascensorcongiro = 15; # segundos
my $ascensorcongiro_v2 = 15;  # la mitad que con uno
my $retirada = 12; # segundos
my $largoplaza = 5; # metros 
my $altoplaza = 2; # metros
my $anchoplaza = 2.5; # metros

say "Dimensiones:";
say "Ancho = ", $anchoplaza*$C, " metros";
say "Largo = ", $largoplaza*$F, " metros";
say "Alto = ", $altoplaza*$P, " metros";  

my ($capacidad, $pasillo, $elevador, $intercambio);
my @posx = ($pos1, $pos2);
my $cola;

for my $i (split (//, $planta)) {
    if ($i eq "O") {
	$capacidad++;
#	$posx[$capacidad-1] = $index[$kontador--] if (($index[$kontador] ne $index[$kontador+1]));
    }elsif ($i eq "&"){
	$elevador++;
    }elsif ($i eq "I"){
	$pasillo++;
    }elsif ($i eq "-"){
	$intercambio++;
    }
}

say "";
say "capacidad (5x8+2)x3 = $capacidad";
say "pasillo ((4x6)+6-2)x3 = $pasillo"; 
say "elevadores 2x(1x3+1) (planta 0) = $elevador+1";
say "servicio o buffer 2x3 = $intercambio";
say "";
###############    
    
my ($llegada, $peticion, $insercion);

my $t =0;
my ($id, $lleno);
my ($x,$y,$z);

my @lista;
push @lista, rand()*48-24 for 1..100_000;
@lista = sort { $a <=> $b } @lista;
my $c;
while (@lista){
    $llegada = shift @lista;

=from Style:
    This is the Harry the Dirty of code: reuse a variable only to have 
      fun and prank inexpert minds. I only expect to fool myself too.
      
=cut    
    
    my $cual = policylifts();
    if ($cual == 0){
	$cual = $pos1;
    }else{
	$cual = $pos2;
    }
    if ($llegada <=0){                                   # RETIRADA
	$x = int rand()*($P+1);
	$z = int rand()*(1+$C);
	$peticion = "$x-$y-$z";
	$insercion = 0;
	$t += mov ( $cual , $rindex{$peticion} );
	$t += $retirada;
	$t += mov ( $rindex{$peticion}, $cual );
	$t += $ascensorcongiro_v2;
	$array[$x][$y][$z] = "O" if ($array[$x][$y][$z] ne "&" && $array[$x][$y][$z] ne "-");   # porsiaca
    }else{                                               # INSERCION
	$id = 1+int (123456789 * rand()); 
	$insercion = algoritmo($id);
	if ($insercion eq "FULL"){
	    $lleno++;
	    next;
	}
	$t += $ascensorcongiro_v2;
	$peticion = $insercion;	
	$t += mov ( $cual , $peticion );
	$t += $tiempometer;
	$t += mov ( $insercion , $cual );                # para confirmar, podría ser opcional
    }
    print "\rTiempo medio = " , int($t / ++$c), " segundos";
}
say "";
say "Fracasos por llenos ", $lleno/100_000;
say "";
exit 2;


sub mov {
    my ($x, $y) = @_;
    $x =~ /(\d+)\-(\d+)-(\d+)/;
    my $piso = $1;
    my $fila = $2;
    my $col = $3;

    
    $y =~ /(\d+)\-(\d+)\-(\d+)/;
    my $pison = $1;
    my $filan = $2;
    my $coln = $3;

    my ($dist, $dp, $df, $dc);
    
    $dp = abs ($pison - $piso);
    $df = abs ($filan - $fila);
    
    if (abs($coln - $col) <= 1){
	$dc = 0;
    }elsif (abs($coln - $col) > 1){
	$df *= 2;
	$dc = abs ($coln -$col);
    }
#    $dist = $dp + $df + $dc;
    my $tt = 0;
    $tt = $dp * $altoplaza / $velocidad + $df * $anchoplaza / $velocidad + $dc * $largoplaza / $velocidad;
#    $pos = $y;
    return $tt;
}

sub algoritmo {     # algoritmo de inserción a lo más cercano
    my $id = shift;
#    my $t = mov ( $pos, "0-6-5" );
    my ($x, $y, $z, $r, $c);
    do {
	$c++;
	$x = int rand()*($P+1);
	$y = int rand()*($F+1);
	$z = int rand()*($C+1);
#	$r = mov ( "0-6-5", "$x-$y-$z" );	
    }until ($array[$x][$y][$z] eq "O" || $c>=120);
    if ($c >= 120){
	for $y (1..$F){
	    for $z (1..$C){
		for $x (1..$P){
		    goto ya if ($array[$x][$y][$z] eq "O");
		}
	    }
	}
	if ($y == $F) { 
#	    $pos = $posx[ int(1+2*rand()) % 2];
	    return "FULL"; 
	}
    }
ya:    
      $array[$x][$y][$z] = $id;
#   $t += $r;
    return "$x-$y-$z";
}

sub policylifts {
    state $which;
    $which++;
    if ($which > 1){ $which = 1; }else{ $which = 0; }
    return $which;
}


__END__
  
It suggest a second lift is needed
  
