Чи може Пак-Ман з'їсти цю струну?


46

У аркадній версії гри Pac-Man їсть pac-крапки. Однак у цьому виклику він прагне буквено-цифрових символів та пунктуації в рядку.

Ваше завдання - створити функцію, яка подає Pac-Man рядку, оцінює, може він її їсти чи ні, і повертає рядок із розташуванням у ній Pac-Man.

Pac-Man ( <) їсть символів зліва направо, залишаючи підкреслення або пробіл для кожного персонажа, коли він йде, і його мета - дістатися з першої позиції-1 до останньої позиції + 1:

1. <Pac
2. _<ac
3. __<c
4. ___<

Однак природний ворог Пак-Мана, привид, зупинить його, якщо він зустріне одну з букв у слові "GHOST" (не з урахуванням регістру). Ваша функція повинна повертати рядок із розташуванням Pac-Man, коли він стикається з ghostперсонажем:

1. <No!
2. _<o!

Єдине, що може перемогти привид - це силова гранула. Якщо Pac-Man досягне букви у слові "PELLET" (також не чутливий до регістру) перед тим, як прийти до привида, він з'їсть привид і продовжить рух, і цей гранул буде використаний. Силові гранули можуть укладатися (тобто в ppggобох привидів їдять). Символ T існує як привид, так і гранул, тому його можна ігнорувати (трактувати як будь-який інший лист, як a).

1. <Pop
2. _<op
3. __<p
4. ___<

Для подальшого уточнення в рядку "Pac-Man програє тут" відбуваються такі операції:

P <P, +1 Pellet (1 pellet)
a <a
c <c
- <-
M <M
a <a
n <n
  <[space]
l <l, +1 Pellet (2 pellets)
o <o, -1 Pellet (1 pellet)
s <s, -1 Pellet (0 pellets)
e <e, +1 Pellet (1 pellet)
s <s, -1 Pellet (0 pellets)
  <[space]
h <h, ghost wins, returns
e
r
e

Приклади

Input: Pacman wins!
Output: ____________<

