Jardín de programadores

12

Jardín de programadores

Al ser un desarrollador de software profesional, no puede arriesgarse a exponerse a la dura luz no artificial del sol, pero también tiene un punto débil para las flores y desea mantener su jardín en buen estado durante todo el año.

Con este fin, se contrata a un jardinero cada mes para ordenar el cantero al pie de su casa. Sin embargo, debe asegurarse de que el jardinero esté haciendo su trabajo correctamente y hacer un pago adecuado para el trabajador. Naturalmente, una solución de software es la mejor.

Entrada

Su programa recibirá información que describa el macizo de flores tal como parece actual y los detalles de los elementos que deben eliminarse. El programa debe dar salida al jardín sin el desorden e imprimir un desglose del pago de los jardineros. La entrada puede ser de STDIN o como un argumento de línea de comando único.

La primera línea de entrada es del formato.

width height unwanted_item_type_count

donde widthes el ancho del macizo de flores, heightes la altura del macizo de flores (ambos en caracteres ASCII) y unwanted_item_type_countle indica cuántas líneas seguirán con una descripción de un tipo de elemento que se eliminará del jardín.

Cada línea para cada tipo de elemento no deseado tiene el formato

width height string_representation name fee_per_item

donde widthes el ancho del elemento, heightes la altura del elemento (ambos en caracteres ASCII), string_representationes la representación de cadena del elemento sin saltos de línea, namees un identificador para el tipo de elemento (los espacios se reemplazarán con guiones bajos) y fee_per_itemes cuánto se debe pagar al jardinero por la eliminación de cada tipo de artículo.

Por ejemplo

3 2 .R.\|/ rouge_flower 3

Representa un tipo de nombre de elemento rouge_flower, que cuesta 3 eliminar, y se ve así:

.R.
\|/

Los elementos no contendrán espacios, y ningún elemento puede tener un borde que consista completamente en puntos, y la representación de la cadena también tendrá el tamaño exacto descrito. Por lo tanto, todos los siguientes son entradas no válidas:

3 1 ( ) space 0
1 1 . dot 0
2 1 .! bang 0
3 2 .@.\|/. plant 0

Sin embargo, tenga en cuenta que 0 es una tarifa válida (las tarifas siempre serán enteros mayores que -1).

Tenga en cuenta también que el macizo de flores está compuesto principalmente por puntos ( .) en lugar de espacios, y puede usar espacios en blanco de forma segura como delimitación para todas las entradas. El macizo de flores siempre está limitado por puntos en sí.

Después de que se enumeran los tipos de elementos no deseados, viene la representación ASCII del macizo de flores de ancho y alto dados.

Salida

La salida debe ser STDOUT, o una alternativa adecuada si su idioma no lo admite.

La salida comienza con una impresión del macizo de flores, pero con todos los elementos no deseados eliminados (reemplazados por puntos), para que pueda ver cómo debería aparecer y verificar que el jardinero haya hecho su trabajo. Cada elemento en el macizo de flores estará rodeado por un rectángulo de puntos y será un elemento contiguo (es decir, no habrá puntos de separación dentro del elemento). Por ejemplo

.....
.#.#.
.....

muestra 2 artículos separados

.....
.\@/.
.....

muestra 1 artículo

......
.#....
....|.
....|.
.o--/.
......

