Jardin du programmeur

12

Jardin du programmeur

En tant que développeur de logiciels professionnel, vous ne pouvez pas risquer de vous exposer à la dure lumière non artificielle du soleil, mais vous avez également un faible pour les fleurs et souhaitez garder votre jardin en bon état toute l'année.

À cette fin, un jardinier est embauché chaque mois pour ranger le parterre de fleurs au pied de votre maison. Cependant, vous devez vous assurer que le jardinier fait correctement son travail et établir un paiement approprié pour le travailleur acharné. Naturellement, une solution logicielle est la meilleure.

Contribution

Votre programme sera alimenté en entrée décrivant le parterre de fleurs tel qu'il apparaît actuellement et les détails des éléments qui doivent être supprimés. Le programme doit produire le jardin sans encombrement et imprimer une ventilation du salaire des jardiniers. L'entrée peut provenir de STDIN ou d'un argument de ligne de commande unique.

La première ligne d'entrée est au format

width height unwanted_item_type_count

widthest la largeur du parterre de fleurs, heightest la hauteur du parterre de fleurs (les deux en caractères ASCII), et unwanted_item_type_countvous indique combien de lignes suivront contenant une description d'un type d'élément à retirer du jardin.

Chaque ligne pour chaque type d'élément indésirable est au format

width height string_representation name fee_per_item

widthest la largeur de l'élément, heightest la hauteur de l'élément (les deux en caractères ASCII), string_representationest la représentation sous forme de chaîne de l'élément sans les sauts de ligne, nameest un identifiant pour le type d'élément (les espaces seront remplacés par des traits de soulignement), et fee_per_itemest combien le jardinier doit être payé pour l'enlèvement de chaque type d'article.

Par exemple

3 2 .R.\|/ rouge_flower 3

Représente un type d'élément de nom rouge_flower, qui coûte 3 à supprimer, et ressemble à ceci:

.R.
\|/

Les éléments ne contiendront pas d'espaces, et aucun élément ne peut avoir une bordure entièrement composée de points, et la représentation sous forme de chaîne aura également la taille exacte décrite. Ainsi, tous les éléments suivants sont des entrées non valides:

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

Notez que 0 est cependant un tarif valide (les tarifs seront toujours des entiers supérieurs à -1).

Notez également que le parterre de fleurs est principalement composé de points ( .) plutôt que d'espaces, et vous pouvez utiliser en toute sécurité des espaces blancs comme délimitation pour toutes les entrées. Le parterre est toujours délimité par des points lui-même.

Après la liste des types d'éléments indésirables, vient la représentation ASCII du parterre de largeur et de hauteur données.

Production

La sortie doit être vers STDOUT, ou une alternative appropriée si votre langue ne la prend pas en charge.

La sortie commence par une impression du parterre de fleurs, mais avec tous les éléments indésirables supprimés (remplacés par des points), vous pouvez donc voir comment cela devrait apparaître et vérifier que le jardinier a fait son travail. Chaque élément du parterre de fleurs sera entouré d'un rectangle de points et sera un élément contigu (c'est-à-dire qu'il n'y aura pas de points de séparation à l' intérieur de l'élément). Par exemple

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

affiche 2 éléments distincts

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

montre 1 article

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

n'est pas valide, car alors que la pierre (#) peut être appariée, le serpent (vous ne pouviez pas dire que c'était un serpent?) ne peut pas car la pierre interfère avec l'entourage requis des points.

...
\@.
...

Ceci est également invalide, car l'escargot est sur le bord du parterre de fleurs, et le bord doit toujours être délimité par des points dans une entrée valide.

Après cela, il devrait y avoir une liste de chaque type d'élément indésirable, indiquant le nombre, le coût par élément et les coûts pour tous les éléments (nombre * coût par élément), au format:

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

Après cela, il devrait y avoir une seule ligne indiquant le coût total (la somme des coûts des articles indésirables):

total cost <total_cost>

Exemple

Pour cette entrée donnée

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

Le programme devrait produire cette sortie

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

La sortie doit être terminée par un saut de ligne.

