Python Forum
Gui slot machine-out of memory error
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Gui slot machine-out of memory error
#1
Python V3.72
Windows 7\Linux Mint 19.1

A game I am working on called Freespin Frenzy
crashes after a while with either an "out of memory"
message in the shell, or a "Python has stopped working" pop up,
this is in Windows 7.

The memory is getting eaten up fast by a bad piece of my code that
"spins" the reels, it doesn't actually spin them,
it just flashes all the symbols on top of each other for a short while.

I am sure I am approaching this all wrong, but this is the best
I can do at my current ability level.

Please look at this piece of the code below and see if you can advise me
on how to load in and use the graphics in a way that will
not use up RAM in about 30 mins of play, (I have 8gig ram).

You can get the full source code here if you want:
https://stevepython.wordpress.com/2020/0...-79-update

The game is still a work in progress and I hope to make it look a lot
better in future updates, but I have to get this fixed first really.

Regards, Steve.

def spin_reels():
    """Pseudo spin,pretty poor, but best I can do for now."""

    spinner = ['FH', 'FD', 'FC',
               'WH', 'WD', 'WC',
               'JH', 'JD', 'JC', 'JS',
               'QH', 'QD', 'QC', 'QS',
               'KH', 'KD', 'KC', 'KS',
               'AH', 'AD', 'AC', 'AS',
               'BH', 'BD', 'BC']

    r_one = Label(cards_frame)
    r_two = Label(cards_frame)
    r_three = Label(cards_frame)

    Glo.hold_btn1.configure(state=DISABLED)
    Glo.hold_btn2.configure(state=DISABLED)
    Glo.hold_btn3.configure(state=DISABLED)

    for spins in range(4):

        for spinr in range(18):
            rnd_symb1 = randrange(len(spinner))
            symb1 = spinner[rnd_symb1]+'.png'

            rnd_symb2 = randrange(len(spinner))
            symb2 = spinner[rnd_symb2]+'.png'

            rnd_symb3 = randrange(len(spinner))
            symb3 = spinner[rnd_symb3]+'.png'

            if spins < 1 and not Glo.btn1_is_held:
                r_one = Label(cards_frame)
                PHOTO = PhotoImage(file='cards/gfx/'+str(symb1))
                r_one.config(image=PHOTO)
                r_one.grid(row=0, column=1, padx=2, pady=2)
                r_one.photo = PHOTO
                r_one.update()

            if spins == 1 and not Glo.btn1_is_held:
                card_lbl_one = Label(cards_frame)
                PHOTO = PhotoImage(file='cards/gfx/'+str(Glo.reel_one))
                card_lbl_one.config(image=PHOTO)
                card_lbl_one.grid(row=0, column=1, padx=2, pady=2)
                card_lbl_one.photo = PHOTO
                r_one.update()

            if spins < 2 and not Glo.btn2_is_held:
                r_two = Label(cards_frame)
                PHOTO = PhotoImage(file='cards/gfx/'+str(symb2))
                r_two.config(image=PHOTO)
                r_two.grid(row=0, column=2, padx=2, pady=2)
                r_two.photo = PHOTO
                r_two.update()

            if spins == 2 and not Glo.btn2_is_held:
                card_lbl_two = Label(cards_frame)
                PHOTO = PhotoImage(file='cards/gfx/'+str(Glo.reel_two))
                card_lbl_two.config(image=PHOTO)
                card_lbl_two.grid(row=0, column=2, padx=2, pady=2)
                card_lbl_two.photo = PHOTO
                r_two.update()

            if spins < 3 and not Glo.btn3_is_held:
                r_three = Label(cards_frame)
                PHOTO = PhotoImage(file='cards/gfx/'+str(symb3))
                r_three.config(image=PHOTO)
                r_three.grid(row=0, column=3, padx=2, pady=2)
                r_three.photo = PHOTO
                r_three.update()

            if spins == 3 and not Glo.btn3_is_held:
                spins = 99
                card_lbl_three = Label(cards_frame)
                PHOTO = PhotoImage(file='cards/gfx/'+str(Glo.reel_three))
                card_lbl_three.config(image=PHOTO)
                card_lbl_three.grid(row=0, column=3, padx=2, pady=2)
                card_lbl_three.photo = PHOTO
                r_three.update()

            time.sleep(0.025)
            r_one.destroy()
            r_two.destroy()
            r_three.destroy()

    rnd_hold()
    check_for_win()
    save_bank()
