HiveBrain v1.2.0
Get Started
← Back to all entries
snippetpythonModerate

How can I shorten this paint program?

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
thiscanshortenprogramhowpaint

Problem

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()

Solution

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:

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

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

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

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

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

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

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

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

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

Code Snippets

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()

Context

StackExchange Code Review Q#38494, answer score: 12

Revisions (0)

No revisions yet.