es inválido, ya que si bien la piedra (#) puede coincidir, la serpiente (¿no se podía decir que era una serpiente?) no puede porque la piedra interfiere con el entorno requerido de puntos.

...
\@.
...

Esto tampoco es válido, ya que el caracol está en el borde del macizo de flores, y el borde siempre debe estar delimitado por puntos en una entrada válida.

Después de esto, debe haber una lista de cada tipo de artículo no deseado, dando el recuento, el costo por artículo y los costos de todos los artículos (recuento * costo por artículo), en el formato:

<count> <name> at <cost_per_item> costs <cost>

Después de esto, debería haber una sola línea que arroje el costo total (la suma de los costos de los artículos no deseados):

total cost <total_cost>

Ejemplo

Para esta entrada dada

25 18 3
4 2 .\/.\\// weeds 5
2 1 \@ snails 2
1 1 # stones 1
.........................
.\@/.................\@..
............\/...........
......O....\\//..^|^.....
.#...\|/.........^|^.....
..................|......
.................\|/.....
..\@.....\/...........#..
........\\//....#........
....*....................
...\|/......\/......\@/..
...........\\//..........
..................*......
.......\@/.......\|/.....
...O.....................
..\|/.......*............
.......#...\|/....\@.....
.........................

El programa debe producir esta salida.

.........................
.\@/.....................
.........................
......O..........^|^.....
.....\|/.........^|^.....
..................|......
.................\|/.....
.........................
.........................
....*....................
...\|/..............\@/..
.........................
..................*......
.......\@/.......\|/.....
...O.....................
..\|/.......*............
...........\|/...........
.........................
3 weeds at 5 costs 15
3 snails at 2 costs 6
4 stones at 1 costs 4
total cost 25

La salida debe ser terminada por un salto de línea.

Este es el código de golf, que gane el código más corto.

Caso de prueba adicional

Editar: esto solía contener Unicode, que no está permitido en el macizo de flores, demasiado moderno. Esto ha sido rectificado, perdón por eso.

25 15 5
5 3 ..@..\\|//.\|/. overgrown_plants 3
5 3 @-o....|...\|/. semi-articulated_plant 4
3 2 .|.\@/ mutant_plants 5
1 1 $ dollars 0
1 1 # stones 1
.........................
........@................
....$..\|/...........@...
............|.......\|/..
...#.......\@/...........
.........................
.........................
......@.......@......@...
.....\|/....\\|//...\|/..
.............\|/.........
.#....................#..
.........$.......|.......
...\/.......\/..\@/..\/..
..\\//.....\\//.....\\//.
.........................

Rendimiento esperado:

.........................
........@................
.......\|/...........@...
....................\|/..
.........................
.........................
.........................
......@..............@...
.....\|/............\|/..
.........................
.........................
.........................
...\/.......\/.......\/..
..\\//.....\\//.....\\//.
.........................
1 overgrown_plants at 3 costs 3
0 semi-articulated_plants at 4 costs 0
2 mutant_plants at 5 costs 10
2 dollars at 0 costs 0
3 stones at 1 costs 3
total cost 16
VisualMelon
fuente
¿Podemos suponer que el cuadro delimitador de cada elemento no deseado es exacto? Es decir, ¿ningún borde en la descripción del elemento tiene puntos completos?
John Dvorak
@ JanDvorak sí, eso parece una restricción bastante razonable. Agregaré eso a la pregunta, y tomaré prestada su redacción suponiendo que no le importará que lo haga.
VisualMelon
¿Se arrastrará también el caracol en diferentes direcciones? \@y @/por ejemplo ... ¿O están destinados a apuntar eternamente al oeste?
Han Soalone
@SickDimension los elementos no deseados solo deben coincidir exactamente como se describen, las rotaciones y volteos distintos no deben coincidir. Esto no excluye la posibilidad de que un caracol se arrastre en la otra dirección, pero a nadie se le paga para eliminarlos en el ejemplo.
VisualMelon

Respuestas:

3

Perl - 636

Definitivamente hay algo más de golf que se puede hacer. Y probablemente mejores formas de hacerlo también.

<>;while(<>){if(/ /){chomp;push@v,$_}else{$t.=$_}}for(@v){r(split/ /)}say$t.$y."total cost $u";sub r{my($e,$w,$c,$h,$z)=@_;($i,$f,$q,$d)=(1,0,0,"."x$e);@m=($c=~/($d)/g);@l=split/\n/,$t;while($i>0){($g,$j)=(1,0);for(0..$#l){if($j==0&&$l[$_]=~/^(.*?)\.\Q$m[$j]\E\./){$j++;$l="."x length$1}elsif($j<@m&&$l[$_]=~/^$l\.\Q$m[$j]\E\./){$j++}elsif($j>0){$l[$_-1]=~s!.\Q$m[$j-1]\E.!" ".$m[$j-1]=~s/\./ /gr." "!e;($j,$g)=(0,0)}if($j==@m){$k=$j;for($f=$_;$f>$_-$j;$f--){$k--;$o="."x length$m[$k];$l[$f]=~s/^($l)\.\Q$m[$k]\E\./$1.$o./}($g,$j)=(0,0);$q++}}if($g){$i--}}$t=join("\n",@l)."\n";$t=~s/ /./g;$p=$z*$q;$u+=$p;$y.="$q $h at $z costs $p\n"}

635 caracteres + 1 por -Cbandera para manejar los euros.

Si tiene la entrada almacenada input.txt, puede ejecutarla con:

cat input.txt | perl -C -E'<>;while(<>){if(/ /){chomp;push@v,$_}else{$t.=$_}}for(@v){r(split/ /)}say$t.$y."total cost $u";sub r{my($e,$w,$c,$h,$z)=@_;($i,$f,$q,$d)=(1,0,0,"."x$e);@m=($c=~/($d)/g);@l=split/\n/,$t;while($i>0){($g,$j)=(1,0);for(0..$#l){if($j==0&&$l[$_]=~/^(.*?)\.\Q$m[$j]\E\./){$j++;$l="."x length$1}elsif($j<@m&&$l[$_]=~/^$l\.\Q$m[$j]\E\./){$j++}elsif($j>0){$l[$_-1]=~s!\Q$m[$j-1]\E!$m[$j-1]=~s/\./ /gr!e;($j,$g)=(0,0)}if($j==@m){$k=$j;for($f=$_;$f>$_-$j;$f--){$k--;$o="."x length$m[$k];$l[$f]=~s/^($l)\.\Q$m[$k]\E\./$1.$o./}($g,$j)=(0,0);$q++}}if($g){$i--}}$t=join("\n",@l)."\n";$t=~s/ /./g;$p=$z*$q;$u+=$p;$y.="$q $h at $z costs $p\n"}'

Aquí está la versión analizada. Lo revisé y agregué algunos comentarios para ayudar a explicar las cosas. Tal vez haga que los nombres de las variables sean más legibles en algún momento. Puede haber algunos casos extremos con los que esto no funciona, pero al menos funciona con los ejemplos.

BEGIN { # These are the features we get with -C and -E flags
    $^H{'feature_unicode'} = q(1); # -C gives us unicode
    $^H{'feature_say'} = q(1); # -E gives us say to save 1 character from print
    $^H{'feature_state'} = q(1);
    $^H{'feature_switch'} = q(1);
}
<ARGV>; # throw away the first line
while (defined($_ = <ARGV>)) { # read the rest line by line
    if (/ /) { # if we found a space (the garden doesn't have spaces in it)
        chomp $_; # remove the newline
        push @v, $_; # add to our array
    }
    else { # else, we construct the garden
        $t .= $_;
    }
}
foreach $_ (@v) { # call the subroutine r by splitting our input lines into arguments
    r(split(/ /, $_, 0)); # the arguments would be like r(3,2,".R.\|/","rouge_flower",3)
}
say $t . $y . "total cost $u"; # print the cost at the end

# this subroutine removes weeds from the garden and counts them
sub r {
    BEGIN {
        $^H{'feature_unicode'} = q(1);
        $^H{'feature_say'} = q(1);
        $^H{'feature_state'} = q(1);
        $^H{'feature_switch'} = q(1);
    }
    my($e, $w, $c, $h, $z) = @_; # get our arguments
    ($i, $f, $q, $d) = (1, 0, 0, '.' x $e); # initialize some variables
    @m = $c =~ /($d)/g; # split a string like this .R.\|/ into .R. and \|/
    @l = split(?\n?, $t, 0); # split the garden into lines to process line by line
    while ($i > 0) {
        ($g, $j) = (1, 0);
        foreach $_ (0 .. $#l) { # go through the garden
            if ($j == 0 and $l[$_] =~ /^(.*?)\.\Q$m[$j]\E\./) { # this matches the top part of the weed. \Q and \E make it so the weed isn't intepreted as a regex. Capture the number of dots in front of it so we know where it is
                ++$j;
                $l = '.' x length($1); # this is how many dots we have
            }
            elsif ($j < @m and $l[$_] =~ /^$l\.\Q$m[$j]\E\./) { # capture the next line
                ++$j;
            }
            elsif ($j > 0) { # if we didn't match we have to reset
                $l[$_ - 1] =~ s[.\Q$m[$j - 1]\E.][' ' . $m[$j - 1] =~ s/\./ /rg . ' ';]e; # this line replaces the dots next to the weed and in the weed with spaces
                # to mark it since it didn't work but the top part matches
                # that way when we repeat we go to the next weed
                ($j, $g) = (0, 0);
            }
            if ($j == @m) { # the whole weed has been matched
                $k = $j;
                for ($f = $_; $f > $_ - $j; --$f) { # remove the weed backwards line by line
                    --$k;
                    $o = '.' x length($m[$k]);
                    $l[$f] =~ s/^($l)\.\Q$m[$k]\E\./$1.$o./; 
                }
                ($g, $j) = (0, 0);
                ++$q;
            }
        }
        if ($g) {
            --$i; # all the weeds of this type are gone
        }
    }
    $t = join("\n", @l) . "\n"; # join the garden lines back together
    $t =~ s/ /./g; # changes spaces to dots 
    $p = $z * $q; # calculate cost
    $u += $p; # add to sum
    $y .= "$q $h at $z costs $p\n"; #get message
}

¡No dude en sugerir mejoras!

hmatt1
fuente
Buen trabajo, y me temo que he pecado, especifiqué que el macizo de flores sería ASCII, y luego me emocioné y puse a Unicode en el ejemplo: cambiaré el ejemplo para que sea solo ASCII, lo siento por hacer el trabajo para tú.
VisualMelon
1
@VisualMelon fue interesante aprender cómo hacer que una línea funcione con Unicode. No sabía sobre la -Cbandera antes de esto. Lo dejaré allí para que sea compatible de todos modos, ya que es solo una diferencia de 1 carácter.
hmatt1
0

Python 3, 459 bytes

    from re import*
E=input()
W,H,C=map(int,E[0].split())
B,T,O='\n'.join(E[~H:]),0,''
for L in E[1:~H]:
 w,h,s,n,c=L.split();w,h,c=map(int,(w,h,c));r,t='.'*(w+2),0;a=[r]+['.%s.'%s[i:i+w]for i in range(0,w*h,w)]+[r]
 for L in['(%s)'%'\\n'.join('.{%d})%s(.*'%(i,escape(b))for b in a)for i in range(W)]:t+=len(findall(L,B));B=sub(L,r.join('\\%d'%b for b in range(1,h+4)),B,MULTILINE)
 O+='%d %s at %d costs %d\n'%(t,n,c,t*c);T+=t*c
print(B+O+'total cost',T)

Asume que la entrada se dará como una lista de cadenas.

Triggernometry
fuente
Me gusta el ~Htruco; No puedo probar esto ahora, pero intentaré hacerlo más tarde hoy.
VisualMelon
Parece que no puedo hacer que esto se ejecute correctamente ( ValueError: not enough values to unpack (expected 3, got 1), python 3.6.6); ¿Puede proporcionar un enlace TIO o alguna descripción sobre cómo ejecutarlo? Creo que podría estar doblando las reglas asumiendo que la entrada está en una sola línea, pero no estaba del todo claro en la pregunta, así que no me quejaré.
VisualMelon
@VisualMelon - bah, probablemente he copiado / pegado algo incorrectamente. No puedo llegar a TIO en el trabajo, así que revisaré mi trabajo y publicaré un enlace más tarde hoy.
Triggernometry