Reply
#2
It could be because of each time spin reels is called new labels are created instead of creating them once and updating what they display in this function.
Reply
#3
I'm destroying the labels on each new iteration, I think, unless I have the indenting wrong?
I'll nip off and experiment, thanks.

returned:
on moving the
time.sleep(0.025)
r_one.destroy()
r_two.destroy()
r_three.destroy()
back 4 spaces, doesn't make much difference to memory usage.
Moving back another 4 spaces uses more than double the memory I was previously using up.

I think it is more to do with loading in the files a new each iteration
instead of pre-loading them and then using the image object, though
I have no idea how to do that.


(May-17-2020, 01:49 PM)Yoriz Wrote: It could be because of each time spin reels is called new labels are created instead of creating them once and updating what they display in this function.
Reply
#4
There are new labels created both outside and inside of the for loop

Create the labels once outside of the spin function

Update the existing labels in the spin function

delete them separately when they are no longer required or they can be deleted by destroying their parent.

At the moment labels are being piled up on top of each other using up memory.
Reply
#5
Okay thanks for the guidance I will give it a try.
Reply
#6
Destroying the labels does nothing to the images. The images remain as long as their reference count is > 0. Since you keep reusing PHOTO I would expect all of your labels to display the same card. Maybe they would if set all the images first and then updated.

I do not know exactly when unreferenced objects are deleted in Python, but you are defeating it somehow.

