Zarządzaj sklepem z ciastkami!

12

Podsumowanie

Kod golfa jest dobry. Ciasto jest dobre . Po połączeniu tych dwóch rzeczy mogą się zdarzyć tylko dobre rzeczy.

Dane techniczne

W tym wyzwaniu będziesz zarządzać sklepem z ciastkami. Użytkownik będzie mógł wprowadzić pięć różnych poleceń: list, count, buy, sell, i exit. Oto specyfikacje dla każdego:

  • list

    • Wydrukuj listę wszystkich posiadanych ciast i ich liczby. Oddziel |i pad z odstępem po obu stronach. |s musi być wyrównany. Ilość ciasta może być ujemna (to znaczy, że jesteś komuś winien ciasto :(). Na przykład:

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

    • Wydrukuj, ile jest {{type}}ciast. Drukuj „Nie ma {{type}}ciasta!” jeśli nie ma. {{type}}zawsze będzie pasować do wyrażenia regularnego \w+(tzn. zawsze będzie to jedno słowo). Na przykład, gdybym miał liczbę ciast pokazanych na powyższej przykładowej liście, wtedy

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

    • Dodaj {{n}}do liczby {{type}}ciast i wydrukuj ją. Utwórz {{type}}ciasto, jeśli nie istnieje. {{n}}zawsze będzie pasować do wyrażenia regularnego [0-9]+(tzn. zawsze będzie liczbą). Oto inny przykład (z takim samym zapasem ciasta jak w poprzednich przykładach):

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

    • Odejmij {{n}}od liczby {{type}}ciast i wydrukuj ją. Utwórz {{type}}ciasto, jeśli nie istnieje. Ciasto może być ujemne (o nie, to znaczy, że jesteś winien komuś ciasto!).

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

    • Drukuj „Sklep z ciastami został zamknięty!” i wyjdź z programu.

      > exit
      The pie store has closed!
      

Dalsze wyjaśnienia

  • Jeśli wywoływana jest nieistniejąca funkcja (pierwsze słowo), wydrukuj „To nie jest poprawne polecenie”.
  • Jeśli wywoływana jest istniejąca funkcja z niepoprawnymi argumentami (słowa po pierwszym słowie), zachowanie programu nie ma znaczenia. „Nieprawidłowe argumenty” obejmują zbyt wiele argumentów, zbyt mało argumentów, {{n}}nie będący liczbą itp.
  • Ciasto jest dobre.
  • Twój wkład musi być odróżniony od twoich wyników. Jeśli uruchamiasz program w wierszu poleceń / terminalu / powłoce / innej rzeczy opartej na tekście, musisz poprzedzić wejście > ​"znakiem „ (znak„ większy niż ”i spacją) lub inną rzeczą przedrostkową.
  • Ciasto jest dobre.
  • Jeśli wszystkie te wyjaśnienia nie są wystarczająco dobre, oto kilka przykładowych wyników:

    > 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!
    
  • W przypadku zakupu / sprzedaży ciasto i hrabia netto staje się 0, można też przechowywać go w list, czy nie, i można albo powrócić 0lub There is no {{type}} pie!kiedy countgo.

  • To jest ; najkrótszy kod wygrywa.
  • Czy wspomniałem, że ciasto jest dobre?
Klamka
źródło
3
Żeby wyjaśnić ... czy ciasto jest dobre?
Igby Largeman
4
Czy dopuszczalne jest utrzymywanie ciasta na liście z liczbą zero? Jak jeśli buy 1 applei sell 1 apple. I czy w takim przypadku uzasadnione count applebyłoby zwrócenie 0zamiast There is no apple pie!?
Igby Largeman
@IgbyLargeman Cholera, myślałem, że wszystko wyjaśniłem! : P Dodano nowy przypadek testowy do dodatkowych wyjaśnień
Klamka
@Doorknob hej! Wysyłam komunikat „nie ma szarlotki” po sprzedaży ostatniego.
John Dvorak,
@JanDvorak W porządku, chyba obie strony będą działać. Zaktualizowany ponownie
Klamka

Odpowiedzi:

3

Rubin, 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}

Kilka sztuczek tutaj:

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

Pomysł Doorknob na użycie formatera został dosłownie o krok dalej. Po pierwsze, najdłuższy ciąg w haszu spośród wszystkich kluczy i wartości jest formatowany przy użyciu " %%%ds |"takiego łańcucha " %6s |". Tak, nie zawijaj kurczowo każdej kolumny osobno. Nigdy nie było takiego wymogu. Jeden rozmiar dla wszystkich. Następnie ciąg ten jest duplikowany i używany jako ciąg formatujący dla tablicy dwuelementowej zawierającej bieżący wiersz. Wreszcie, +blisko początku zaczyna się słowo i przygotowuje pojedynczą rurkę prowadzącą. Aha, i putsma niezłą obsługę tablic.

Ruby interpoluje literały regularne. To napięty zapis, ale trochę oszczędza.

Ruby wymaga średnika po whenwyrażeniu, ale nie przed słowem kluczowym. Prowadzi to do dziwnego artefaktu renderowania, gdy średnik jest zastępowany nową linią.

I, oczywiście, perlizm znany jako magiczne globale i automatyczne dopasowywanie literałów regularnych przeciwko nim.

