Pac-Man pode comer essa corda?


46

Na versão arcade do jogo, Pac-Man come pac-dots. No entanto, neste desafio, ele tem fome de caracteres alfanuméricos e pontuação em uma sequência.

Sua tarefa é criar uma função que alimente uma sequência de caracteres do Pac-Man, avalie se ele pode ou não comê-la e retorne a sequência com a localização do Pac-Man.

Pac-Man ( <) come caracteres da esquerda para a direita, deixando um sublinhado ou espaço para cada personagem à medida que avança, e seu objetivo é ir da primeira posição-1 à última posição + 1:

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

No entanto, o inimigo natural do Pac-Man, o fantasma, irá detê-lo se ele encontrar uma das letras da palavra "FANTASMA" (não diferencia maiúsculas de minúsculas). Sua função deve retornar a string com a localização do Pac-Man quando ele encontrar o ghostpersonagem:

1. <No!
2. _<o!

A única coisa que pode derrotar um fantasma é um pellet de poder. Se o Pac-Man alcançar uma letra com a palavra "PELLET" (também não diferencia maiúsculas de minúsculas) antes de chegar a um fantasma, ele o comerá e continuará se movendo, e esse pellet será usado. Grânulos de poder podem empilhar (ou seja, em ppggambos os fantasmas seriam comidos). O caractere T existe como um fantasma e um pellet, para que possa ser ignorado (tratado como qualquer outra letra, como a).

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

Para esclarecer, na sequência "Pac-Man perde aqui", ocorrem as seguintes operações:

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

Exemplos

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: ___________<

Isso é código-golfe - a menor pontuação em bytes ganha.


29
Então os pellets não têm prazo de validade?
Rɪᴋᴇʀ

Tabulações à direita são aceitas na saída?
precisa

7
+1 pelo fato de "aqui" ser o local onde o pacman perde. Caso de teste inteligente.
Olivier Dulac

5
> [Neste] desafio, ele tem fome de caracteres alfanuméricos e pontuação em uma sequência. ... Yacc- cara?
Kaz

9
Agora eu vejo um pacman cinza camuflada com lábios negros cada vez que eu olhar para o <símbolo ...
QBrute

Respostas:


16

Geléia, 34 33 bytes

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

Experimente online!

Acho que finalmente estou começando a entender Jelly. Parece um pouco assustador.


5
Eu começar a se preocupar quando você pode lê-lo fluentemente :)
quetzalcoatl

30

Retina , 55 38 bytes

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

Experimente online! (A primeira linha apenas permite executar vários casos de teste ao mesmo tempo.)

Explicação

O problema é essencialmente encontrar o prefixo mais longo que não tem um parêntese de fechamento incomparável. Exceto que podemos usar e, lou pno lugar de (e ou g, h, oou sno lugar de ).

Portanto, essa solução é quase um exemplo de grupo de balanceamento. Não entrarei em muitos detalhes sobre como eles funcionam, pois esse código é essencialmente o mesmo que o exemplo padrão que você pode ler na minha resposta SO sobre grupos de balanceamento .

O programa inteiro é, portanto, uma única substituição de regex. A iativa caso insensibilidade. Em seguida, combinamos um pellet [elp]e incrementamos o contador de profundidade (na forma da pilha de captura de grupo 2), ou combinamos com algo que não é um fantasma [ghos]ou com um fantasma .e diminuímos o contador de profundidade ao sair da pilha 2. Obviamente, em princípio, isso permite combinar um pellet com a [^ghos]seção ou um não-fantasma com a .seção, mas, graças à correspondência gananciosa e à maneira como a regex é retornada, essas possibilidades nunca são tentadas pelo mecanismo de regex.

A substituição usa dois recursos específicos da Retina: $*repete o caractere à sua direita quantas vezes for especificado pelo token à sua esquerda. Esse token é $.&a duração de toda a partida. Isso significa apenas que substituímos cada personagem da partida por a _. E também anexamos a <a esses sublinhados. A parte da entrada que não é consumida simplesmente não é afetada pela substituição.


Bom abuso de capturar grupos!
Freira vazada

11
@LeakyNun Abuse? É para isso que são criados os grupos de equilíbrio. : D
Martin Ender

