1

I am making a 2048 game in python and I am using def functions to execute a certain chunk of my code whenever I want to. But I've run into a problem while trying to generate the random numbers that spawn at the start of the game and whenever you make a move. RecursionError: maximum recursion depth exceeded in comparison. I have no idea what this means and how it happened. This is a chunk of the code simplified:

def game():
if not 'n' in locals():
        random_n()

#Generating 2/4s
def random_n():
    num = randint(0,100)
    global tile_number, n
    if num > 10:
        tile_number = 2
    else:
        tile_number = 4
    
    if not 'n' in locals():
        n = 0
        random_n()
    game()

while True:
    events = pygame.event.get()
    for event in events:

    #WASD (only really the end matters(i'm just showing I have a loop at the bottom))
        if event.type == pygame.KEYDOWN:
            def keybinds():
                if event.key == pygame.K_w:
                    print("Pressed W")
                elif event.key == pygame.K_a:
                    print("Pressed A")
                elif event.key == pygame.K_s:
                    print("Pressed S")
                elif event.key == pygame.K_d:
                    print("Pressed D")
    
                #ARROWS
                elif event.key == pygame.K_UP:
                    print("Pressed UP")
                elif event.key == pygame.K_LEFT:
                    print("Pressed LEFT")
                elif event.key == pygame.K_DOWN:
                    print("Pressed DOWN")
                elif event.key == pygame.K_RIGHT:
                    print("Pressed RIGHT")
                else:
                    keybinds()
                random_n()
                
            keybinds()

This is not my actual code but a simplified version to get rid of things that I don't think affect the error, but if that is not true, here is my real code:

import pygame
from random import randint

#Initialising PyGame
pygame.init()
 
#Creating Display
w = 640
h = 780
screen = pygame.display.set_mode((w,h))

#PyGame window name and icon
pygame.display.set_caption('2048')
icon = pygame.image.load('2048 icon.png')
pygame.display.set_icon(icon)

#Variables
background_c = 236, 231, 217
font_c = 147, 121, 97
button_c = font_c
menu_restart_background_c = button_c
game_background_c = 191, 173, 155
score_background_c = game_background_c
font1 = pygame.font.Font('calibri font sv\Calibri Bold.TTF', 30)
font2 = pygame.font.Font('calibri font sv\Calibri Bold.TTF', 80)
font3 = pygame.font.Font('calibri font sv\Calibri Bold.TTF', 60)
game_slots_c = 208, 193, 176
number_text_c = {"2+4_c": (123, 110, 98), "above4_c": (255,255,255)}
#number_background_c = {"2": (238, 228, 218), "4": (237, 224, 199), "8": (242, 177, 122), "16": (245, 149, 99),
#"32": (255, 116, 85), "64": (, , ), "128": (, , ), "256": (, , ), "512": (255, 255, 255),
#"1024": (255, 255, 255), "2048": (255, 255, 255)}
play = 0

#Menu
def menu():
    #Colours + Rectangles
    screen.fill((249, 248, 236))
    pygame.draw.rect(screen, background_c,(0,0, w, h/10))
    #Title Text
    title = font1.render("2048", True, font_c)
    screen.blit(title, (35, 25)) 
    pygame.display.flip()

    #Button
    pygame.draw.rect(screen, button_c, (49, 349, 536, 100), 0, 12)
    #Button Text
    pbutton_f = font2.render("Play", True, (255,255,255))
    screen.blit(pbutton_f,(240, 360))
    pygame.display.update()
menu()

