Gerenciar uma loja de tortas!

12

Sumário

Código de golfe é bom. Torta é boa . Quando você junta os dois, apenas coisas boas podem acontecer.

Especificações

Neste desafio, você gerenciará uma loja de tortas. O usuário será capaz de entrada de cinco diferentes comandos: list, count, buy, sell, e exit. Aqui estão as especificações para cada um:

  • list

    • Imprima uma lista de todas as tortas de propriedade e quantas. Separe com |e junte com um espaço de cada lado. |s devem estar alinhados. O valor da torta pode ser negativo (isso significa que você deve torta a alguém :(). Por exemplo:

      | apple     | 500 |
      | blueberry | 2   |
      | cherry    | -30 |
      
  • count [type]

    • Imprima quantas {{type}}tortas existem. Imprimir "Não há {{type}}torta!" se não houver. {{type}}sempre corresponderá à regex \w+(ou seja, sempre será uma única palavra). Por exemplo, se eu tivesse a quantidade de tortas mostrada na lista de exemplos acima, então

      > count apple
      500
      > count peach
      There is no peach pie!
      
  • buy [n] [type]

    • Adicione {{n}}à contagem de {{type}}torta e imprima-a. Crie {{type}}torta se não existir. {{n}}sempre corresponderá à regex [0-9]+(ou seja, sempre será um número). Aqui está outro exemplo (com o mesmo inventário de torta que os exemplos anteriores):

      > count blueberry
      2
      > buy 8 blueberry
      10
      
  • sell [n] [type]

    • Subtraia {{n}}da contagem de {{type}}torta e imprima-a. Crie {{type}}torta se não existir. Torta pode ser negativa (oh não, isso significaria que você deve torta a alguém!).

      > sell 15 blueberry
      -5
      > buy 5 blueberry
      0
      
  • exit

    • Imprimir "A loja de tortas fechou!" e saia do programa.

      > exit
      The pie store has closed!
      

Esclarecimentos adicionais

  • Se uma função não existente for chamada (a primeira palavra), imprima "Isso não é um comando válido".
  • Se uma função existente é chamada com argumentos inválidos (as palavras após a primeira palavra), o comportamento do seu programa não importa. "Argumentos inválidos" inclui muitos argumentos, muito poucos argumentos, {{n}}não sendo um número etc.
  • Torta é boa.
  • Sua entrada deve ser diferenciada da sua saída. Se você estiver executando o programa na linha de comando / terminal / shell / outra coisa baseada em texto, deverá prefixar a entrada com " > ​"(um sinal" maior que "e um espaço) ou alguma outra coisa com prefixo de entrada da shell.
  • Torta é boa.
  • Se todos esses esclarecimentos não forem bons o suficiente, aqui está um exemplo de saída:

    > list
    > buy 10 apple
    10
    > sell 10 blueberry
    -10
    > list
    | apple     | 10  |
    | blueberry | -10 |
    > count apple
    10
    > count peach
    There is no peach pie!
    > exit
    The pie store has closed!
    
  • Se você comprar torta / venda ea contagem líquida torna-se 0, você pode quer mantê-lo no listou não, e você pode quer voltar 0ou There is no {{type}} pie!quando countele.

  • Isso é ; o código mais curto vence.
  • Eu mencionei que a torta é boa?
Maçaneta da porta
fonte
3
Então, só para esclarecer ... a torta é boa?
Igby Largeman
4
É aceitável manter uma torta na lista com uma contagem de zero? Como se você fazer buy 1 applee sell 1 apple. E seria então válido count appleretornar em 0vez de There is no apple pie!?
Igby Largeman
@IgbyLargeman Porra, eu pensei que tinha esclarecido tudo! : P Adicionado novo caso de teste a esclarecimentos adicionais
Doorknob
@Doorknob hey! Estou exibindo "não há torta de maçã" depois que a última foi vendida.
John Dvorak
@JanDvorak Tudo bem, suponho que de qualquer maneira funcione. Atualizado novamente
Maçaneta da porta

Respostas:

3

Rubi, 335 330

h=Hash.new 0
loop{$><<"> "
puts case gets when/^list/
h.map{|x|?|+" %%%ds |"%h.flatten.map{|e|e.to_s.size}.max*2%x}when/^count (.*)/
h[$1]!=0?h[$1]:"There is no #{$1} pie!"when/^buy#{m=" (.*)"*2}/
h[$2]+=$1.to_i when/^sell#{m}/
h[$2]-=$1.to_i when/^exit/
puts"The pie store has closed!"
break else"That's not a valid command."end}

Alguns truques aqui:

?|+" %%%ds |"%[*h].flatten.map{|e|e.to_s.size}.max*2%x

A ideia da maçaneta da porta de usar um formatador é um passo além, literalmente. Primeiro, a string mais longa no hash entre todas as chaves e valores é formatada usando " %%%ds |"para produzir uma string como " %6s |". Sim, sem encolher cada coluna separadamente. Nunca houve a exigência de. Um tamanho serve para todos. Em seguida, essa sequência é duplicada e usada como uma sequência de formatação para a matriz de dois elementos que contém a linha atual. Por fim, o +começo do começo recebe sua palavra e precede um único tubo principal. Ah, e putstem um bom manuseio de matrizes.

Ruby tem interpolação em literais regex. É uma defesa apertada, mas economiza um pouco.

Ruby requer ponto e vírgula após a whenexpressão, mas não antes da palavra-chave. Isso leva a um artefato de renderização estranho quando o ponto-e-vírgula é substituído por uma nova linha.

E, é claro, perlismo conhecido como globals mágicos e correspondência automática de literais regex contra eles.

Além disso, a maioria das instruções incluindo casesão expressões.

John Dvorak
fonte
Truques muito inteligentes! +1
Maçaneta
Hmm, mas por que em Hash.new(0)vez de {}?
Maçaneta
1
Os hashes do Ruby no @Doorknob podem ter valores padrão (se você passar um objeto) ou até geradores (se você passar um bloco (chave, hash -> valor) .Se você não passar, o valor padrão é nil(o que não é permitir a adição) os usos literais. nilcomo o valor padrão.
John Dvorak
Poderia salvar alguns caracteres com h=Hash.new(0)=> h=Hash.new 0, print"> "=> $><<'> ', e acho que [*h]pode ser h. Tentei montar uma versão sem a instrução switch, pois todo esse texto padrão realmente se soma: gist.github.com/chron/6315218 . Eu estava tentando fazer alguma coisa funcionar com ruby -apmas a exigência para as marcas rápidas difícil: <
Paul Prestidge
@chron obrigado! Não posso acreditar que perdi a primeira e não sei por que pensei que $><<imprimia uma nova linha. Quanto à última sugestão ... infelizmente, os hashes não têm um método "achatado".
John Dvorak
3

Ruby, 427 384 caracteres

alias x puts
p={}
loop{
print'> '
case(u=gets.chop.split)[0]when'exit'
x'The pie store has closed!'
exit
when'list'
p.each{|k,v|printf"| %-#{p.keys.map(&:size).max}s | %-#{p.map{|e,a|a.to_s.size}.max}s |\n",k,v}
when'count'
x p[t=u[1]]||"There is no #{t} pie!"
when/sell|buy/
m=(u[0]<?s?1:-1)*u[1].to_i
if p[t=u[2]]
x p[t]+=m
else
x p[t]=m
end
else x"That's not a valid command."
end}

Graças a Jan Dvorak, pela enorme melhoria de 427 para 384 (!)

Maçaneta da porta
fonte
Você pode usar em loop{...}vez de while 1do...end.
precisa
Você pode usar splitsem seu argumento. Por padrão, ela se divide por espaços em branco (ou $;se isso for definido)
John Dvorak
p.keys.group_by(&:size).max[0]- você está procurando p.keys.map(&:size).maxou p.map{|x,_|x.size}.max? Aqui: [(t=p.values).max.to_s.size,t.min.to_s.size].maxvocê está procurando p.map{|_,x|x.to_s.size}.max? Eu vou levar a sua ideia e abuse do formatador, embora :-)
John Dvorak
p[t]=p[t]+mé equivalente a p[t]+=m(exceto p[t]é avaliado duas vezes em vez de uma vez) e mais. Use o último.
precisa
@JanDvorak Oooh, obrigado por todas as dicas: DI pensou que Ruby não tinha um +=operador; por isso não o usei. Talvez seja só por isso ++. Editarei minha postagem em breve.
Maçaneta da porta
3

Pitão Pie -thon 437

Tenho certeza de que há alguma folga na segunda última linha, mas o requisito de alinhar as barras para o tipo e o número da torta é um pouco confuso.

p,C,l={},"count",len
while 1:
 a=raw_input("> ").split();c=a.pop(0)
 if"exit"==c:print"The pie store has closed!";break
 if"sell"==c:a[0]=int(a[0])*-1
 if c in[C,"buy","sell"]:
  y=a[-1]
  if c!=C:p[y]=p.get(y,0)+int(a[0])
  print p.get(y,"There is no %s pie!"%y)
 elif"list"==c:
  for i in p:print"| %s | %s |"%(i.ljust(l(max(p.keys(),l))),str(p[i]).rjust(max([l(str(x)) for x in p.values()])))
 else:print"That's not a valid command."

De acordo com o comentário de Igby Largeman as regras não são claras sobre o que fazer se não era uma torta de um tipo específico, mas existem 0agora. Então, eu interpretei a meu favor.

Saída de amostra:

> buy 10 apple
10
> sell 1 blueberry
-1
> buy 1 keylime
1
> sell 3 apple
7
> buy 5 blueberry
4
> list
| keylime   | 1 |
| apple     | 7 |
| blueberry | 4 |
> sell 1 keylime
0
> count keylime
0

fonte
Desculpe, mas neste > count potatoproduz em That's not a valid command.vez de #There is no potato pie!
Maçaneta
@Doorknob Você está executando o IDLE?
Sim. Vou tentar em um arquivo #
Maçaneta da porta
Na verdade, a contagem não parece estar funcionando . Na verdade, às vezes funciona, mas às vezes não. É muito estranho ...
Maçaneta da porta
3
Hehe, eu sabia que era um conflito de nomes de algum tipo: P +1 Ah, e também, meu arquivo para o seu programa tinha um nome divertido pie.py:: P
Maçaneta da porta
3

C # - 571 568 559

Trazendo a retaguarda, como de costume, com o C # irremediavelmente detalhado.

using C=System.Console;class Z{static void Main(){var P=new 
System.Collections.Generic.Dictionary<string,int>();int i=0,n;a:C.Write
("> ");var I=C.ReadLine().Split(' ');var c=I[0];object s=c=="exit"?
"The pie store has closed!":"That's not a valid command.";if(c==
"count")try{s=P[c=I[1]];}catch{s="There is no "+c+" pie!";}if(c==
"buy"||c=="sell"){n=int.Parse(I[1]);n=c=="sell"?-n:n;try{n+=P[c=
I[2]];}catch{}s=P[c]=n;i=(n=c.Length)>i?n:i;}if(c=="list")foreach(
var p in P.Keys)C.Write("| {0,"+-i+"} | {1,11} |\n",p,P[p]);else C.
WriteLine(s);if(c!="exit")goto a;}}

insira a descrição da imagem aqui

Tomei alguma liberdade com a regra sobre a saída da lista. Para salvar alguns caracteres, eu codifiquei a largura da coluna de contagem para a largura máxima de um valor inteiro. (As regras não diziam que espaços extras não eram permitidos.)

Formatado:

using C = System.Console;
class Z
{
    static void Main()
    {
        var P = new System.Collections.Generic.Dictionary<string, int>();
        int i = 0, n;
    a:
        C.Write("> ");
        var I = C.ReadLine().Split(' ');
        var c = I[0];
        object s = c == "exit" ? "The pie store has closed!" 
                               : "That's not a valid command.";

        // allow Dictionary to throw exceptions; cheaper than using ContainsKey()
        if (c == "count")
            try { s = P[c = I[1]]; }
            catch { s = "There is no " + c + " pie!"; }

        if (c == "buy" || c == "sell")
        {
            n = int.Parse(I[1]);
            n = c == "sell" ? -n : n;

            try { n += P[c = I[2]]; }
            catch { }

            s = P[c] = n;
            i = (n = c.Length) > i ? n : i;
        }

        if (c == "list")
            foreach (var p in P.Keys) 
                C.Write("| {0," + -i + "} | {1,11} |\n", p, P[p]);
        else
            C.WriteLine(s);

        if (c != "exit") goto a; // goto is cheaper than a loop
    }
}
Igby Largeman
fonte
1
+1, estou surpreso que você possa obter uma contagem tão baixa de caracteres com uma linguagem tão detalhada: D
Maçaneta da porta
Meu objetivo com o Java é apenas vencer a implementação do C #. Haha Bom trabalho com este.
Asteri 26/08/2013
2

Python 3, 310

p={}
c=G=p.get
while c:
 l=("exit list buy count sell "+input("> ")).split();c=l.index(l[5]);*_,n=l
 if~-c%2*c:p[n]=(3-c)*int(l[6])+G(n,0)
 print(["The pie store has closed!","\n".join("| %*s | %9s |"%(max(map(len,p)),k,p[k])for k in p),G(n),G(n,"There is no %s pie!"%n),G(n),"That's not a valid command."][c])
Restabelecer Monica
fonte
1

Java - 772 751 739 713 666 619

Eu sei que não está ganhando o concurso, mas apenas por diversão!

import java.util.*;class a{static<T>void p(T p){System.out.print(p);}public static
 void main(String[]s){z:for(Map<String,Long>m=new HashMap();;){p("> ");s=new
 Scanner(System.in).nextLine().split(" ");switch(s[0]){case"list":for(Map.Entry 
e:m.entrySet())System.out.printf("|%12s|%6s|\n",e.getKey(),e.getValue());break;
case"count":p(m.get(s[1])!=null?m.get(s[1]):"There is no "+s[1]+" pie!\n");break;
case"buy":case"sell":long r=(s[0].length()==3?1:-1)*new Long(s[1])+(m.get(s[2])!=null?
m.get(s[2]):0);p(r+"\n");m.put(s[2],r);break;case"exit":p("The pie store has
 closed!");break z;default:p("That's not a valid command.\n");}}}}

Com quebras de linha e guias:

import java.util.*;

class a{

    static<T>void p(T p){
        System.out.print(p);
    }

    public static void main(String[]s){
        z:for(Map<String,Long>m=new HashMap();;){
            p("\n> ");
            s=new Scanner(System.in).nextLine().split(" ");
            switch(s[0]){
            case"list":
                for(Map.Entry e:m.entrySet())
                    System.out.printf("|%12s|%6s|\n",e.getKey(),e.getValue());
                break;
            case"count":
                p(m.get(s[1])!=null?m.get(s[1]):"There is no "+s[1]+" pie!");
                break;
            case"buy":
            case"sell":
                long r=(s[0].length()==3?1:-1)*new Long(s[1])+(m.get(s[2])!=null?m.get(s[2]):0);
                p(r);
                m.put(s[2],r);
                break;
            case"exit":
                p("The pie store has closed!");
                break z;
            default:
                p("That's not a valid command.");
            }
        }
    }

}
asteri
fonte
1
+1 para um idioma de golfe não tradicional :). Com o C #, descobri que a instrução switch é mais cara do que simples se {} for construída. Isso também deve ser verdade para Java.
Igby Largeman
@IgbyLargeman Sim, eu continuava tentando ficar if/elsemais barato, mas devido ao fato de que eu precisaria fazer s[0]=s[0].intern()para comparar ==, ele sempre acaba sendo mais . Eu sei, muito contra-intuitivo.
Asteri 26/08/2013