パックマンはこの糸を食べることができますか?


46

ゲームのアーケード版では、パックマンはパックドットを食べます。しかし、この課題では、彼は文字列の英数字と句読点に飢えています。

あなたの仕事は、パックマンに文字列を送り、食べられるかどうかを評価し、パックマンの位置を含む文字列を返す関数を作成することです。

パックマン(<)はキャラクターを左から右に食べ、行くたびに各キャラクターにアンダースコアまたはスペースを残し、彼の目標は最初の位置-1から最後の位置+1に到達することです:

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

ただし、パックマンの天敵であるゴーストは、「GHOST」という単語の文字の1つ(大文字と小文字を区別しない)に遭遇すると、彼を停止します。関数は、Pac-Manがghost文字を検出すると、その位置を含む文字列を返す必要があります。

1. <No!
2. _<o!

幽霊を打ち負かすことができるのはパワーペレットだけです。パックマンが幽霊来る前に「PELLET」(大文字と小文字を区別しない)という単語の文字に到達すると、幽霊を食べて動き続け、そのペレットは使い果たされます。パワーペレットは積み重ねることができます(つまり、ppgg両方のゴーストで食べられます)。Tのそれは(のような、任意の他の文字として扱われ、無視できるような文字は、ゴーストとペレットの両方として存在します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ɪᴋᴇʀ

出力で後続の集計は受け入れられますか?
かてんきょう

7
「ここ」がpacmanの敗北という事実のために+1。賢いテストケース。
オリビエデュラック

5
> [I]この挑戦では、彼は文字列の英数字と句読点に飢えています。... のYacc -man?
カズ

9
今、私は<シンボルを見るたびに黒い唇で偽装された灰色のパックマンを見ます
...-QBrute

回答:



30

網膜55 38バイト

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

オンラインでお試しください!(最初の行では、一度に複数のテストケースを実行できます。)

説明

問題は、本質的に、不一致の閉じ括弧を持たない最長のプレフィックスを見つけることです。私たちのいずれかを使用できることを除いてelまたはpの代わりに、(いずれかghoまたはsの代わりに)

したがって、このソリューションは、バランスグループの教科書の例に近いものです。このコードは基本的に、グループのバランスに関するSOの回答で参照できる標準的な例と同じであるため、それらの動作についてはあまり詳しく説明しません。

したがって、プログラム全体は単一の正規表現置換です。はi大文字と小文字を区別しません。次に、ペレットを一致させ[elp]て深さカウンターをインクリメントし(グループのキャプチャスタックの形式で2)、またはゴーストではないものを一致させるか、ゴースト[ghos]を一致させ、.スタックからポップして深さカウンターをデクリメントします2。もちろん、これにより、原則として[^ghos]セクションとペレットまたは非ゴーストをセクションに一致させることができます.が、貪欲なマッチングと正規表現のバックトラックのおかげで、これらの可能性は正規表現エンジンによって試行されません。

次に、置換は2つのRetina固有の機能を使用$*します。左側のトークンで指定された回数だけ文字を右側に繰り返します。そのトークンは$.&、マッチ全体の長さです。これは、一致する各文字をaに置き換えることを意味し_ます。そして、<それらの下線にもa を追加します。食べられない入力の部分は、置換の影響を受けないままです。


グループをキャプチャすることの素晴らしい虐待!
リーキー修道女

11
@LeakyNun虐待?それがバランシンググループの目的です。:D
マーティンエンダー

1
ねえ、私が使用している正規表現のように見えるRetinaの回答
cat

10

パイソン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ああ、ありがとう。ただし、ここではタブのようには見えませんが、「編集」に行ったときでもそうではありません。そして、問題は明らかに「戻り」と述べています...それを無効にするサイト全体のルールがありますか?(私はここでかなり新しく、知らない)
ステファンポックマン

@StefanPochmannタブは、SEによって食べられます(通常は4つのスペースに変換されます)。関数での印刷が明示的に指定されていない限り、許可されます。OPはおそらくこれをオーバーライドするつもりはありませんでした
ブルー

関数の場合は常に戻るか、stdinおよびprintから読み取る必要があると言うのは合理的だと思います。とにかく短くなるはずの標準入力からの読み取りに変更します。
アルフィー

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、空の文字列の場合は0 が追加されます。これは、Pythonのスライシングとのおかげで'' in any_str == True、ペレットとゴーストがキャンセルされます。

returnステートメントはtest and b or a、代わりにa if test else b1バイトを保存します。再帰ベース場合は、文字列の端部またはパックマンのいずれかが簡潔として表さペレットを使い果たしたときに発生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

1
宣言にはコンマを使用できます "int i = 0、p = 0; string P =" PELpel "、G =" GHOSghos "、t = '' + x;" @CSharpieからの変更により、ループが「for(; i ++ <s.Length;)」になります。さらに、「Console.Write(s);」を実行できます 合計235バイト。
ニックソン

1
elseさらに5文字を保存しなくても動作するはずです。そして、ループを開始するi = 1ことにより、コードを毎回実行できるため、最後のifを削除できるはずです。
Frozn

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バイト

!!@-> }トリックの@ 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を知っている人だけが理解できるものです。他のほとんどのコードと同様に、自然に
ルイスメンドー