#Game
def game():
    i = 114
    #Game board
    screen.fill(background_c)
    game_board = pygame.Surface((536, 536))
    game_board.fill((background_c))
    pygame.draw.rect(game_board, game_background_c,(0,0, 536, 536),0,12)
    #Game slots
    while i <= 2064:
        if i <= 504:
            pygame.draw.rect(game_board, game_slots_c,((16+i)-114, 16, 114, 114),0,6)
        elif i <= 1024:
            pygame.draw.rect(game_board, game_slots_c,((16+i)-634, 146, 114, 114),0,6)
        elif i <= 1544:
            pygame.draw.rect(game_board, game_slots_c,((16+i)-1154, 276, 114, 114),0,6)
        else:
            pygame.draw.rect(game_board, game_slots_c,((16+i)-1674, 406, 114, 114),0,6)
        i += 130
    screen.blit(game_board,(49, 200))
    #Menu, Restart, Scores
    pygame.draw.rect(screen, menu_restart_background_c,(49, 25, 200, 70),0,7)
    pygame.draw.rect(screen, menu_restart_background_c,(49, 110, 200, 70),0,7)
    pygame.draw.rect(screen, score_background_c,(284, 25, 138, 155),0,7)
    pygame.draw.rect(screen, score_background_c,(437, 25, 138, 155),0,7)
    mbutton_f = font3.render("Menu", True , (255,255,255))
    screen.blit(mbutton_f, (75, 32))
    rbutton_f = font3.render("Restart", True , (255,255,255))
    screen.blit(rbutton_f, (58, 118))
    if not 'n' in locals():
        random_n()

#Generating 2/4s
def random_n():
    num = randint(0,100)
    global tile_number, n
    if num > 10:
        tile_number = 2
    else:
        tile_number = 4
    
    if not 'n' in locals():
        n = 0
        random_n()
    game()

    pygame.display.update()


#Loop
while True:
    events = pygame.event.get()
    for event in events:

        #Button functions
        if event.type == pygame.MOUSEBUTTONDOWN:
            xy = pygame.mouse.get_pos()
            if play == 0:
                if 49 <= xy[0] <= 536:
                    if 349 <= xy[1] <= 449:
                        game()
                        play = 1

            if play == 1:
                if 49 <= xy[0] <= 249:
                    if 25 <= xy[1] <= 95:
                        menu()
                        play = 0
                    if 110 <= xy[1] <= 180:
                        game()

        #Making the "X" button work
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()

        #WASD
        if event.type == pygame.KEYDOWN:
            def keybinds():
                if event.key == pygame.K_w:
                    print("Pressed W")
                elif event.key == pygame.K_a:
                    print("Pressed A")
                elif event.key == pygame.K_s:
                    print("Pressed S")
                elif event.key == pygame.K_d:
                    print("Pressed D")
    
                #ARROWS
                elif event.key == pygame.K_UP:
                    print("Pressed UP")
                elif event.key == pygame.K_LEFT:
                    print("Pressed LEFT")
                elif event.key == pygame.K_DOWN:
                    print("Pressed DOWN")
                elif event.key == pygame.K_RIGHT:
                    print("Pressed RIGHT")
                else:
                    keybinds()
                random_n()
                
            keybinds()
shoewis
  • 45
  • 4
  • That error means a recursive function called itself, which called itself, which called itself.... over and over and over. – John Gordon Jul 06 '22 at 00:33
  • `if not 'n' in locals():` How do you expect there to ever be a local variable named `n`? You explicitly said `n` is global. – John Gordon Jul 06 '22 at 00:34
  • @JohnGordon What would be a solution? – shoewis Jul 06 '22 at 00:37
  • Python has a maximum recursion depth, which means it allows a recursive function to call itself only so many times without returning. The reason for this is that recursive calls that deep have one of 3 issues: 1) there's a far more efficient way to perform the operation iteratively, 2) the problem will explode eponentially and never finish anyway and 3) the algorithm has entered a loop and will never terminate. The practical reason is that every recursive call incurs some overhead and there's a limit to the amount of space reserved for the overhead of recursive calls. A loop is most likely. – Grismar Jul 06 '22 at 00:37
  • In your case, you check `if not 'n' in locals():` and in that case, you call the function again. Which will check the same thing again, call itself again, check it again, etc. ad infinitum - a loop. – Grismar Jul 06 '22 at 00:39
  • What is the purpose of `random_n()` being recursive anyway? – John Gordon Jul 06 '22 at 00:39
  • I think OP wants to generate random numbers until some condition is met, but there's several serious issues with the implementation. – Grismar Jul 06 '22 at 00:40
  • I fixed it by checking if n is in globals. I am new to coding and I didn't know the difference. – shoewis Jul 06 '22 at 00:46

0 Answers0