Input: Pacman loses wah-wah :(
Output: _______________<h-wah :(

Input: PELLET PELLET GHOST
Output: ___________________<

Input: Hello World!
Output: <Hello World!

Input: <_!@12<_<_<
Output: ___________<

Це код-гольф - найнижчий бал у виграші байтів.


29
Тож гранули не мають терміну придатності?
Rɪᴋᴇʀ

Чи приймаються у висновку тривалі таблиці?
Катенкьо

7
+1 за те, що "тут" - це те, де Pacman програє. Розумний тестовий випадок.
Олів'є Дулак

5
> [Я] в цьому виклику, він голодний на буквено-цифрові символи та розділові знаки в рядку. ... Якч -ман?
Каз

9
Тепер я бачу замурованого сірого пакмана з чорними губами щоразу, коли я дивлюсь на <символ ...
QBrute

Відповіді:


16

Желе, 34 33 байт

Œl“ʋʋ“ṁḍ»ċ€Ð€IF+\‘0ṭi0ð’”_×;”<;ṫ@

Спробуйте в Інтернеті!

Я думаю, я нарешті починаю розуміти Джелі. Відчуває себе трохи страшно.


5
Я б почав хвилюватися, коли ви зможете читати це вільно :)
quetzalcoatl

30

Сітківка , 55 38 байт

i`^(([elp])|[^ghos]|(?<-2>.))*
$.&$*_<

Спробуйте в Інтернеті! (Перший рядок просто дозволяє запускати кілька тестових випадків одночасно.)

Пояснення

Проблема полягає в тому, щоб знайти найдовший префікс, який не має неперевершених дужок, що закриваються. Крім того, що ми можемо використовувати або e, lабо pв місці , (і або g, h, oабо sна місці ).

Отже, це рішення є майже підручниковим прикладом балансування груп. Я не буду надто детально розповідати про те, як вони працюють, оскільки цей код по суті той самий, що і стандартний приклад, про який ви можете прочитати в моїй відповіді "SO" про балансуючі групи .

Отже, вся програма є однією заміною регулярних виразів. iАктивує прецедентне нечутливість. Тоді ми або узгоджуємо гранулу із [elp]збільшенням лічильника глибини (у формі стека захоплення групи 2), або ми узгоджуємо щось, що не є привидом, [ghos]або ми співставляємо привид з .та зменшуємо лічильник глибини, вискакуючи зі стека 2. Звичайно, в принципі це дозволяє зіставити гранулу з [^ghos]секцією або не-привид з .секцією, але завдяки жадібному зіставленню та способу зворотного відтворення регексу, ці можливості ніколи не намагаються використовувати двигун регулярного виведення.

Потім підстановка використовує дві особливості Retina: $*повторює символ праворуч стільки разів, скільки визначено лексемою зліва. Цей жетон - $.&це довжина всього матчу. Це просто означає, що ми замінюємо кожного символу в матчі на "a" _. І тоді ми також додаємо <до цих підкреслень. Частина введення, яку не їдять, просто не впливає на заміну.


Приємні зловживання захоплення груп!
Leaky Nun

11
@LeakyNun Зловживання? Саме для цього створені балансуючі групи. : D
Мартін Ендер

1
Слухай, відповідь на сітківку, яка віддалено нагадує регулярний вираз, який я використовую
кіт

10

Python 2, 114 113 108 байт

s=raw_input()
p=i=0
for c in s:
 p+=(c in'plePLE')-(c in'ghosGHOS')
 if p<0:break
 i+=1
print'_'*i+'<'+s[i:]

Ваша функція повертається None, а не відповідь. А як ви рахуєте 107? Я рахую 110.
Стефан Похманн

@StefanPochmann подвійні пробіли - це вкладки, і дозволено друкувати відповідь, а не повертати її
Blue

@muddyfish Ах, дякую. Вони, схоже, тут не є вкладками, навіть коли я переходжу до редагування. І проблема чітко говорить про "повернення" ... Чи існують правила, пов’язані з усім сайтом, чи це так? (Я тут досить новий і не знаю)
Стефан Похман

Вкладки @StefanPochmann їдять SE (зазвичай перетворюються на 4 проміжки). Якщо чітко не вказано друк у функції, дозволено. ОП, мабуть, не мав на увазі це перекрити
Синій

Я думаю, що розумно сказати, що він завжди повинен або повертатися, якщо це функція, або читати зі stdin та друкувати. Я перейду до читання з stdin, який у будь-якому випадку повинен бути коротшим.
Arfie

8

Python 2, 89 байт

Іноді моя вперта рішучість зробити Python функціональною мовою має свої переваги.

def f(s,l=1):l+=(s[:1]in'plePLE')-(s[:1]in'ghosGHOS');return s*l and'_'+f(s[1:],l)or'<'+s

(Злегка) невольф:

def f(s, l=1):
    l += (s[:1] in 'plePLE') - (s[:1] in 'ghosGHOS')
    return (s * l) and ('_' + f(s[1:], l)) or ('<' + s)

Збирає рядок результатів за допомогою рекурсії. Оновлення до l(для "життя") додає 1 для гранул ( True - False == 1), віднімає 1 для привидів ( False - True == -1) і додає 0 для будь-якого іншого символу. Він також додає 0, коли sце порожня рядок, завдяки нарізці Python і тому, що '' in any_str == True, таким чином, гранули і привид скасовують.

Оператор return використовує test and b or aзамість того, a if test else bщоб зберегти один байт. Базовий випадок рекурсії виникає, коли або закінчується рядок, або Pac-Man закінчується з гранул, лаконічно представлених як s*p, що дорівнює ''(і тому оцінюється як хибне), коли s == ''або p == 0.


8

C #, 269 256 232 212 211 байт

Перший в історії публікацію тут, тому це, мабуть, набагато довше, ніж могло б бути (і, мабуть, тому, що воно є в C #). Будь-які поради щодо того, де я могла би скоротити це було б чудово!

Дякую всім за коментарі, які мені допомогли!

Гольф-версія

static void p(string x){int p=0,i=0;string t='<'+x;var s=t.ToCharArray();for(;++i<s.Length;){if("PELpel".Contains(s[i]))p++;if("GHOSghos".Contains(s[i])&&--p<0)break;s[i]='<';if(i>0)s[i-1]='_';}Console.Write(s);}

Безгольова версія

static void p(string x) {
 int p = 0, i = 0;
 string t = '<' + x;
 var s = t.ToCharArray();
 for (; ++i < s.Length;) {
  if ("PELpel".Contains(s[i])) p++;
  if ("GHOSghos".Contains(s[i]) && --p < 0) break;
  s[i] = '<';
  if (i > 0) s[i - 1] = '_';
 }
 Console.Write(s);
}

1
Ви можете замінити типи в зміннихдеклараціях, використовуючи ключове слово var. наприклад, var temp = '' + вхід; Цикл for можна переписати, щоб зберегти 4 символи: for (var i = 0; i ++ <s.Length;)
CSharpie

1
Ви можете використовувати коми для декларацій "int i = 0, p = 0; рядок P =" PELpel ", G =" GHOSghos ", t = '' + x;" та зміна від @CSharpie, роблячи цикл "for (; i ++ <s.Length;)". Крім того, ви можете "Console.Write (s);" безпосередньо на загальну суму 235 байт.
Ніксон

1
Я думаю, що це також має працювати без elseзбереження ще 5 символів. І, запустивши цикл у i = 1вас, ви зможете видалити останню, якщо код може виконуватися кожен раз.
Фрозн

1
Ви можете позбутися своєї декларації c і просто ввести s[i]доступ для 5 символів.
JustinM

1
Чи варто призначати P="PELpel"і G="GHOSghos"? Ви використовуєте їх лише один раз. Я щось пропускаю, чи це лише 4 зайвих символи? Також вам потрібен else? "PELpel".Contains(c)і "GHOSghos".Contains(c)повинні бути взаємовиключними.
jpmc26

7

Pyth, 53 48 44 байт

4 байти завдяки @ Pietu1998 за хитрість !!@-> }(яку можуть зрозуміти лише люди, які знають Pyth)

++ * Jf <@ + sM._m - !! @ d "PELpel" !! @ d "GHOSghos" Q_1T00 \ _ \ <> QJ 
++ * Jf <@ + sM._m - !! @ d "PEL" !! @ d "GHOS" rQ1_1T00 \ _ \ <> QJ
++ * Jf <@ + sM._m-} d "PEL"} d "GHOS" rz1_1T00 \ _ \ <> zJ

Тестовий набір.


17
що лише люди, які знають Pyth, можуть зрозуміти Ну, як і решта коду, природно
Луїс Мендо

4
@LuisMendo Щоб бути справедливим до людей, які не знають Pyth, я впевнений, що більшість з них може зрозуміти, що перетин множини між одним одиночним набором та іншим набором, що має будь-які члени, еквівалентний тому, що член набору однотонних є членом більший набір: P
FryAmTheEggman

1
@FryAmTheEggman так очевидно, що !!@це просто триграф }, правда? : p
CAD97

7

MATL , 37 36 35 байт

tkt'ghos'mw'pel'm-Ys1=Y>&)g95*60bhh

Спробуйте в Інтернеті!

Пояснення

tkt      % Input string implicitly. Duplicate, convert to lower case, duplicate
'ghos'm  % True for "ghost" characters
w'pel'm  % Swap to bring lowercase copy to top. True for "pellet" characters
-Ys      % Subtract, cumulative sum. Pac-Man can reach until the first "1"
1=       % True for entries that equal 1
Y>       % Cumulative maximum. This gives false until the first true is found, and
         % true from there on
&)       % Split original string in two parts, given by the zeros and ones respectively
g95*     % Convert the first part into ones and multiply by 95. This gives a numerical
         % array containing number 95 (ASCII for '_')
60       % Push 60 (ASCII for '<')
b        % Bubble up second part of original string
hh       % Concatenate the three strings/arrays, automatically converting to char

7

JavaScript (ES6), 98 байт

s=>s.replace(/./g,c=>p<0?c:(p+=/[elp]/i.test(c)-/[ghos]/i.test(c))<0?"<"+c:"_",p=0)+"<".slice(p<0)

Пояснення: pпідтримує поточну кількість гранул. Якщо це вже негативно, ми просто повертаємо персонаж і рухаємось далі, так що решта рядка не зачіпається. В іншому випадку ми перевіряємо поточний символ, і якщо це pстає негативним, ми вставляємо <символ, інакше заміняємо поточний символ на _. Нарешті, якщо pніколи не стає негативним, ми суфікс a <до рядка.


4

Pyth, 47 46 44 байт

++*\_Kh+f!h=+Z-}Jr@zT0"pel"}J"ghos"Uzlz\<>zK

Спробуйте в Інтернеті. Тестовий набір.

Зовсім інший підхід від Leaky Nun's, і я цілком впевнений, що це можна пограти в гольф далі.


Використовуйте Zзамість цього Gі змініть f!наf!h
Leaky Nun

@LeakyNun Просто зрозумів, що це також на іншій вкладці. Дякую.
PurkkaKoodari

2
Я думаю , що tв "ghost"повинно бути видалений
Дірявий Nun

Якщо ми продовжуємо гольф наших рішень, у чому полягає визначальна різниця між нашими рішеннями?
Leaky Nun

@LeakyNun Я не впевнений, що з них ближче, але моя перша спроба отримала мені 43 байти , і я не думаю, що мені потрібно додати третю відповідь. Може, нам слід спільно працювати в чаті Pyth?
FryAmTheEggman

4

Луа, 198 190 184 185 163 байт

Гаразд, зізнаюся, це довго. Дуже довго. У Lua є кілька інструментів для гри зі струнами, але вона обмежена, це стосується і умовних умов, які займають багато місця.

Редагувати: дякую @LeakyNun за те, що врятував мені 9 байт :) Втратив кілька байтів, щоб виправити помилку

Редагувати 2: 163 байт рішення, знайдене @LeakyNun

i=0p=0n=...for c in n:gmatch"."do
p=p+(c:find"[ghosGHOS]"and-1or c:find"[pelPEL]"and 1or 0)if p<0then
break else i=i+1 end end print(('_'):rep(i)..'<'..n:sub(i+1))

185 років

p=0z=(...):gsub(".",function(c)p=p+(c:find"[ghosGHOS]"and-1or
c:find"[pelPEL]"and 1or 0)s=p<0 and 1or s
return s and c or'_'end)_,i,s=z:find"(_+)"print((s or'')..'<'..z:sub(1+(i or 0)))

Безумовно

i=0                        -- number of characters eaten
p=0                        -- pellet counter
n=...                      -- shorthand for the argument
for c in n:gmatch"."       -- iterate over each characters in the input
do
  p=p+(c:find"[ghosGHOS]"  -- if the current char is a GHOST
        and-1              -- decrement the pellet counter
      or c:find"[pelPEL]"  -- if it's a PELLET
        and 1              -- increment it
      or 0)                -- else, leave it alone
  if p<0                   -- if we try to eat a ghost without pellet
  then 
    break                  -- stop iterating
  else
    i=i+1                  -- else, increment our score
  end
end

print(('_'):rep(i)         -- print i*'_'
  ..'<'                    -- appended with Pacman
  ..n:sub(i+1))            -- appended with the remaining characters if we died

Видаліть d=c:lower()і шукайте великі літери також
Leaky Nun

and 1or s and 1or s s and s
Лина монашка

@LeakyNun не бачив, що буде коротше, щоб просто написати всі листи ... Дякую. Також у другому коментарі згадувалося щось, що я змінив, але лише в невольф> _ <
Katenkyo

print(('').rep('_',i)..','..z:sub(i+1))
Leaky Nun

@LeakyNun Я працюю над подібним рішенням, але проблема випливає з того, що iможе бутиnil
Katenkyo

3

Пітон 3, 176 157 150 149 134 133 124 байт

Визначте функцію, на fяку покладено рядок як аргумент

def f(s):
 n=i=0
 for c in s:
  if c in"GgHhOoSs":
   if n:n-=1
   else:break
  n+=c in"PpEeLl";i+=1
 return"_"*i+"<"+s[i:]

Можливо, може бути більше гольфу

Дякую всім, хто прокоментував: D


1
﹐ Видаліть x=c.upper()і шукайте малі матчі
Leaky Nun

Ви можете зберегти деякі, записавши деякі вирази в одному рядку, розділеному, ;а не кожним у своєму рядку. Також ви можете використовувати Python 2, що дозволяє використовувати пробіли як перший рівень намірів, а вкладки як другий.
Денкер

n=i=0, не n=0і i=0. t[i]="_"замість t[i] = "_"того ж для t[i] = "<". return''.join(t), видаліть пробіл.
Ерік Аутгольфер

@LeakyNun У тестах є великі регістри.
TuxCrafting

@ TùxCräftîñg Ні, вони означають "GgHhOoSs"і "PpEeLl".
Ерік Аутгольфер

2

Python 3, 114 110 байт

Мій перший гольф-код.

Завдяки д-р Зелені яйця та Залізна людина за збереження 4-х байт.

l,x=1,0
f,y,s="ghosGHOS","pelPEL",input()
while s[x:]*l:l+=(s[x]in y)-(s[x]in f);x+=l>0
print("_"*x+"<"+s[x:])

Використовує оцінку булевих значень до одиниці та нуля, щоб конденсувати логічне І множення. (0 * 0 = 0, 1 * 0 = 0, 1 * 1 = 1). Я сподіваюся, що це хороша перша спроба.


Приємна відповідь і ласкаво просимо на сайт! Яку версію python ви використовуєте? Ви можете вказати це. Також я його не перевіряв, але ви, можливо, зможете while s[x:]*lзняти 4 байти.
DJMcMayhem

1

Powershell, 185

{$l=1;$o="";for($i=0;($i -lt $_.Length) -or (($o+="<") -and 0); $i++){if ($_[$i] -match '[pel]'){$l++}if($_[$i] -match '[ghos]'){$l--}if(!$l){$o+="<"+$_.substring($i);break}$o+="_"}$o}

Безголівки:

("Pacman wins!",
"Pacman loses wah-wah :(",
"PELLET PELLET GHOST",
"Hello World!"
) | 
% {
    $l=1;$o="";
    for($i = 0; ($i -lt $_.Length) -or (($o+="<") -and 0); $i++) {
        if ($_[$i] -match '[pel]') { $l++ }
        if ($_[$i] -match '[ghos]') { $l--}
        if (!$l) { $o+="<"+$_.substring($i); break }        
        $o += "_"
    }
    $o
}

1

Python3, 211 184 байт

Аргумент 's' - це рядок

def f(s):
    p=c=0
    for i in s:
        if i in "gGhHoOsS":
            if p<1:break
            else:p-=1
        if i in "pPeElL":p+=1
        c+=1
    return"_"*c + "<" + s[c:]

Буду вдячний за будь-які поради щодо гольфу, оскільки це моя перша спроба гольфу з кодом

Дякуємо за коментар :)


2
Ласкаво просимо до головоломки програмування та коду для гольфу! Деякі поради: між операторами існує багато непотрібних пробілів. Видалення їх дозволить заощадити гарну кількість байтів. Також ви можете використовувати Python 2, що дозволяє використовувати пробіли як перший рівень намірів, а вкладки для інших.
Денкер

1
Перший ви можете замінити return "_"*c + "<" + s[c:]лише тим break, що цей код буде виконуватися після циклу for.
Arfie

Спробуйте в Інтернеті! До речі, я отримав 183 байти. Чи є підрахований новий рядок?
Павло

1

Haskell, 119 113 байт

Завдяки Даніелю Вагнеру на 6 байт менше.

p=(0!)
n!(c:s)|elem c"ghosGHOS"=if n<1then '<':c:s else(n-1)&s|elem c"elpELP"=(n+1)&s|0<1=n&s
_!_="<"
n&s='_':n!s

Називай це як p "Hello World!".

Це 1thenкрайній випадок, який правильно інтерпретується в моєму GHC (7.10), але він кидає більшість підсвічувачів синтаксису. Тож це може трактуватися і по-різному у вашому компіляторі.

Безголівки:

pacman string = go 0 string

-- | In the golfed version: (!)
go _   []                   = "<"                            -- won
go pellets (char:string)
 | char `elem` "ghosGHOS"
 = if pellets < 1        then '<':char:string                -- lost
                         else nextStep (pellets - 1) string  -- ghost
 | char `elem` "elpELP"
 =                            nextStep (pellets + 1) string  -- pellet
 | otherwise
 =                            nextStep  pellets      string  -- anything else

-- | In the golfed version: (&)
nextStep pellets string = '_':(go pellets string)

1
Ви можете зберегти кілька байтів, поставивши всі щитки в одну лінію, наприклад n!(c:s)|elem c"blah"=blah|elem c"blah"=blah|0<1=blah.
Даніель Вагнер

@Daniel Wagner Приємна порада, дякую!
MarLinn

Чи можете ви додати посилання TIO ? Я намагаюся отримувати помилки, коли я намагаюся змусити її працювати.
Павло

1

C, 237 байт

#include<stdio.h>
#include<string.h>
main(p,i,j){char s[99];fgets(s,99,stdin);for(p=i=0;s[i];++i){if(strchr("GHOSghos",s[i])){if(p)p--;else break;}else if(strchr("PELpel",s[i]))p++;}j=i-(s[i]==0);while(j--)printf("_");printf("<%s",s+i);}

1

C ++, 315 373 327 байт

(Примітка: все-таки гольф)

#include <iostream>
#include <string>
using namespace std;
int main(){string input;getline(cin, input);
if(input.find("Pac-Man loses")!=string::npos||input.find("Pacman loses")!=string::npos)
    cout<<"<"<<input.substr(15,input.length()-1);
else{for(unsigned i=0;i<=input.length();++i)
    cout << "_";
cout<<"<";
}return 0;
}

1
Pac-Man не програє, коли це має бути.
tildearrow

Привіт @tildearrow, дякую за перегляд мого коду! Я оновлю свою посаду.
тахма

Я думаю, що це може бути більше гольфу. Спробуйте видалити / переклад рядка прогалин після if(), і видалення пробілів навколо !=, ||, =, -, і <=. Крім того, не cin>>inputпрацює замість getline? Ви також можете конденсуватися навколо ;.
NoOneIsHere

@NoOneIsHere, дякую за ваш коментар! Я насправді новачок у коді-гольфінгу, тому спробую ще раз поширити свій код і оновити свою посаду. Якщо у вас є якісь корисні поради щодо гольф-коду, я дуже вдячний.
тахма

1
Ви можете подивитися поради щодо C / C ++ гольфу .
NoOneIsHere

1

Ruby, (119 байт)

q=i=0;a=$**" ";a.split(//).each{|c|q+=((c+?p=~/[ple]/i)^1)-((c+?g=~/[ghos]/i)^1);q<0?break : i+=1};p ?_*i+?<+a[i..-1]

Напевно, є деякі речі, яких мені не вистачає, коли я новачок у цьому ...

Рубі - мій друг :)


1
Ласкаво просимо до PPCG!
FlipTack

0

Perl, 54 (52 + 2) байт

s/([pel](?1)*[ghos]|[^ghos
])*/'_'x(length$&).'<'/ei

Необхідно -pвказати в параметрах командного рядка.

Пояснення:

Цей -pпараметр призводить до того, що оператор загортається у цикл читання-модифікація-друк, де під час кожної ітерації циклу $_міститься рядок введення, включаючи роздільник рядка.

Зворотній вираз є значною мірою тією ж ідеєю, що і у відповіді Ретина.

Назвіть шаблон пошуку ([pel](?1)*[ghos]|[^ghos ])*"прийнятним". Тоді це може бути рекурсивно визначено як:

Рядок є "прийнятним", якщо:

  • Це символ, за PELLETвинятком T, за ним - прийнятна рядок, а потім - символ у, GHOSTкрім T.
  • Це не символ, за GHOSTвинятком того, Tщо це не символ нового рядка.
  • Це об'єднання будь-якого числа (включаючи 0) прийнятних рядків.

Це визначення дозволяє отримати більше гранул, ніж привидів: PELперсонаж може відповідати або символу гранул, або символу, що не привид.

Порожній рядок вважається прийнятним, тому гарантується, що регулярний вираз буде відповідати в позиції 0, де буде узгоджена найдовша прийнятна підрядка.

Потім ця довга прийнятна підрядок узгоджується з підкресленнями однакової довжини, за якими слід <.


Прапори iirc, як -p, вважаються кожним байтом.
Павло

1
@Pavel Це складно. Якщо звичайне виклик без -pвже використаного -, наприклад perl -e-> perl -pe, тоді -вивільнення вільне. Але я думаю, що perl -eверсія довша через цитування, тому я думаю, що я не можу це використати тут.
hvd
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.