Pre-allocating the images is easy. Easier than what you are doing now.
def make_images():
    spinner = ['FH', 'FD', 'FC',
               'WH', 'WD', 'WC',
               'JH', 'JD', 'JC', 'JS',
               'QH', 'QD', 'QC', 'QS',
               'KH', 'KD', 'KC', 'KS',
               'AH', 'AD', 'AC', 'AS',
               'BH', 'BD', 'BC']
    images = []
    for name in spinner:
        images.append(PhotoImage(file='cards/gfx/'+name+'.png')
    return images
Reply
#7
Thank you for your reply deanhystad.

I tried your bit of code, but it doesn't seem to return a
the filenames as I would of expected, eg. pyimage1, pyimage2 etc.
instead of:
cards/gfx/FH.png
cards/gfx/FD.png
etc.

I ran the code separately to test this to make sure:
from tkinter import Tk, PhotoImage
root = Tk()

spinner = ['FH', 'FD', 'FC',
           'WH', 'WD', 'WC',
           'JH', 'JD', 'JC', 'JS',
           'QH', 'QD', 'QC', 'QS',
           'KH', 'KD', 'KC', 'KS',
           'AH', 'AD', 'AC', 'AS',
           'BH', 'BD', 'BC']
images = []
for name in spinner:
    images.append(PhotoImage(file='cards/gfx/'+name+'.png'))
    print(name)

print(images[0])
output:
FH
FD
FC
WH
WD
WC
JH
JD
JC
JS
QH
QD
QC
QS
KH
KD
KC
KS
AH
AD
AC
AS
BH
BD
BC
pyimage1




(May-17-2020, 06:09 PM)deanhystad Wrote: Destroying the labels does nothing to the images. The images remain as long as their reference count is > 0. Since you keep reusing PHOTO I would expect all of your labels to display the same card. Maybe they would if set all the images first and then updated.

I do not know exactly when unreferenced objects are deleted in Python, but you are defeating it somehow.

Pre-allocating the images is easy. Easier than what you are doing now.
def make_images():
    spinner = ['FH', 'FD', 'FC',
               'WH', 'WD', 'WC',
               'JH', 'JD', 'JC', 'JS',
               'QH', 'QD', 'QC', 'QS',
               'KH', 'KD', 'KC', 'KS',
               'AH', 'AD', 'AC', 'AS',
               'BH', 'BD', 'BC']
    images = []
    for name in spinner:
        images.append(PhotoImage(file='cards/gfx/'+name+'.png')
    return images
Reply
#8
You are printing out the name python is using to reference the image. Since the program does not provide an attribute name these are being generated automatically. It doesn't matter what they are called because you would reference images using an index into the images array.

If you would rather refer to the images using names like 'FW' or 'BC', the images could be placed in a dictionary.
from tkinter import Tk, PhotoImage
root = Tk()
 
spinner = ['FH', 'FD', 'FC',
           'WH', 'WD', 'WC',
           'JH', 'JD', 'JC', 'JS',
           'QH', 'QD', 'QC', 'QS',
           'KH', 'KD', 'KC', 'KS',
           'AH', 'AD', 'AC', 'AS',
           'BH', 'BD', 'BC']
images = {}
for name in spinner:
    images[name] = PhotoImage(file='cards/gfx/'+name+'.png')
 
print(images['BH'])
I notice a similar preference for individual variables is shown in your use of r_one, r_two, r_three and hold_btn1, hold_btn2, etc... Your slot machine has 3 reels and 3 hold buttons. Your code should have variables like reel_labels[] and hold_buttons[] and reel_pos[]. Other than where it appears in the window is there any difference between r_one and r_three? By treating the buttons and the reels generically, the amount of code will decrease and will be easier to understad

By using individual variables you make your code much more complicated. For example, I think the spin reel code could be reduced to something like this:
def spin_reels():
    """Spin the reels"""
    for _ in range(18):
        for i in range(len(reel_labels)):
            if not hold[i]: # Don't spin a held reel
                reel[i] = randrange(len(spinner_images)):
                reel_label[i].config(image=spinner_images[reel[i]])
        time.sleep(0.025)
I don't understand how the game plays with 4 spins and hold buttons so this could be completely wrong. This spin_reels randomly spins the three reels 18 times and remembers the last image in reel[]. If reel[0] = 3, the image displayed is WH.png. If there are multiple spins you would call the function multiple times. To lock a wheel you set hold[I] = True.
Reply
#9
You are totally right, I have confused my code and myself with badly named variables.
The reason for the 4 and 18 etc is to spin reel3 longer than reel 2 andreel2 a bit longer than reel 1,
if you see what I mean.
-----------------------
By the way:
"spinr" represents the 19 symbols of the reels
(should be 25 now I have added more symbols)

r_one is a temp variable for duration of spin.
I tried changing all the r_one to use the same label as
card_lbl_one but it produces errors in the reel display, the
card ends up as a face-down card that I use as a blank.
so r_one etc are necessary at the moment.
------------------
All will be clear if you want to download and run the game,
link in my original post.

I will experiment with your shortened code, thank you for that,
if I can't get that to work I may have to scrap the whole function and
re-write it from scratch.

Thanks for your time.

I made a gif of the reels "spinning" so you
can see what I mean.
[Image: YhHn6VDT]
Reply
#10
That info helps a lot.
def spin_reels():
    """Spin the reels"""
    for i in range(3):
        # Spin reel on X times, two 2X times, three 3X times
        for _ in range(18):
            for j in range(len(reel_labels)):
                # Don't spin a held reel.
                if not hold[j] and j >= i:
                    reel[j] = randrange(len(spinner_images)):
                    reel_label[i].config(image=spinner_images[reel[i]])
            time.sleep(0.025)
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Help For Slot Machine Code Rayaan 1 1,204 Mar-30-2020, 05:01 AM
Last Post: SheeppOSU
  Memory consumption grows during execution only on single machine Jendker 2 731 Feb-10-2020, 01:57 PM
Last Post: Jendker
  Go around memory error Pytonormen 1 791 Oct-19-2019, 04:31 PM
Last Post: Gribouillis
  memory error using permutation list of 11 elements kikidog 1 1,612 Sep-10-2019, 08:22 PM
Last Post: ichabod801
  machine learning error (using jupyter) calonia 1 2,493 Jun-26-2019, 05:16 PM
Last Post: ThomasL
  Fix Memory Error while installing a library for Qgis alexastorga 0 1,535 Apr-13-2018, 04:54 PM
Last Post: alexastorga
  Dictionaries and memory error. jarrod0987 5 3,228 Feb-23-2018, 12:15 PM
Last Post: buran

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020