I’m attempting to make a 2048 game that will run as a widget. The game does work, however it will crash if run in the widget. I can also get it to work by removing any of my colour changing code, however I wish to avoid this. To my (untrained) eye, when looking in the object inspector, the vast majority of variables appear to be UI variables. Therefore, I'm wondering if there is any way to drastically trim the included data attributes and methods. Also, I have tried to modify my code to reduce memory usage but any further suggestions are welcome.
from random import randint
from console import alert
from appex import set_widget_view
import ui
"""These variables need to be global"""
score = 0 #what it says
moves = 0
fails = set() #needs to be global despite only being in one module to exist between calls
failed = False #Records whether a move was sucessful and therefore whether to add randoms
playGrid = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] #The current grid
tileUI = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] #The corresponding text fields
def printGrid():
"""Outputs the current grid onto the UI, along with score, and number of moves"""
for y in range(4):
for x in range(4):
tile = screen["tile" + str(y) + str(x)]
#Reset normal font colour and size
tile.text_color = "#000000"
tile.font = ("<system-bold>", 50)
if playGrid[y][x] != 0: #Write non-zeros to grid pos
tile.text = str(playGrid[y][x])
#Set colours
if playGrid[y][x] == 2:
tile.background_color = "#fbffaa"
elif playGrid[y][x] == 4:
tile.background_color = "#fff1aa"
elif playGrid[y][x] == 8:
tile.background_color = "#ffb86a"
elif playGrid[y][x] == 16:
tile.background_color = "#ff703e"
elif playGrid[y][x] == 32:
tile.background_color = "#ff4f4f"
elif playGrid[y][x] == 64:
tile.background_color = "#f20000"
elif playGrid[y][x] == 128:
tile.background_color = "#edf800"
elif playGrid[y][x] == 256:
tile.background_color = "#7cff61"
elif playGrid[y][x] == 512:
tile.background_color = "#00f315"
elif playGrid[y][x] == 1024:
tile.background_color = "#23ffe2"
elif playGrid[y][x] == 2048:
tile.background_color = "#47b7ff"
elif playGrid[y][x] == 4096:
tile.background_color = "#0b20ff"
tile.text_color = "#ffffff"
elif playGrid[y][x] == 8192:
tile.background_color = "#9400db"
tile.text_color = "#ffffff"
else:
tile.background_color = "#000000"
tile.text_color = "#ffffff"
tile.font = ("<system-bold>", 42)
else:
tile.text = "" #Zeros shown as blank
tile.background_color = "#ffffff"
del tile
screen["scoreLabel"].text = "Score: " + str(score)
screen["movesLabel"].text = "Moves: " + str(moves)
def generateNewNumbers():
"""Places a random 2 or 4 onto a random grid position"""
randomXLocation = randint(0, 3) #Generate random coordinates
randomYLocation = randint(0, 3)
while playGrid[randomYLocation][randomXLocation] != 0: #Keep doing it till the location is empty
randomXLocation = randint(0, 3)
randomYLocation = randint(0, 3)
playGrid[randomYLocation][randomXLocation] = randint(1, 2) * 2 #Set that location to 2 or 4
del randomXLocation, randomYLocation
def moveTilesDirection(direction):
"""Moves the tiles in playGrid in a specified direction.
Usage: moveTilesDirection(direction)
0 is up, 1 is right, 2 is down, 3 is left
"""
#failed, fails and moves need to be global, playgrid is a list and does not
global failed
global fails
global moves
def combineTiles():
"""Combines current tile with previous tile, and add non-zero values to a stack"""
#score must be global
global score
#Non-Local needed to ensure that values are retrived and modified correctly
nonlocal Ycord
nonlocal Xcord
nonlocal lastTile
nonlocal tileStack
if playGrid[Ycord][Xcord] > 0: #First check there is a value here
if lastTile == playGrid[Ycord][Xcord]: #If the same as last, combine
tileStack.pop() #Remove the last value from stack
tileStack.append(lastTile * 2) #and add combined
score += lastTile * 2 #Add to score
lastTile = -1 #And reset to prevent double combines
else: #If not the same as last
lastTile = playGrid[Ycord][Xcord] #update last tile
tileStack.append(lastTile) #and add to row stack
#empty the save of previous grid and update to current (surface copy)
previousPlayGrid = [playGrid[i][:] for i in range(4)]
#check for directions
if direction == 0:
for Xcord in range(4): #for each row/column
tileStack = [] #reset the stack and last tile
lastTile = -1
for Ycord in range(4): #step through row/column
combineTiles() #with combine tiles
while len(tileStack) < 4: #append as many 0's as needed
tileStack.append(0)
for i, tile in enumerate(tileStack): #write to column
playGrid[i][Xcord] = tile
elif direction == 2:
for Xcord in range(4):
tileStack = []
lastTile = -1
for Ycord in range(3, -1, -1):
combineTiles()
tileStack.reverse() #reverse the complete stack
while len(tileStack) < 4:
tileStack.insert(0, 0) #need to put 0's at start so have to insert at beginning
for i, tile in enumerate(tileStack):
playGrid[i][Xcord] = tile
elif direction == 1:
for Ycord in range(4):
tileStack = []
lastTile = -1
for Xcord in range(3, -1, -1):
combineTiles()
tileStack.reverse()
while len(tileStack) < 4:
tileStack.insert(0, 0)
playGrid[Ycord] = tileStack #easier to write to rows
elif direction == 3:
for Ycord in range(4):
tileStack = []
lastTile = -1
for Xcord in range(4):
combineTiles()
while len(tileStack) < 4:
tileStack.append(0)
playGrid[Ycord] = tileStack
#Check this was a valid move
if previousPlayGrid == playGrid: #if nothing moved
fails.add(direction) #add this direction to failed set (set ensures no duplicates)
if len(fails) == 4: #if all 4 directions tried, you lost
alert("YOU LOST!")
else: #if not retry without adding random tiles or printing
failed = True
else: #if the moved worked, reset fail counters
fails = set()
failed = False
moves += 1
"""UI SETUP"""
def upButton(sender):
moveTilesDirection(0)
if failed == False:
generateNewNumbers()
printGrid()
def rightButton(sender):
moveTilesDirection(1)
if failed == False:
generateNewNumbers()
printGrid()
def downButton(sender):
moveTilesDirection(2)
if failed == False:
generateNewNumbers()
printGrid()
def leftButton(sender):
moveTilesDirection(3)
if failed == False:
generateNewNumbers()
printGrid()
#finally do something (load the view)
screen = ui.load_view('ScreenWidget')
set_widget_view(screen)
#generate starting numbers and print to screen
generateNewNumbers()
printGrid()