Home > Software design >  How can I simplify my python turtle game to avoid it from taking larger memory as the running time i
How can I simplify my python turtle game to avoid it from taking larger memory as the running time i

Time:04-26

This is a color-flipping game based on the python turtle module. The game is composed of a rectangular board divided into a number of flat colored tiles of various colors. The goal of the game is to turn all tiles to the same color by choosing one tile on the board and then changing its color to another color. The newly selected color will spread to all its neighboring tiles which match the original color of the chosen tile. The player continues selecting another tile and changing its color to another until all the tiles within the board flipped to the same color. In addition to the rectangular board, an array of colors is shown below the board. These are the colors to which the player can choose to flip the color of the selected tile.

As I started to run my game, the memory it took up was getting larger and larger as the running time increased. And it's getting slower and slower. I think it might be due to the while loop at the end of my code. But I'm not sure. How can I modify it to make it faster?

from turtle import *
from random import choice
from functools import partial

# set game dimension to be 5 x 5
g_dim = 5
# use random.choice() to create the color for the game
g_game = [choice(['#0000FF', '#FF0000', '#FFFF00', '#008000', '#00FFFF']) for i in range(25)]
# provide the option to flip during the game
optionColor = ['#0000FF', '#FF0000', '#FFFF00', '#008000', '#00FFFF']

# show a set of colors as option for user to flip
def promptColorToFlip(optionColor,  # a list that contains a set of the color for user to choose from
                    height=100,     # the height of the option tiles
                    width=100       # the width of the option tiles
                    ):
    # the coordinates of the first tiles
    x = -200
    y = -200

    for i in range(len(optionColor)):
        tile = prototype.clone()
        tile.goto(i * width   x, -(height 50)   y)
        tile.color('white', optionColor[i])
        tile.onclick(partial(returnChosenColor, i))

# return the index of the select-to-flip-to color in the optionColor list
def returnChosenColor(userChosenColor,  # the index of the select-to-flip-to color in the optionColor list
                        x, y            # take the positional arguments from the onclick() function to avoid errors, no significant meaning
                        ):
    global userOption
    userOption = userChosenColor

def refreshScreen(game, rows=5, columns=5, height=100, width=100):
    x = -200  
    y = -200

    for column in range(columns):
        for row in range(rows):
            square = prototype.clone()
            square.goto(column * (5 width)   x , row * (5 height)   y)
            square.onclick(partial(userChosenTile, row, column))
            if state['framed'] == row*5 column:
                square.color('black', game[row*5 column])
            else:
                square.color('white', game[row*5 column])
    update()

def userChosenTile(ROW, COL, x, y):
    global state, R, C
    state['framed'] = ROW*5 COL
    R = ROW
    C = COL

def flipColor(row, col, game, orig, to):
    print('excuted')
    global userOption, state, R, C
    if orig == to:
        return game
    if row < 0 or row >= g_dim:
        return
    if col < 0 or col >= g_dim:
        return

    idx = row*g_dim col   

    if game[idx] != orig:
        return
    print(idx, 'excuted')
    game[idx] = to
    flipColor(row-1, col, game, orig, to)
    flipColor(row 1, col, game, orig, to)
    flipColor(row, col-1, game, orig, to)
    flipColor(row, col 1, game, orig, to)
    
    state = {'framed':None}
    R = None
    C = None
    userOption = None

    return game

# initialize the game status
state = {'framed':None}     # stores the number of the last selected tile, which will be framed with a black border
R = None                    # the row of the last selected tile
C = None                    # the column of the last selected tile
userOption = None           # the index of the select-to-flip-to color in the optionColor list

# create a prototype of the tiles
prototype = Turtle()
prototype.shape('square')
prototype.shapesize(5, 5, 5)
prototype.penup()

# disable auto screen refresh
tracer(False)
# run the game
while True:
    # the try and except block here is to prevent error from raising when user terminate the progarm
    try:
        promptColorToFlip(optionColor)
        refreshScreen(g_game)
        if state['framed'] is not None and R is not None and C is not None and userOption is not None:
            g_game = flipColor(R, C, g_game, g_game[state['framed']], optionColor[userOption])
    except:
        pass

CodePudding user response:

I haven't fully worked through your somewhat complex code, but I'm pretty sure I see the source of your progressive slowdown as the game runs for a while. It's right here, in your refreshScreen function:

for column in range(columns):
    for row in range(rows):
        square = prototype.clone()
        ...

This code makes a new turtle for each square of your board on every frame. Those turtles never go away, so you just keep on stacking up more and more of them, which slows down the performance of the whole game over time. The solution is probably to use only one turtle for each location, and keep references to them so that you can change their colors when necessary, rather than making them anew each time.

  • Related