Сад програміста


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

Представляє тип імені елемента 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

Вихід повинен бути припинений переривкою рядків.

Це код-гольф, можливо, найкоротший код виграє.

Додатковий тестовий випадок

Редагувати: тут містився Unicode, який не дозволений на клумбі, занадто сучасний. Це було виправлено, вибачте за це.

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

Чи можемо ми вважати, що обмежувальне поле кожного небажаного предмета є точним? Тобто, жодна межа в описі елемента не є повністю крапкою?
Джон Дворак

@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
}

Не соромтеся пропонувати поліпшення!


Хороша робота, і я боюся, що я згрішив, я вказав, що клумба буде ASCII, а потім все схвильовано і поставив Unicode в приклад - я поміняю приклад, щоб це був просто ASCII, вибачте за те, що я працював на ви.
VisualMelon

1
@VisualMelon було цікаво дізнатися, як змусити однолінійку працювати з unicode. Я раніше не знав про -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)

Припустимо, що введення буде подано у вигляді списку рядків.


Мені подобається ~Hтрюк; Я зараз не можу перевірити це, але спробую зробити це пізніше сьогодні.
VisualMelon

Я не можу зробити так, щоб це запустилося правильно ( ValueError: not enough values to unpack (expected 3, got 1), python 3.6.6); чи можете ви надати посилання TIO або опис того, як його запустити. Я думаю, що це може бути згинання правил, припускаючи, що введення все на одному рядку, але я не зовсім зрозумів про це в питанні, тому я не буду скаржитися.
VisualMelon

@VisualMelon - так, я, мабуть, щось неправильно копіював / макаронив. Я не можу дістатися до TIO на роботі, тому я перевірю свою роботу та опублікую посилання пізніше сьогодні.
Тригернометрія
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.