4
@LuisMendo Pythを知らない人に公平を期すために、ほとんどの人は、あるシングルトンセットと任意のメンバーを持つ別のセットのセット交差が、シングルトンセットのメンバーがメンバーであることに等しいことを理解できると確信しています大きなセット:P
FryAmTheEggman

1
@FryAmTheEggmanので、明らかに!!@、単なる3文字表記}ですよね?: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

2
を削除tする"ghost"必要があります
Leaky Nun

ソリューションをゴルフで使い続けると、ソリューションの明確な違いは何ですか?
リーキー修道女

@LeakyNunこれらのどれが近いかはわかりませんが、最初の試みで43バイトが取得され、3番目の答えを追加する必要はないと思います。たぶん、Pythチャットルームで一緒に仕事をするべきでしょうか?
FryAmTheEggman

4

Luaの、198 190 184 185 163のバイト

わかりました、これは長いです。とても長い。Luaには文字列を操作するためのツールがいくつかありますが、制限されており、多くのスペースを必要とする条件文についても同様です。

編集:9バイトを保存してくれてありがとう@LeakyNun :)バグを修正するためにいくつかのバイトを失いました

編集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()大文字も削除して検索します
Leaky Nun

and 1or s and 1or s s and s
リーキー修道女

@LeakyNunは、すべての文字を書くだけでは短くなるとは思いませんでした。ありがとう。また、2番目のコメントは、私が変更したことを言及していましたが、変更されていない> _ <でのみ
-Katenkyo

print(('').rep('_',i)..','..z:sub(i+1))
漏れの修道女

@LeakyNun私は同様の解決策に取り組んでいますが、問題は次のi可能性があるという事実にnil
起因し

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 で区切って同じ行にいくつかの式を書くことで、いくつかを保存できます。また、スペースを最初の意図レベルとして使用し、タブを2番目の意図レベルとして使用できるPython 2を使用できます。
デンカー

n=i=0、ではn=0ありませんi=0t[i]="_"の代わりにt[i] = "_"、同じt[i] = "<"return''.join(t)、そのスペースを削除します。
エリックアウトゴルファー

@LeakyNunテストケースには大文字があります。
TuxCrafting

@TùxCräftîñgいいえ、それらはを意味"GgHhOoSs""PpEeLl"ます。
エリックアウトゴルファー

2

Python 3、114 110バイト

私の最初のコードゴルフ。

4バイトを節約してくれたDr Green EggsとIron Manに感謝します。

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を使用することもできます。これにより、最初の意図レベルとしてスペースを使用し、他のレベルのタブとして使用できます。
デンカー

1
とにかくforループの後にコードが実行されるため、最初のコードをreturn "_"*c + "<" + s[c:]aに置き換えることができbreakます。
アルフィー

オンラインでお試しください!ちなみに私は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
ダニエルワグナー

@ダニエル・ワグナー素敵なヒント、ありがとう!
-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
パックマンは、あるべき時に負けていない。
ティルダロー

こんにちは@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]

私はこれに慣れていないので、おそらくいくつか欠けていることがあります...

Rubyは私の友人です:)


1
PPCGへようこそ!
FlipTack 16

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での一致が保証されます。位置0では、受け入れ可能な最も長い部分文字列が一致します。

次に、この最長の受け入れ可能な部分文字列は、等しい長さの下線と一致し、その後にが続き<ます。


-pのようなiircフラグは、それぞれ1バイトとしてカウントします。
パベル

1
@Pavelそれは複雑です。-p既に使用されていない通常の呼び出し-、たとえばperl -e->のperl -pe場合、-は無料です。しかしperl -e、引用のためにバージョンが長くなると思うので、ここでは使用できないと思います。
hvd 16
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.