Ponadto większość instrukcji, w tym casewyrażenia, są wyrażeniami.

John Dvorak
źródło
Bardzo sprytne sztuczki! +1
Klamka
Hmm, ale dlaczego Hash.new(0)zamiast {}?
Klamka
1
@Doorknob Skróty Ruby mogą mieć wartości domyślne (jeśli przekazujesz obiekt) lub nawet generatory (jeśli przekazujesz blok (klucz, skrót -> wartość). Jeśli nie przejdziesz, domyślną wartością jest nil(która nie zezwalaj na dodawanie). Dosłownie używa niljako wartości domyślnej
John Dvorak
Można zapisać kilka znaków za pomocą h=Hash.new(0)=> h=Hash.new 0, print"> "=> $><<'> 'i myślę, że [*h]tak właśnie jest h. Próbowałem skompletować wersję bez instrukcji switch, ponieważ cały ten tekst na tablicy naprawdę się sumuje: gist.github.com/chron/6315218 . Próbowałem zmusić coś do pracy, ruby -apale wymóg szybkiego pytania utrudnia: <
Paul Prestidge
@chron dzięki! Nie mogę uwierzyć, że przegapiłem pierwszy i nie jestem pewien, dlaczego myślałem, że $><<wydrukowałem nowy wiersz. Jeśli chodzi o ostatnią sugestię ... niestety skróty nie mają metody „spłaszczania”.
John Dvorak,
3

Rubin, 427 384 znaków

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}

Dzięki Janowi Dvorakowi ogromnej poprawy z 427 do 384 (!)

Klamka
źródło
Możesz użyć loop{...}zamiast while 1do...end.
John Dvorak,
Możesz używać splitbez jego argumentu. Domyślnie dzieli się według białych znaków (lub $;jeśli jest ustawiony)
John Dvorak
p.keys.group_by(&:size).max[0]- szukasz p.keys.map(&:size).maxczy p.map{|x,_|x.size}.max? Tutaj: [(t=p.values).max.to_s.size,t.min.to_s.size].maxszukasz p.map{|_,x|x.to_s.size}.max? Wezmę twój pomysł i nadużywam formatyzatora :-)
John Dvorak
p[t]=p[t]+mjest równoważne p[t]+=m(z wyjątkiem p[t]jest oceniane dwukrotnie zamiast raz) i dłużej. Użyj tego drugiego.
John Dvorak,
@JanDvorak Oooh, dzięki za wszystkie wskazówki: DI myślałem, że Ruby nie ma +=operatora; dlatego go nie użyłem. Może to tylko dla ++. Niedługo będę edytować swój post
Klamka
3

Pyton Ciasto - thon 437

Jestem pewien, że w drugim ostatnim wierszu jest trochę luzu, ale wymóg wyrównania słupków zarówno dla rodzaju ciasta, jak i liczby jest doozy.

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."

Zgodnie z komentarzem Igby Largeman za przepisy są niejasne wokół tego, co zrobić, jeśli nie było ciasto typu konkretnego, ale istnieje 0teraz. Zinterpretowałem to na swoją korzyść.

Przykładowe dane wyjściowe:

> 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

źródło
Przepraszamy, ale w tym > count potatoprodukuje That's not a valid command.zamiastThere is no potato pie!
Klamka
@Doorknob Czy używasz go w IDLE?
Tak. Spróbuję w pliku
Klamka
W rzeczywistości liczenie wcale nie działa . Właściwie to czasem działa, ale czasem nie. To bardzo dziwne ...
Klamka
3
Hehe, wiedziałem, że to jakiś konflikt nazewnictwa: P +1 Och, a także, mój plik dla twojego programu miał zabawną nazwę pie.py:: P
Klamka
3

C # - 571 568 559

Jak zwykle podnosząc tył z beznadziejnie pełnym C #.

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

wprowadź opis zdjęcia tutaj

Przyjąłem trochę wolności, stosując regułę dotyczącą wyświetlania list. Aby zapisać niektóre znaki, zakodowałem na stałe szerokość kolumny zliczania do maksymalnej szerokości wartości całkowitej. (Reguły nie mówiły, że dodatkowe spacje są niedozwolone).

Sformatowany:

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
źródło
1
+1, jestem zaskoczony, że możesz uzyskać tak niską liczbę znaków przy takim pełnym języku: D
Klamka
Moim celem w Javie jest tylko pokonanie implementacji C #. Ha ha. Dobra robota z tym.
asteri
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])
Przywróć Monikę
źródło
1

Java - 772 751 739 713 666 619

Wiem, że nie wygrywa konkursu, ale dla zabawy!

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

Z podziałami i tabulatorami:

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
źródło
1
+1 za nietradycyjny język golfa :). W języku C # stwierdziłem, że instrukcja switch jest droższa niż prosta, jeśli konstruuje {}. To powinno być prawdą również w Javie.
Igby Largeman
@IgbyLargeman Tak, ciągle próbowałem if/elsebyć tańszy, ale z powodu tego, że musiałbym to zrobić s[0]=s[0].intern(), aby porównać ==, zawsze kończyło się to na więcej . Wiem, bardzo sprzeczne z intuicją.
asteri