Question: I based the code below on this article: http://kevman3d.blogspot.com/2015/07/basic-games-in-python-1982-would-be.html and on the ZX BASIC in this image:   10 LET P=0 20 LET T=P 30 FOR Z=1 T0 10 35 CLS 37 PRINT AT 12,0;T 40 LET R=INT (RND*17) 50 FOR Y=0 TO 10 60 PRINT AT Y,R;"O" 70 LET N=P(INKEY$="4")-(INKEY$="1") 80 IF N<0 OR N>15 THEN LET N=P 100 PRINT AT 11,P;" ";AT 11,N;"┗┛";AT Y,R;" " 110 LET P=N 120 NEXT Y 130 LET T=T+(P=R OR P+1=R) 150 NEXT Z 160 PRINT AT 12,0;"YOU SCORED ";T;"/10" 170 PAUSE 4E4 180 RUN  I also shared it on Code Review Stack Exchange, and got a very helpful response refactoring it into high quality Python code complete with type hints. However, for my purposes I'm wanting to keep the level of knowledge required to make this work a little less advanced, including avoiding the use of OOP. I basically want to maintain the "spirit of ZX BASIC" but make the code "not awful." The use of functions is fine, as we were allowed GOSUB back in the day. I'm pretty dubious about the approach of using nested FOR loops inside the main game loop to make the game work, but at the same time I'm curious to see how well the BASIC paradigm maps onto the more event driven approach of Pygame, so I'd welcome any comments on the pros and cons of this approach. More specifically,  Is there somewhere I can put the exit code if event.type == pygame.QUIT where it will work during game rounds, without having to repeat the code elsewhere?  How would this game be implemented if I were to avoid the use of FOR loops / nested FOR loops?  Are there any points of best practice for pygame/Python which I have violated?  What improvements can you suggest, bearing in mind my purpose is to write good Pygame code while maintaining the "spirit" of the ZX81 games?   Any input much appreciated. I'm also curious to see a full listing implementing some of the ideas arising from my initial attempt if anyone is willing to provide one. import pygame import random import sys # Define colors and other global constants BLACK = (0, 0, 0) WHITE = (255, 255, 255) TEXT_SIZE = 16 SCREEN_SIZE = (16 * TEXT_SIZE, 13 * TEXT_SIZE) NUM_ROUNDS = 5 def print_at_pos(row_num, col_num, item): """Blits text to row, col position.""" screen.blit(item, (col_num * TEXT_SIZE, row_num * TEXT_SIZE)) # Set up stuff pygame.init() screen = pygame.display.set_mode(SCREEN_SIZE) pygame.display.set_caption("Dropout") game_font = pygame.font.SysFont('consolas', TEXT_SIZE) # Create clock to manage how fast the screen updates clock = pygame.time.Clock() # initialize some game variables player_pos, new_player_pos, coin_row, score = 0, 0, 0, 0 # -------- Main Program Loop ----------- while True: score = 0 # Each value of i represents 1 round for i in range(NUM_ROUNDS): coin_col = random.randint(0, 15) # Each value of j represents one step in the coin's fall for j in range(11): pygame.event.get() pressed = pygame.key.get_pressed() if pressed[pygame.K_RIGHT]: new_player_pos = player_pos + 1 elif pressed[pygame.K_LEFT]: new_player_pos = player_pos - 1 if new_player_pos < 0 or new_player_pos > 15: new_player_pos = player_pos # --- Game logic player_pos = new_player_pos coin_row = j if player_pos + 1 == coin_col and j == 10: score += 1 # --- Drawing code # First clear screen screen.fill(WHITE) player_icon = game_font.render("|__|", True, BLACK, WHITE) print_at_pos(10, new_player_pos, player_icon) coin_text = game_font.render("O", True, BLACK, WHITE) print_at_pos(coin_row, coin_col, coin_text) score_text = game_font.render(f"SCORE: {score}", True, BLACK, WHITE) print_at_pos(12, 0, score_text) # --- Update the screen. pygame.display.flip() # --- Limit to 6 frames/sec maximum. Adjust to taste. clock.tick(8) msg_text = game_font.render("PRESS ANY KEY TO PLAY AGAIN", True, BLACK, WHITE) print_at_pos(5, 0, msg_text) pygame.display.flip() waiting = True while waiting: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit(0) if event.type == pygame.KEYDOWN: waiting = False 

Answer: Here's my reorganisation of your code: import pygame import random # Define global constants TEXT_SIZE = 16 SCREEN_SIZE = (16 * TEXT_SIZE, 13 * TEXT_SIZE) NUM_ROUNDS = 5 def print_at_pos(row_num, col_num, item): """Blits text to row, col position.""" screen.blit(item, (col_num * TEXT_SIZE, row_num * TEXT_SIZE)) # Set up stuff pygame.init() screen = pygame.display.set_mode(SCREEN_SIZE) pygame.display.set_caption("Dropout") game_font = pygame.font.SysFont("consolas", TEXT_SIZE) # Create clock to manage how fast the screen updates clock = pygame.time.Clock() # draw the images player_icon = game_font.render("|__|", True, "black", "white") # if we don't specify a background color, it'll be transparent coin_text = game_font.render("O", True, "black") msg_text = game_font.render("PRESS ANY KEY TO PLAY AGAIN", True, "black", "white") # initialize some game variables waiting = False # start in game player_pos = 0 score = 0 game_round = 0 coin_row = 0 coin_col = random.randint(0, 15) running = True # For program exit # -------- Main Program Loop ----------- while running: # event handling for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.KEYDOWN: if waiting: waiting = False score = 0 # reset score elif event.key == pygame.K_LEFT: player_pos -= 1 elif event.key == pygame.K_RIGHT: player_pos += 1 # --- Game logic if waiting: # don't update the game state or redraw screen print_at_pos(5, 0, msg_text) else: coin_row += 1 # TODO: decouple from frame rate if -1 > player_pos: player_pos = -1 # so we can catch a coin at zero elif 15 < player_pos: player_pos = 15 # coin is in scoring position if coin_row == 10: if player_pos + 1 == coin_col: score += 1 elif coin_row > 10: # round is over coin_col = random.randint(0, 15) coin_row = 0 game_round+= 1 if game_round >= NUM_ROUNDS: waiting = True game_round = 0 # reset round counter # --- Drawing code screen.fill("white") # clear screen print_at_pos(10, player_pos, player_icon) print_at_pos(coin_row, coin_col, coin_text) score_text = game_font.render(f"SCORE: {score}", True, "black", "white") print_at_pos(12, 0, score_text) # --- Update the screen. pygame.display.flip() # --- Limit to 6 frames/sec maximum. Adjust to taste. clock.tick(6) pygame.quit()  I've used a boolean waiting to allow for common event and game state handling that only moves during gameplay. For more complex interactions, you'll want a state machine. The coin movement is currently coupled to the frame rate, which is easy, but ideally you'd specify a rate/time interval, e.g. 200ms between row drops and then you could have a refresh rate similar to the monitor refresh rate.