1
Ei, olha, uma resposta Retina que a aparência remotamente como o regex que eu uso
cat

10

Python 2, 114 113 108 bytes

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:]

Sua função retorna None, não a resposta. E como você conta 107? Conto 110.
Stefan Pochmann

@StefanPochmann as duplas espaços são guias e sua permissão para imprimir a resposta em vez de devolvê-lo
azul

@muddyfish Ah, obrigado. Eles não parecem tabs aqui, nem mesmo quando eu vou "editar". E o problema claramente indica "retorno" ... existem regras em todo o site que o anulam? (Eu sou muito novo aqui e não sei)
Stefan Pochmann

As guias @StefanPochmann são comidas pelo SE (normalmente convertidas em 4 espaços). A menos que a impressão explicitamente declarada em uma função seja permitida. O OP provavelmente não teve a intenção de anular isso
azul

Eu acho que é razoável dizer que ele sempre deve retornar se for uma função ou ler de stdin and print. Vou mudar para a leitura de stdin, que deve ser mais curta de qualquer maneira.
Arfie

8

Python 2, 89 bytes

Às vezes, minha determinação obstinada de tornar o Python uma linguagem funcional tem seus benefícios.

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

(Levemente) não destruído:

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

Constrói a sequência de resultados usando recursão. A atualização para l(para "vidas") adiciona 1 para pellets ( True - False == 1), subtrai 1 para fantasmas ( False - True == -1) e adiciona 0 para qualquer outro caractere. Ele também adiciona 0 quando sa string vazia, graças ao fatiamento do Python e ao fato de que '' in any_str == True, portanto, o pellet e o ghost são cancelados.

A declaração de retorno usa test and b or ano lugar de a if test else bpara salvar um byte. O caso da base de recursão ocorre quando a corda termina ou o Pac-Man fica sem pellets, representado sucintamente como s*p, o que é igual ''(e, portanto, avalia falso) quando é s == ''ou p == 0.


8

C #, 269 256 232 212 211 Bytes

Primeiro post aqui, então isso provavelmente é muito mais longo do que poderia ser (e provavelmente porque está em C #). Qualquer dica sobre onde eu poderia encurtar seria ótimo!

Obrigado a todos nos comentários que me ajudaram!

Versão Golfed

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);}

Versão ungolfed

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
Você pode substituir tipos em declarações variadas usando a palavra-chave var. por exemplo, var temp = '' + entrada; O laço pode ser reescrita para salvar 4 caracteres: para (var i = 0; i ++ <s.length;)
CSharpie

1
Você pode usar vírgulas para declarações "int i = 0, p = 0; string P =" PELpel ", G =" GHOSghos ", t = '' + x;" e a mudança de @CSharpie, criando o loop "for (; i ++ <s.Length;)". Além disso, você pode "Console.Write (s);" diretamente para um total de 235 bytes.
Nickson

1
Eu acho que também deve funcionar sem elsesalvar mais 5 caracteres. E iniciando o loop, i = 1você poderá remover o último se o código puder ser executado sempre.
Frozn 30/06/16

1
Você pode se livrar da sua declaração c e apenas inline o s[i]acesso para 5 caracteres.
JustinM - Restabelecer Monica

1
Vale a pena atribuir P="PELpel"e G="GHOSghos"? Você os usa apenas uma vez cada. Estou faltando alguma coisa, ou são apenas 4 caracteres extras? Além disso, você precisa do else? "PELpel".Contains(c)e "GHOSghos".Contains(c)deve ser mutuamente exclusivo.
Jpmc26

7

Pitão, 53 48 44 bytes

4 bytes graças a @ Pietu1998 pelo truque !!@-> }(que somente pessoas que conhecem Pyth podem entender)

++ * 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

Suíte de teste.


17
que apenas as pessoas que conhecem Pyth pode entender Bem, como praticamente o resto do código, naturalmente
Luis Mendo

4
@LuisMendo Para ser justo com pessoas que não conhecem Pyth, tenho certeza de que a maioria delas pode entender que a interseção entre um conjunto singleton e outro conjunto com membros é equivalente ao membro do conjunto singleton ser membro da conjunto maior: P
FryAmTheEggman

