9
\$\begingroup\$

Note: This isn't as much a golfing challenge; it is more so asking for golfing suggestions.

Recently I had a Python assignment for my web development class, in order to check whether we could code. Since I already feel comfortable in Python, I decided to try and golf it, and I was wondering if people could point out things that I missed.

I already know that there are extra spaces in some places, but I'm more interested in conceptual things, like using while r: when r is a variable, and then waiting for it to "run out"!

The assignment

import random
from collections import Counter
s=l=''
c=['yellow','blue','white','green','Black', 'purple', 'silver', 'cyan', 'magenta', 'red']
n=[10,15,1,10,6,15,10,25,1,12,5,10,4,6,5,12,0,10,1,1]
o=i=0
for y in c:l+=y[0]*(random.randint(n[o],n[o+1]));o+=2
l=list(l)              
print("Welcome to the CIMS Gumball Machine Simulator\nYou are starting with the following gumballs:")
for b in c:print(str(l.count(b[0])) + " "+b);random.shuffle(l)
print("Here are your random purchases:")
while 'r' in l:
    random.shuffle(l); r=l.pop(); s+=r
    for j in c:
        if j[0] == r:print(j.capitalize())
print("You purchased %i gumballs, for a total of $%.2f \nMost common gumball(s):" % (len(s),len(s)*25/100))
a=Counter(s).most_common()
m=[x[1] for x in a]
while m[0] == m[i]:
    for j in c:
        if j[0] == a[i][0]:print(j.capitalize(), end=" ")
if(i<(len(m)-1)):i+=1
else:break

Also: I'm sorry if this isn't an appropriate question for the code golf page, since it is not a challenge and will remove it on request.

\$\endgroup\$
  • \$\begingroup\$ Putting the issue of on-topic-ness aside (since I'm not sure), perhaps take a look at the Python golf tips page? Also, which Python version? (I'm assuming 3 due to the parens around print, but just to check) \$\endgroup\$ – Sp3000 Feb 24 '15 at 4:15
  • 5
    \$\begingroup\$ Have you attempted to golf it yet? \$\endgroup\$ – feersum Feb 24 '15 at 4:18
  • 2
    \$\begingroup\$ This code has a lot of simple golf improvements remaining. I think you'd learn better if you reviewed the golf tips and looked at other Python golfs, and did more to shorten it your code on your own. Then, if you post what you get, people can give more insightful advice. \$\endgroup\$ – xnor Feb 24 '15 at 6:40
20
\$\begingroup\$

Here's a whole bunch of micro-optimisations you can do:

Use .split() to create a long list (-17 bytes):

c=['yellow','blue','white','green','Black', 'purple', 'silver', 'cyan', 'magenta', 'red']
c='yellow blue white green Black purple silver cyan magenta red'.split()

Remove extraneous brackets (-2 bytes):

l+=y[0]*(random.randint(n[o],n[o+1]))
l+=y[0]*random.randint(n[o],n[o+1])

Use splat (-2 bytes):

random.randint(n[o],n[o+1])
random.randint(*n[o:o+2])

Use extended iterable unpacking to turn something into a list (-4 bytes):

l=list(l)
*l,=l

Import all the things (-15 bytes):

import random;random.randint;random.shuffle;random.shuffle
from random import*;randint;shuffle;shuffle

Use other functions that can do the same job here (-5 * 2 = -10 bytes):

j.capitalize()
j.title()

print separates by space by default (-11 bytes):

print(str(l.count(b[0])) + " "+b)
print(l.count(b[0]),b)

More unpacking (-3 bytes):

r=l.pop()
*l,r=l

Abuse side-effects (-1 byte, plus indents):

if j[0]==r:print(j.capitalize())
r!=j[0]or print(j.capitalize())

Anything reused and over 5 chars might be worth saving as a variable (-1 byte):

len(s);len(s)
L=len(s);L;L

Simplify fractions (-5 bytes):

len(s)*25/100
len(s)/4

Unary abuse (-4 bytes):

if(i<(len(m)-1)):i+=1
if~-len(m)>i:i+=1

Or the biggest one of all...

Look at your algorithm, and see if it needs changing altogether

from random import*
*s,P,S=print,shuffle
P("Welcome to the CIMS Gumball Machine Simulator\nYou are starting with the following gumballs:")
*l,c,C='yellow blue white green Black purple silver cyan magenta red'.split(),s.count
for x,y,z in zip(c,[10,1,6,10,1,5,4,5,0,1],[15,10,15,25,12,10,6,12,10,1]):n=randint(y,z);l+=[x]*n;P(n,x)
S(l)
P("Here are your random purchases:")
while'red'in l:S(l);*l,r=l;s+=r,;P(r.title())
L=len(s)
P("You purchased %i gumballs, for a total of $%.2f\nMost common gumball(s):"%(L,L/4))
for x in c:C(x)!=max(map(C,c))or P(x.title())

(If you ever find yourself importing Counter in a code-golf, you're probably doing something very wrong...)

\$\endgroup\$
  • \$\begingroup\$ Wow!! This is exactly what I was looking for. Thanks so much for your help! \$\endgroup\$ – aks. Feb 24 '15 at 5:53
  • \$\begingroup\$ You could probably obviate the need for .title() by precapitalizing everything. Also, assign s.count to a variable. \$\endgroup\$ – isaacg Feb 24 '15 at 5:57
  • \$\begingroup\$ @isaacg I thought I'd try to keep the functionality of the original program. If the spec was all that counted, I'd drop a few of the long print statements since technically the assignment doesn't need them ;) \$\endgroup\$ – Sp3000 Feb 24 '15 at 5:58
  • \$\begingroup\$ @Sp3000 In that case, why not put the .title() on the initial string? Saves one .title() use. \$\endgroup\$ – isaacg Feb 24 '15 at 5:59
  • \$\begingroup\$ @isaacg Also, I did it by picking out of an array of each of the starting letters, and 'b' represented blue and 'B' represented black \$\endgroup\$ – aks. Feb 24 '15 at 6:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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