Сад программистов

12

Сад программистов

Будучи профессиональным разработчиком программного обеспечения, вы не можете рисковать, подвергаясь резкому неискусственному солнечному свету, но у вас также есть мягкое место для цветов, и вы хотите поддерживать свой сад в хорошем состоянии круглый год.

Для этого каждый месяц нанимают садовника, чтобы привести в порядок клумбу у подножия вашего дома. Однако вы должны убедиться, что садовник выполняет свою работу должным образом, и найти подходящую оплату для трудолюбивого сотрудника. Естественно, программное решение лучше.

вход

Ваша программа будет снабжена вводом, описывающим клумбу, как она выглядит текущей, и сведениями об элементах, которые необходимо удалить. Программа должна выводить сад, лишенный беспорядка, и распечатывать разбивку заработной платы садоводов. Ввод может быть либо из STDIN, либо в виде одного аргумента командной строки.

Первая строка ввода имеет формат

width height unwanted_item_type_count

где width- ширина клумбы, heightвысота клумбы (обе в символах ASCII), и unwanted_item_type_countговорит, сколько строк будет следовать, содержащих описание типа предмета, который будет удален из сада.

Каждая строка для каждого нежелательного типа элемента имеет формат

width height string_representation name fee_per_item

где width- ширина элемента, heightвысота элемента (как в символах ASCII), так string_representationи строковое представление элемента без разрывов строк, nameидентификатор типа элемента (пробелы будут заменены подчеркиванием) и fee_per_itemэто то, сколько садовник должен заплатить за удаление каждого типа предмета.

Например

3 2 .R.\|/ rouge_flower 3

Представляет тип элемента name rouge_flower, который стоит 3 для удаления, и выглядит следующим образом:

.R.
\|/

Элементы не будут содержать пробелов, и ни один элемент не может иметь границы, состоящей целиком из точек, и строковое представление также будет иметь точный описанный размер. Таким образом, все следующие данные являются недействительными:

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

Обратите внимание, что 0, однако, является действительным взносом (сборы всегда будут целыми числами больше -1).

Также обратите внимание, что клумба состоит преимущественно из точек ( .), а не пробелов, и вы можете безопасно использовать пробелы в качестве разделителя для всех входных данных. Клумба всегда ограничена точками.

После того, как нежелательные типы элементов перечислены, затем в ASCII представлении клумбы данной ширины и высоты.

Выход

Вывод должен быть STDOUT или подходящей альтернативой, если ваш язык не поддерживает его.

Вывод начинается с распечатки клумбы, но со всеми ненужными элементами, удаленными (замененными точками), чтобы вы могли увидеть, как он должен выглядеть, и проверить, что садовник выполнил свою работу. Каждый предмет на клумбе будет окружен прямоугольником из точек и будет одним смежным предметом (т.е. внутри предмета не будет разделительных точек ). Например

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

показывает 2 отдельных пункта

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

показывает 1 пункт

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

недопустимо, так как в то время как камень (#) может быть сопоставлен, змея (вы не могли бы сказать, что это была змея?) не может, потому что камень мешает требуемому окружению точек.

...
\@.
...

Это также недопустимо, так как улитка находится на краю клумбы, а край всегда должен быть ограничен точками в допустимом вводе.

После этого должен быть список каждого типа нежелательных предметов с указанием количества, стоимости за единицу и стоимости для всех предметов (количество * стоимость за единицу) в формате:

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

После этого должна быть одна строка, в которой указана общая стоимость (сумма затрат на нежелательные предметы):

total cost <total_cost>

пример

Для этого дан вход

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

Программа должна выдавать этот вывод

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

Вывод должен быть завершен переводом строки.

Это код-гольф, пусть победит самый короткий код.

Дополнительный контрольный пример

Редактировать: раньше он содержал Юникод, который не разрешен на клумбе, слишком современный. Это было исправлено, извините за это.

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

Ожидаемый результат:

.........................
........@................
.......\|/...........@...
....................\|/..
.........................
.........................
.........................
......@..............@...
.....\|/............\|/..
.........................
.........................
.........................
...\/.......\/.......\/..
..\\//.....\\//.....\\//.
.........................
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
источник
Можем ли мы считать, что ограничительная рамка каждого нежелательного элемента является точной? То есть, нет границ в описании элемента полностью точек?
Джон Дворак
@JanDvorak да, это кажется достаточно разумным ограничением. Я добавлю это к вопросу, и я позаимствую вашу формулировку, исходя из предположения, что вы не будете против, если я сделаю это.
VisualMelon
Будет ли улитка ползать в другом направлении? \@и @/например .. Или они должны вечно указывать на запад?
Хан Соалоне
@SickDimension нежелательные элементы должны соответствовать только точно так, как они описаны, отдельные повороты и сальто не должны совпадать. Это не исключает возможности того, что улитка будет ползти в другом направлении, но никто не платит за их удаление в этом примере.
VisualMelon

Ответы:

3

Perl - 636

Определенно есть еще кое-что, что можно сделать. И, вероятно, лучшие способы сделать это тоже.

<>;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 символов + 1 для -Cфлага для обработки евро.

Если у вас есть входные данные, input.txtвы можете запустить их с помощью:

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

Вот ушедшая версия. Я прошел и добавил несколько комментариев, чтобы помочь объяснить вещи. Может быть, я когда-нибудь сделаю имена переменных более читабельными. Могут быть некоторые крайние случаи, с которыми это не работает, но это работает по крайней мере с примерами.

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
}

Не стесняйтесь предлагать улучшения!

hmatt1
источник
Хорошая работа, и я боюсь, что согрешил, я определил, что клумба будет ASCII, а затем все взволнован и поместил Unicode в пример - я изменю пример так, что это просто ASCII, извините за то, что я работал вы.
VisualMelon
1
@VisualMelon было интересно узнать, как заставить однострочную работу работать с юникодом. Я не знал о -Cфлаге до этого. Я оставлю это там, чтобы быть совместимым в любом случае, так как разница только в 1 символ.
hmatt1
0

Python 3, 459 байт

    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)

Предполагается, что входные данные будут представлены в виде списка строк.

Triggernometry
источник
Мне нравится ~Hтрюк; Я не могу проверить это сейчас, но постараюсь сделать это позже сегодня.
VisualMelon
Я не могу заставить его работать правильно ( ValueError: not enough values to unpack (expected 3, got 1)Python 3.6.6); Можете ли вы предоставить ссылку TIO или описание того, как его запустить. Я думаю, что это может нарушать правила, если предположить, что все вводится в одну строку, но я не совсем понял это в вопросе, поэтому не буду жаловаться.
VisualMelon
@VisualMelon - ба, я, вероятно, скопировал / вставил что-то неправильно. Я не могу попасть в TIO на работе, поэтому проверю свою работу и выложу ссылку позже сегодня.
Triggernometry