1
@FryAmTheEggman então, obviamente, !!@é apenas um trigrama para }, certo? : p
CAD97 30/06

7

MATL , 37 36 35 bytes

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

Experimente online!

Explicação

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 bytes

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

Explicação: pmantém o número atual de pelotas. Se já é negativo, retornamos o caractere e seguimos em frente, para que o restante da string seja intocado. Caso contrário, examinamos o caractere atual e, se isso se ptornar negativo, inserimos o <caractere, caso contrário, substituímos o caractere atual por _. Por fim, se pnunca se tornar negativo, temos o sufixo <a na string.


4

Pitão, 47 46 44 bytes

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

Experimente online. Suíte de teste.

Uma abordagem bem diferente da da Leaky Nun's, e tenho certeza de que isso pode ser ainda mais importante.


Use Zem vez de Ge mudança f!paraf!h
Leaky Nun

@LeakyNun Acabei de descobrir isso em outra guia também. Obrigado.
PurkkaKoodari

2
Eu acho que o tno "ghost"deve ser removido
Leaky Nun

Se continuarmos jogando golfe em nossas soluções, qual é a diferença definitiva entre nossas soluções?
Leaky Nun

@LeakyNun Não sei ao certo qual deles está mais próximo, mas minha primeira tentativa obteve 43 bytes e acho que não preciso adicionar uma terceira resposta. Talvez devêssemos trabalhar juntos na sala de chat Pyth?
FryAmTheEggman

4

Lua, 198 190 184 185 185 163 Bytes

Ok, eu admito, isso é longo. Muito longo. Lua tem algumas ferramentas para brincar com strings, mas é limitado, o mesmo vale para condicionais que ocupam muitos espaços.

Edit: obrigado @LeakyNun por me salvar 9 bytes :) Perdi alguns bytes para corrigir um erro

Edit 2: 163 Bytes solution found by @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))

Antigo 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)))

Ungolfed

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

Remova d=c:lower()e pesquise também os caracteres maiúsculos #
Leaky Nun

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

@LeakyNun não viu que seria mais curto escrever apenas todas as cartas ... Obrigado. Além disso, o segundo comentário mencionou algo que eu mudei, mas apenas no ungolfed> _ <
Katenkyo

print(('').rep('_',i)..','..z:sub(i+1))
Freira vazada

@LeakyNun Estou trabalhando em uma solução semelhante, mas o problema vem do fato de que ipode ser #nil
Katenkyo

3

Python 3, 176 157 150 149 134 133 124 bytes

Defina uma função nomeada fque aceita a string como argumento

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:]

Provavelmente pode ser jogado mais

Obrigado a todos que comentaram: D


1
﹐ Remova x=c.upper()e procure correspondências em minúsculas
Leaky Nun

Você pode salvar alguns escrevendo algumas expressões na mesma linha separadas por um em ;vez de ter cada uma em sua própria linha. Além disso, você pode usar o Python 2, que permite usar espaços como primeiro nível de intenção e tabulações como segundo.
Denker

n=i=0, não n=0e i=0. t[i]="_"em vez de t[i] = "_", o mesmo para t[i] = "<". return''.join(t), remova esse espaço.
Erik the Outgolfer

@LeakyNun Há maiúsculas nos casos de teste.
TuxCrafting

@ TùxCräftîñg Não, eles querem dizer "GgHhOoSs"e "PpEeLl".
Erik the Outgolfer

2

Python 3, 114 110 bytes

Meu primeiro código de golfe.

Agradecimentos ao Dr. Green Eggs e Iron Man por salvar 4 bytes.

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:])

Utiliza a avaliação de booleanos para um e zero para condensar um AND lógico a uma multiplicação. (0 * 0 = 0, 1 * 0 = 0, 1 * 1 = 1). Espero que seja uma boa primeira tentativa.


Boa resposta e bem-vindo ao site! Qual versão do python você está usando? Você pode querer especificar isso. Além disso, eu não testei, mas você pode fazer isso while s[x:]*lpara tirar 4 bytes.
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}

Ungolfed:

("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 bytes

O argumento 's' é uma string

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:]

