吃豆人可以吃这串吗?


46

在游戏的街机版本中,吃豆人吃豆点。但是,在这个挑战中,他渴望字符串中的字母数字字符和标点符号。

您的任务是创建一个函数,该函数为吃豆人提供一个字符串,评估他是否可以吃它,然后返回其中包含吃豆人位置的字符串。

吃豆人(<)从左到右吃字符,每个字符在走时都留下下划线或空格,他的目标是从第一个位置1到最后一个位置+1:

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

但是,如果吃豆人的天敌幽灵将阻止他,如果他遇到单词“ GHOST”(不区分大小写)中的一个字母。您的函数在遇到ghost字符时应返回吃豆人所在位置的字符串:

1. <No!
2. _<o!

唯一可以击败幽灵的东西就是力量药丸。如果吃豆人在遇到鬼魂之前到达单词“ PELLET”(也不区分大小写)中的字母,他将吃掉鬼魂并继续移动,该小球将被耗尽。强力药丸可以堆叠(即,ppgg两个鬼魂都会被吃掉)。所述Ť字符存在既作为重影和小球,因此它可以忽略不计(如任何其他信处理,等a)。

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

为了进一步说明,在字符串“吃豆人在这里输”中,发生以下操作:

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ɪᴋᴇʀ

输出中是否接受尾随制表?
Katenkyo,2016年

7
+1是pacman输掉的地方。聪明的测试用例。
奥利维尔·杜拉克

5
> [在这次挑战中,他渴望字符串中的字母数字字符和标点符号。... Yacc-男人?
哈兹

9
现在,每当我看该<标志时,我都会看到一个伪装成灰色的
吃豆人和

Answers:



30

视网膜55 38字节

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

在线尝试!(第一行仅允许一次运行多个测试用例。)

说明

本质上,问题是要找到没有不匹配的右括号的最长前缀。除了我们可以使用elp代替(,要么ghos代替)

因此,该解决方案几乎是平衡组的教科书示例。我不会过多地介绍它们的工作原理,因为此代码与您可以在平衡组的SO答案中阅读的标准示例基本相同。

因此,整个程序是单个正则表达式替换。该i激活不区分大小写。然后,我们将一个小球与匹配[elp]并增加深度计数器(以group的捕获堆栈的形式2),或者我们将一个不重影的对象与之[ghos]匹配,或者将一个重影与之匹配,.并通过从堆栈中弹出来减少深度计数器2。当然,从原则上讲,这允许将小球与该[^ghos]部分匹配,或者将非重影与该.部分匹配,但是由于贪婪的匹配和正则表达式的回溯方式,这些可能性从未被正则表达式引擎尝试过。

然后,替换使用了两个Retina特定功能:$*重复字符右侧的次数,取决于其左侧令牌的指定次数。该令牌就是$.&整个匹配的长度。这仅表示我们将比赛中的每个字符替换为_。然后,我们还会<在这些下划线后面附加一个。输入中未被占用的部分将不受替换的影响。


很好地滥用了捕获团体!
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
斯特凡Pochmann

@StefanPochmann双空间是标签和它允许打印的答案,而不是返回它

@muddyfish啊,谢谢。不过,即使在我进入“编辑”页面时,它们似乎也不是标签。问题清楚地表明是“返回”……是否存在整个站点范围内的否决规则?(我在这里很
陌生,

SE吃掉@StefanPochmann选项卡(通常转换为4个空格)。除非明确声明,否则允许在函数中打印。OP可能并不意味着要覆盖它
蓝色

我认为可以合理地说它应该总是返回(如果它是一个函数)或从stdin和print读取。我将改为从stdin进行阅读,无论如何应该更短一些。
Arfie '16

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(表示“生命”)对小球(True - False == 1)加1,对幻影(False - True == -1)减1,对于其他任何字符加0。s由于Python的切片以及的事实,当空字符串也加0时'' 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-keyword替换变量类型中的类型。例如var temp =''+ input; 可以重写for循环以节省4个字符:for(var i = 0; i ++ <s.Length;)
CSharpie 2016年

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您应该能够删除最后一个,因为每次都可以执行该代码。
Frozn

1
您可以摆脱c声明,而只需内联s[i]5个字符的访问即可。
Phaeze

1
是否值得分配P="PELpel"G="GHOSghos"?您每个只能使用一次。我是否想念一些东西,还是只剩下4个字符?另外,您需要else吗?"PELpel".Contains(c)并且"GHOSghos".Contains(c)应该互斥。
jpmc26 2016年

7

Pyth,53 48 44字节

@ Pietu1998提供了4个字节的!!@-> }技巧(只有知道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的人才能自然而然地理解好代码的其余部分
Luis Mendo

4
@LuisMendo对于不认识Pyth的人来说,我很确定他们中的大多数人都可以理解,一个单例集与另一个具有任何成员的集合之间的集合交集等同于单例集的成员成为该成员的成员。大集:P
FryAmTheEggman '16

1
@FryAmTheEggman很显然!!@只是一个三部曲},对吧?:p
CAD97

7

MATL37 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的方法完全不同,我很确定这可以进一步推广。


使用Z替代G和改变f!,以f!h
漏修女

@LeakyNun刚刚在另一个选项卡中也发现了这一点。谢谢。
PurkkaKoodari '16

2
我认为,t"ghost"应删除
漏嫩

如果我们继续关注我们的解决方案,那么我们的解决方案之间的显着区别是什么?
Leaky Nun

@LeakyNun我不确定其中哪个更接近,但是我的第一次尝试使我获得了43个字节,而且我认为我不需要添加第三个答案。也许我们应该在Pyth聊天室一起工作?
FryAmTheEggman

4

Lua中,198 190 184 185 163个字节

好吧,我承认,这很长。很长。Lua有一些可用来处理字符串的工具,但它是有限的,对于占用大量空间的条件语句也是如此。

编辑:感谢@LeakyNun为我节省了9个字节:)丢失了一些字节来修复错误