C'est le code-golf, que le code le plus court l'emporte.

Cas de test supplémentaire

Edit: il contenait auparavant Unicode, qui n'est pas autorisé dans le parterre de fleurs, beaucoup trop moderne. Cela a été corrigé, désolé.

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
.........................
........@................
....$..\|/...........@...
............|.......\|/..
...#.......\@/...........
.........................
.........................
......@.......@......@...
.....\|/....\\|//...\|/..
.............\|/.........
.#....................#..
.........$.......|.......
...\/.......\/..\@/..\/..
..\\//.....\\//.....\\//.
.........................

Production attendue:

.........................
........@................
.......\|/...........@...
....................\|/..
.........................
.........................
.........................
......@..............@...
.....\|/............\|/..
.........................
.........................
.........................
...\/.......\/.......\/..
..\\//.....\\//.....\\//.
.........................
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
la source
Pouvons-nous supposer que la boîte englobante de chaque élément indésirable est exacte? Autrement dit, aucune bordure dans la description de l'article n'est entièrement composée de points?
John Dvorak,
@JanDvorak oui, cela semble une contrainte assez raisonnable. J'ajouterai cela à la question et j'emprunterai votre libellé en supposant que cela ne vous gênera pas.
VisualMelon
L'escargot rampera-t-il également dans des directions différentes? \@et @/par exemple .. Ou sont-ils tenus de pointer éternellement vers l'ouest?
Han Soalone
@SickDimension les éléments indésirables ne doivent être mis en correspondance avec précision que lorsqu'ils sont décrits, les rotations et les retournements distincts ne doivent pas être mis en correspondance. Cela n'exclut pas la possibilité qu'un escargot rampe dans l'autre sens, mais personne n'est payé pour les supprimer dans l'exemple.
VisualMelon

Réponses:

3

Perl - 636

Il y a certainement encore du golf à faire. Et probablement de meilleures façons de le faire aussi.

<>;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 caractères + 1 pour -Cdrapeau pour gérer les euros.

Si l'entrée est stockée dans, input.txtvous pouvez l'exécuter avec:

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"}'

Voici la version analysée. J'ai parcouru et ajouté quelques commentaires pour aider à expliquer les choses. Je vais peut-être rendre les noms des variables plus lisibles un jour. Il peut y avoir des cas marginaux avec lesquels cela ne fonctionne pas, mais cela fonctionne avec les exemples au moins.

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
}

N'hésitez pas à suggérer des améliorations!

hmatt1
la source
Beau travail, et je crains d'avoir péché, j'ai spécifié que le parterre serait ASCII, puis je me suis excité et j'ai mis Unicode dans l'exemple - je vais changer l'exemple pour qu'il soit juste ASCII, désolé pour le travail pour vous.
VisualMelon
1
@VisualMelon, il était intéressant d'apprendre à faire fonctionner un monoligne avec unicode. Je ne connaissais pas le -Cdrapeau avant ça. Je vais le laisser là pour être compatible de toute façon car il n'y a qu'une différence de 1 caractère.
hmatt1
0

Python 3, 459 octets

    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)

Suppose que l'entrée sera donnée sous forme de liste de chaînes.

Triggernométrie
la source
J'aime l' ~Hastuce; Je ne peux pas tester cela maintenant, mais j'essaierai de le faire plus tard dans la journée.
VisualMelon
Je n'arrive pas à obtenir que cela fonctionne correctement ( ValueError: not enough values to unpack (expected 3, got 1), python 3.6.6); pouvez-vous fournir un lien TIO ou une description sur la façon de l'exécuter. Je pense que cela pourrait contourner les règles en supposant que l'entrée est sur une seule ligne, mais je n'étais pas tout à fait clair à ce sujet dans la question, donc je ne me plaindrai pas.
VisualMelon
@VisualMelon - bah, j'ai probablement copié / collé quelque chose de mal. Je ne peux pas me rendre à TIO au travail, je vais donc vérifier mon travail et publier un lien plus tard dans la journée.
Triggernométrie