Gostaria muito de receber algumas dicas de golfe, pois esta é minha primeira tentativa de golfe com código

Obrigado por comentar :)


2
Bem-vindo à programação de quebra-cabeças e código de golfe! Algumas dicas: Existem muitos espaços em branco desnecessários entre os operadores. Removê-los economizaria uma boa quantidade de bytes. Além disso, você pode usar o Python 2, que permite usar espaços como primeiro nível de intenção e guias para os outros.
Denker

1
Você pode substituir o primeiro return "_"*c + "<" + s[c:]por apenas a, breakpois esse código será executado após o loop for de qualquer maneira.
Arfie

Experimente online! A propósito, tenho 183 bytes. Existe uma nova linha à direita contada?
Pavel

1

Haskell, 119 113 bytes

Obrigado a Daniel Wagner por 6 bytes a menos.

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

Chame como p "Hello World!".

O 1thené um caso extremo que é interpretado corretamente no meu GHC (7,10), mas ele lança da maioria dos marcadores de sintaxe. Portanto, também pode ser interpretado de forma diferente no seu compilador.

Ungolfed:

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
Você pode economizar alguns bytes colocando todos os guardas na mesma linha, por exemplo n!(c:s)|elem c"blah"=blah|elem c"blah"=blah|0<1=blah.
Daniel Wagner

@Daniel Wagner Boa dica, obrigado!
MarLinn

Você pode adicionar um link TIO ? Eu continuo recebendo erros quando tento fazê-lo funcionar.
Pavel

1

C, 237 bytes

#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 bytes

(Nota: ainda jogando golfe)

#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 não está perdendo quando deveria estar.
tildearrow

Olá @tildearrow, obrigado por revisar meu código! Vou atualizar minha postagem.
Tachma

Eu acho que isso pode ser jogado mais. Tente remover newlines / espaços depois if(), e remover os espaços em torno !=, ||, =, -, e <=. Além disso, não cin>>inputfunciona em vez de getline? Você também pode condensar ;.
NoOneIsHere

@NoOneIsHere, obrigado pelo seu comentário! Na verdade, sou novo no código de golfe, então tentarei jogar um pouco mais meu código e atualizar minha postagem. Se você tiver outros conselhos úteis sobre golfe com código, eu realmente aprecio isso.
Tachma


1

Ruby, (119 bytes)

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]

Provavelmente há algumas coisas que estou perdendo, pois sou novo nisso ...

Ruby é meu amigo :)


1
Bem-vindo ao PPCG!
FlipTack

0

Perl, 54 (52 + 2) bytes

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

Precisa -pser especificado nas opções da linha de comandos.

Explicação:

A -popção faz com que a instrução seja quebrada em um loop de leitura-modificação-impressão, onde durante cada iteração do loop, $_contém uma linha de entrada, incluindo o delimitador de linha.

O regex é basicamente a mesma idéia da resposta da Retina.

Chame o padrão de pesquisa ([pel](?1)*[ghos]|[^ghos ])*"aceitável". Em seguida, pode ser definido recursivamente como:

Uma string é "aceitável" se:

  • É um caractere em PELLETexceto por T, seguido por uma sequência aceitável, seguido por um caractere em GHOSTexceto por T.
  • É um caractere que não está, GHOSTexceto Tque não é um caractere de nova linha.
  • É uma concatenação de qualquer número (incluindo 0) de cadeias aceitáveis.

Essa definição permite mais pellets do que fantasmas: um PELcaractere pode ser correspondido como um caractere de pellet ou um caractere não fantasma.

A cadeia vazia é considerada aceitável; portanto, é garantido que o regex corresponde à posição 0, onde a substring aceitável mais longa será correspondida.

Essa substring aceitável mais longa é correspondida por sublinhados de comprimento igual, seguidos por <.


Sinalizadores de iirc como -p contam como um byte cada.
Pavel

1
@ Pavel É complicado. Se a invocação normal ainda não for -pusada -, por exemplo perl -e- -> perl -pe, a opção -será gratuita. Mas acho que a perl -eversão é mais longa por causa da citação, então acho que não posso usá-la aqui.
hvd
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.