编辑2:@LeakyNun找到的163字节解决方案

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()和搜索大写字母,以及
漏尼姑

and 1or s and 1or s s and s
Leaky Nun

@LeakyNun没想到只写所有字母会更短...谢谢。此外,第二条评论提到了我更改的内容,但仅限于未打高尔夫球的> _ <
Katenkyo

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

@LeakyNun我正在研究类似的解决方案,但问题来自i可能是这样的事实nil
Katenkyo,2016年

3

Python 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()和搜索小写的比赛
破尼姑

您可以通过在由a分隔的同一行上编写一些表达式,;而不是将每个表达式放在自己的行中来保存一些表达式。您还可以使用Python 2,它允许您将空格用作第一个预期级别,将制表符用作第二个预期级别。
Denker

n=i=0,不是n=0i=0t[i]="_"代替t[i] = "_",相同t[i] = "<"return''.join(t),请删除该空间。
暴民埃里克(Erik the Outgolfer)

@LeakyNun测试用例中有大写字母。
TuxCrafting

@TùxCräftîñg不,他们的意思是"GgHhOoSs""PpEeLl"
暴民埃里克

2

Python 3中,114个 110字节

我的第一个代码高尔夫。

感谢Green Eggs博士和Iron Man节省了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:])

利用布尔值的取值为1和0来将逻辑AND压缩为乘法。(0 * 0 = 0,1 * 0 = 0,1 * 1 = 1)。我希望这是一个很好的第一次尝试。


很好的答案,欢迎光临本站!您正在使用哪个版本的python?您可能要指定。另外,我还没有测试过,但是您也许可以删除while s[x:]*l4个字节。
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,它允许您将空格用作第一个预期级别,并使用制表符来指定其他级别。
Denker

1
您可以将第一个替换为return "_"*c + "<" + s[c:]a break,因为无论如何,该代码都会在for循环之后执行。
Arfie '16

在线尝试!顺便说一下,我得到了183个字节。您算上尾随换行符了吗?
帕维尔

1

哈斯克尔, 119 113字节

多亏了Daniel Wagner少了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

@Daniel Wagner好的提示,谢谢!
MarLinn '16

您可以添加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
吃豆人并不会因此而输。
tildearrow '16

@tildearrow,您好,感谢您检查我的代码!我将更新我的帖子。
tachma '16

我认为这可以打更多。尝试之后,除去换行/空间if(),和周围去掉空格!=||=-,和<=。另外,不是cin>>input代替getline?您也可以在附近凝结;
NoOneIsHere

@NoOneIsHere,谢谢您的评论!我实际上是代码高尔夫球的新手,所以我将尝试进一步研究代码并更新我的文章。如果您在代码高尔夫球方面还有其他有用的建议,我将非常感谢。
tachma '16

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]

我可能还缺少一些东西,因为我是新来的...

Ruby是我的朋友:)


1
欢迎来到PPCG!
FlipTack

0

Perl,54(52 + 2)字节

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

需要-p在命令行选项中指定。

说明:

-p选项使语句被包装在read-modify-print循环中,该循环在每次循环迭代期间$_包含一行输入,包括行定界符。

正则表达式与Retina答案基本相同。

将搜索模式称为([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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.