Code golf is good. Pie is good. When you put the two together, only good stuff can happen.


In this challenge you will manage a pie shop. The user will be able to input five different commands: list, count, buy, sell, and exit. Here are the specifications for each:

  • list

    • Print a list of all the pies owned, and how many. Separate with | and pad with a space on either side. |s must be aligned. Pie amount may be negative (that means you owe pie to someone :(). For example:

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

    • Print how many {{type}} pies there are. Print "There is no {{type}} pie!" if there is none. {{type}} will always match the regex \w+ (i.e, it will always be a single word). For example, if I had the amount of pies shown in the above example list, then

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

    • Add {{n}} to the count of {{type}} pie, and print it. Create {{type}} pie if it does not exist. {{n}} will always match the regex [0-9]+ (i.e, it will always be a number). Here's another example (with the same pie inventory as the previous examples):

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

    • Subtract {{n}} from the count of {{type}} pie, and print it. Create {{type}} pie if it does not exist. Pie can be negative (oh no, that would mean you owe someone pie!).

      > sell 15 blueberry
      > buy 5 blueberry
  • exit

    • Print "The pie store has closed!" and exit the program.

      > exit
      The pie store has closed!

Further clarifications

  • If a non-existing function is called (the first word), then print "That's not a valid command."
  • If an existing function is called with invalid arguments (the words after the first word), how your program behaves doesn't matter. "Invalid arguments" includes too many arguments, too little arguments, {{n}} not being a number, etc.
  • Pie is good.
  • Your input must be distinguished from your output. If you are running the program on the command line/terminal/shell/other text-based thing, you must prefix input with "> ​" (a "greater than" sign and a space) or some other shell input prefix thing.
  • Pie is good.
  • If all of these clarifications are not good enough, here's some sample output:

    > list
    > buy 10 apple
    > sell 10 blueberry
    > list
    | apple     | 10  |
    | blueberry | -10 |
    > count apple
    > count peach
    There is no peach pie!
    > exit
    The pie store has closed!
  • If you buy/sell pie and the net count becomes 0, you can either keep it in the list or not, and you can either return 0 or There is no {{type}} pie! when you count it.

  • This is ; shortest code wins.
  • Did I mention that pie is good?
  • 3
    \$\begingroup\$ So just to clarify... is pie good? \$\endgroup\$ Aug 22, 2013 at 5:19
  • 4
    \$\begingroup\$ Is it acceptable to keep a pie in the list with a count of zero? Like if you do buy 1 apple and sell 1 apple. And would it then be valid for count apple to return 0 instead of There is no apple pie!? \$\endgroup\$ Aug 22, 2013 at 11:39
  • \$\begingroup\$ @IgbyLargeman Darn it, I thought I clarified everything! :P Added new test case to additional clarifications \$\endgroup\$
    – Doorknob
    Aug 22, 2013 at 14:02
  • \$\begingroup\$ @Doorknob hey! I'm outputting "there is no apple pie" after the last one has been sold. \$\endgroup\$ Aug 22, 2013 at 14:16
  • \$\begingroup\$ @JanDvorak Alright, I suppose either way will work. Updated again \$\endgroup\$
    – Doorknob
    Aug 22, 2013 at 14:21

6 Answers 6


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

Some tricks here:

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

Doorknob's idea to use a formatter is taken a step further here, literally. First, the longest string in the hash among all keys and values is formatted using " %%%ds |" to produce a string like " %6s |". Yep, no shrinkwrapping each column separately. There was never the requirement to. One size fits all. Then this string is duplicated and used as a formatting string for the two-element array containing the current row. Finally, the + near the start gets its word and prepends a single leading pipe. Oh, and puts has a nice handling of arrays.

Ruby has interpolation in regex literals. It's a tight save, but it does save a little.

Ruby requires semicolons after the when expression, but not before the keyword. This leads to a weird rendering artifact when the semicolon is replaced with a newline.

And, of course, perlism known as magic globals and automatic matching of regex literals against them.

Also, most statements including case are expressions.

  • \$\begingroup\$ Very clever tricks! +1 \$\endgroup\$
    – Doorknob
    Aug 22, 2013 at 14:05
  • \$\begingroup\$ Hmm, but why Hash.new(0) instead of {}? \$\endgroup\$
    – Doorknob
    Aug 22, 2013 at 14:55
  • 1
    \$\begingroup\$ @Doorknob Ruby's hashes can have default values (if you pass an object) or even generators (if you pass a block (key, hash -> value). If you don't pass either, the default value is nil (which doesn't allow addition). The literal uses nil as the default value. \$\endgroup\$ Aug 22, 2013 at 15:58
  • \$\begingroup\$ Could save a few characters with h=Hash.new(0) => h=Hash.new 0, print"> " => $><<'> ', and I think [*h] can just be h. I tried putting together a version without the switch statement since all that boilerplate text really adds up: gist.github.com/chron/6315218. I was trying to make something work with ruby -ap but the requirement for the prompt makes it hard :< \$\endgroup\$ Aug 23, 2013 at 3:20
  • \$\begingroup\$ @chron thanks! Can't believe I missed the first one, and I'm not sure why I thought $><< printed a newline. As for the last suggestion... unfortunately, hashes don't have a "flatten" method. \$\endgroup\$ Aug 23, 2013 at 3:27

Ruby, 427 384 characters

alias x puts
print'> '
x'The pie store has closed!'
p.each{|k,v|printf"| %-#{p.keys.map(&:size).max}s | %-#{p.map{|e,a|a.to_s.size}.max}s |\n",k,v}
x p[t=u[1]]||"There is no #{t} pie!"
if p[t=u[2]]
x p[t]+=m
x p[t]=m
else x"That's not a valid command."

Thanks to Jan Dvorak of huge improvement from 427 to 384 (!)

  • \$\begingroup\$ You can use loop{...} instead of while 1do...end. \$\endgroup\$ Aug 22, 2013 at 5:27
  • \$\begingroup\$ You can use split without its argument. By default, it splits by whitespace (or $; if that is set) \$\endgroup\$ Aug 22, 2013 at 5:45
  • \$\begingroup\$ p.keys.group_by(&:size).max[0] -- are you looking for p.keys.map(&:size).max or p.map{|x,_|x.size}.max? Here: [(t=p.values).max.to_s.size,t.min.to_s.size].max are you looking for p.map{|_,x|x.to_s.size}.max? I'm gonna take your idea and abuse the formatter, though :-) \$\endgroup\$ Aug 22, 2013 at 5:52
  • \$\begingroup\$ p[t]=p[t]+m is equivalent to p[t]+=m (except p[t] is evaluated twice instead of once) and longer. Use the latter. \$\endgroup\$ Aug 22, 2013 at 5:58
  • \$\begingroup\$ @JanDvorak Oooh, thanks for all the tips :D I thought Ruby didn't have a += operator; that's why I didn't use it. Maybe that's just for ++. I will edit my post shortly \$\endgroup\$
    – Doorknob
    Aug 22, 2013 at 14:02

Python Pie-thon 437

I'm sure there is some slack on the second last line, but the requirement to align the bars for both the pie type and number is a doozy.

while 1:
 a=raw_input("> ").split();c=a.pop(0)
 if"exit"==c:print"The pie store has closed!";break
 if c in[C,"buy","sell"]:
  if c!=C:p[y]=p.get(y,0)+int(a[0])
  print p.get(y,"There is no %s pie!"%y)
  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."

As per Igby Largeman's comment the rules are unclear around what to do if there was a pie of a specific type, but there are 0 now. So I've interpreted it in my favour.

Sample output:

> buy 10 apple
> sell 1 blueberry
> buy 1 keylime
> sell 3 apple
> buy 5 blueberry
> list
| keylime   | 1 |
| apple     | 7 |
| blueberry | 4 |
> sell 1 keylime
> count keylime
  • \$\begingroup\$ Sorry, but in this one > count potato produces That's not a valid command. instead of There is no potato pie! \$\endgroup\$
    – Doorknob
    Aug 22, 2013 at 14:06
  • \$\begingroup\$ @Doorknob Are you running it in IDLE? \$\endgroup\$
    – user8777
    Aug 22, 2013 at 23:12
  • \$\begingroup\$ Yes. I'll try in a file \$\endgroup\$
    – Doorknob
    Aug 22, 2013 at 23:15
  • \$\begingroup\$ Actually, count doesn't seem to be working at all. Actually it works sometimes but sometimes it doesn't. It's very odd... \$\endgroup\$
    – Doorknob
    Aug 22, 2013 at 23:17
  • 3
    \$\begingroup\$ Hehe, I knew it was a naming clash of some kind :P +1 Oh and also, my file for your program had an amusing name: pie.py :P \$\endgroup\$
    – Doorknob
    Aug 23, 2013 at 0:49

C# - 571 568 559

Bringing up the rear as usual with the hopelessly verbose 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==
var p in P.Keys)C.Write("| {0,"+-i+"} | {1,11} |\n",p,P[p]);else C.
WriteLine(s);if(c!="exit")goto a;}}

