8
\$\begingroup\$

I am currently in a challenge with my buddy to see who can code a simple paint program in the least lines. The only requirement, is that the program must include an eraser. How can I possibly shorten this code, while still using proper, beautiful syntax?

import sys, pygame
from pygame.locals import *
pygame.init() #Starts pygame
screen = pygame.display.set_mode((1000,720)) #window, and sets the size
screen.fill((255,255,255)) # Fills background color
brush = pygame.image.load("brush.jpg") #Loads the image into a variable
eraser = pygame.image.load("white.png") #Loads the image into a variable
brush = pygame.transform.scale(brush, (10,10)) #Scales the image into a more useable  
eraser = pygame.transform.scale(eraser, (100,100)) #Scales the image into a more 
clock = pygame.time.Clock() #Makes a clock to track the ticks within the game
z = 0
while True:
    clock.tick(60) #Limits the ticks to 60 (FPS)
    x,y = pygame.mouse.get_pos() #Sets two variables for the mouse position
    for event in pygame.event.get(): #Recieves events
        if event.type == QUIT: #Checks if the event is a QUIT event
            pygame.quit()  ##Quits##                
            sys.exit()     ##Quits##              
        elif event.type == MOUSEBUTTONDOWN:
            z = 1 #If you press the mouse button down, it sets the screen blit to true
        elif event.type == MOUSEBUTTONUP:
            z = z - 1 #Does the opposite of the above elif statement
        if z == 1: #Cheks if the variable z is true, if it is; updates the screen with the brush
            screen.blit(brush,(x-5,y-5))
        if event.type == KEYDOWN:
            screen.blit(eraser,(x-5,y-5))

    pygame.display.update()
| improve this question | | | | |
\$\endgroup\$
  • \$\begingroup\$ The indentation seems to have gone wrong. Can you fix, please? \$\endgroup\$ – Gareth Rees Jan 3 '14 at 13:11
  • \$\begingroup\$ I honestly dont know how? It always messes it up when I post on stack overflow \$\endgroup\$ – Ungifted Jan 3 '14 at 13:35
  • \$\begingroup\$ CodeReviews is not about 'CodeGolfing', and this question is off-topic: 4. Do I want the code to be good code, (i.e. not code-golfing, obfuscation, or similar) in the help center pages \$\endgroup\$ – rolfl Jan 3 '14 at 13:43
  • 3
    \$\begingroup\$ This question appears to be off-topic because it is about making the code as compact as possible (fewest lines) \$\endgroup\$ – rolfl Jan 3 '14 at 13:44
  • 6
    \$\begingroup\$ @rolfl: OP wants to shorten the code "while still using proper, beautiful syntax". So I think there is something here for Code Review. Ungifted: I fixed the indentation for you. \$\endgroup\$ – Gareth Rees Jan 3 '14 at 14:28
12
\$\begingroup\$

Here's my best effort (8 lines):

from pygame import *
init()
screen = display.set_mode((1000,720))
for e in iter(event.wait, event.Event(QUIT)):
    col = {(1, 0, 0): 'white', (0, 0, 1): 'black'}.get(mouse.get_pressed())
    if col and e.type in (MOUSEBUTTONDOWN, MOUSEMOTION):
        display.update(screen.fill(Color(col), Rect(mouse.get_pos(), (20, 20))))
quit()

Notes:

  1. from module import * is normally deprecated because you don't know all the names you're importing, and some of these might conflict with or shadow names from other modules. But in simple cases like this, with no other dependencies, it's justified because it results in code that's easy to read. You can always go through and change X to pygame.X if you want.

  2. In this program there's nothing that animates, so there's no need for a clock, and the display only needs to be updated when it changes.

  3. You didn't post your images brush.jpg and white.png so I've used solid colour rectangles. (Also, why a JPEG? JPEGs are lossy, so not appropriate for bitmap graphics.)

  4. By changing the program to draw white-on-black I can avoid the initial screen.fill and save a line.

  5. I've used colour names 'white' and 'black' which are clearer than RGB tuples like (255, 255, 255).

  6. I've used the two-argument form of iter to avoid the test for event.type == QUIT. (This feature is useful when you want to exit an iteration on a special value.)

  7. By using event.wait instead of event.get I can reduce the two loops to one.

  8. I've changed the user interface so that the left mouse button draws and the right mouse button erases. This is done by looking up the tuple returned by mouse.get_pressed in a dictionary, to get the colour for the fill.

  9. Surface.fill returns the rectangle that was filled, which is exactly the part of the display that needs to be updated, so I can pass it directly to display.update.

| improve this answer | | | | |
\$\endgroup\$
  • \$\begingroup\$ That's kind of an amazing factorization ! oO I'm really impressed by that one. \$\endgroup\$ – Depado Jan 6 '14 at 15:05
0
\$\begingroup\$

I didn't really try to understand much but I reckon this does the same thing as your code :

import sys, pygame
from pygame.locals import *

pygame.init() 
screen = pygame.display.set_mode((1000,720)) 
screen.fill((255,255,255)) 
brush = pygame.transform.scale(pygame.image.load("brush.jpg"), (10,10)) 
eraser = pygame.transform.scale(pygame.image.load("white.png"), (100,100)) 
clock = pygame.time.Clock() 
z = False
while True:
    clock.tick(60)
    x,y = pygame.mouse.get_pos()
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit() 
        if event.type in [MOUSEBUTTONDOWN, MOUSEBUTTONUP]:
            z = (event.type==MOUSEBUTTONDOWN)
        if z:
            screen.blit(brush,(x-5,y-5))
        if event.type == KEYDOWN:
                screen.blit(eraser,(x-5,y-5))
    pygame.display.update()

Hilights :

  • You don't need that many comments. Comments should explain why, not how.
  • You can use the boolean type instead of playing with integers.
| improve this answer | | | | |
\$\endgroup\$

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.