enter image description here

I took some liberty with the rule about list output. To save some characters I hardcoded the width of the count column to the maximum width of an integer value. (The rules didn't say extra spaces weren't allowed.)


using C = System.Console;
class Z
    static void Main()
        var P = new System.Collections.Generic.Dictionary<string, int>();
        int i = 0, n;
        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]);

        if (c != "exit") goto a; // goto is cheaper than a loop
  • 1
    \$\begingroup\$ +1, I'm surprised that you can get such a low character count with such a verbose language :D \$\endgroup\$
    – Doorknob
    Aug 23, 2013 at 14:14
  • \$\begingroup\$ My goal with the Java is only to beat the C# implementation. Haha. Nice job with this one. \$\endgroup\$
    – asteri
    Aug 26, 2013 at 1:31

Java - 772 751 739 713 666 619

I know it's not winning the contest, but just for fun!

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

With line breaks and tabs:

import java.util.*;

class a{

    static<T>void p(T p){

    public static void main(String[]s){
        z:for(Map<String,Long>m=new HashMap();;){
            p("\n> ");
            s=new Scanner(System.in).nextLine().split(" ");
                for(Map.Entry e:m.entrySet())
                p(m.get(s[1])!=null?m.get(s[1]):"There is no "+s[1]+" pie!");
                long r=(s[0].length()==3?1:-1)*new Long(s[1])+(m.get(s[2])!=null?m.get(s[2]):0);
                p("The pie store has closed!");
                break z;
                p("That's not a valid command.");

  • 1
    \$\begingroup\$ +1 for a non-traditional golfing language :). With C# I found that the switch statement is more expensive than simple if{} constructs. This should be true for Java too. \$\endgroup\$ Aug 26, 2013 at 2:28
  • \$\begingroup\$ @IgbyLargeman Yeah, I kept trying to get if/else to be less expensive, but due to the fact that I'd have to do s[0]=s[0].intern() in order to compare with ==, it always ends up being more. I know, very counterintuitive. \$\endgroup\$
    – asteri
    Aug 26, 2013 at 2:29

Python 3, 310

while c:
 l=("exit list buy count sell "+input("> ")).split();c=l.index(l[5]);*_,n=l
 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])

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.