Help with saving and restoring program state

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Jacob H

    #1

    Help with saving and restoring program state

    Hello list...

    I'm developing an adventure game in Python (which of course is lots of
    fun). One of the features is the ability to save games and restore the
    saves later. I'm using the pickle module to implement this. Capturing
    current program state and neatly replacing it later is proving to be
    trickier than I first imagined, so I'm here to ask for a little
    direction from wiser minds than mine!

    When my program initializes, each game object is stored in two places
    -- the defining module, and in a list in another module. The following
    example is not from my actual code, but what happens is the same.

    (code contained in "globalstat e" module)
    all_fruit = []

    (code contained in "world" module)
    class Apple(object): # the class hierarchy goes back to object, anyway
    def __init__(self):
    self.foo = 23
    self.bar = "something"
    globalstate.all _fruit.append(s elf)
    apple = Apple()

    I enjoy the convenience of being able to refer to the same apple
    instance through world.apple or globalstate.all _fruit, the latter
    coming into play when I write for loops and so on. When I update the
    instance attributes in one place, the changes are reflected in the
    other place. But now comes the save and restore game functions, which
    again are simplified from my real code:

    (code contained in "saveload" module)
    import pickle
    import world
    def savegame(path_t o_name):
    world_data = {}
    for attr, value in world.__dict__. items():
    # actual code is selective about which attributes
    # from world it takes -- I'm just keeping this
    # example simple
    world_data[attr] = value
    fp = open(path_to_na me, "w")
    pickle.dump(wor ld_data, fp)
    fp.close()

    def loadgame(path_t o_name):
    fp = open(path_to_na me, "r")
    world_data = pickle.load(fp)
    for attr, value in world_data.item s():
    setattr(world, attr, value)
    fp.close()

    The problem is that the game objects only get overwritten in the world
    module. The instances in the globalstate.all _fruit list remain
    unchanged, which is not the behaviour I want. I started to write code
    to get around this. I figured that with each loadgame call, I could
    reset all the lists in globalstate to empty, then reappend each game
    object to the appropriate list. But this possibility got complicated
    fast, because all game objects belong to more than one list. My apple
    instance alone would belong to globalstate.all _things,
    globalstate.all _fruit, globalstate.all _items, and perhaps others. Some
    of the game objects contained in these lists don't need to be a part
    of capturing program state in the first place! But I'm stuck, because
    unpickling (so far as I understand it) creates a brand new instance
    that doesn't know it used to have references to itself in the
    globalstate lists.

    Any advice out there? I'm looking for a clean, elegant way to
    overwrite the same class instance in two arbitrary places at once.
    Perhaps the example code I've provided isn't even the best way of
    saving and restoring program state. Perhaps I can easily update my
    globalstate lists and I'm just overlooking the simple way. Or perhaps
    the solution lies in abandoning the concepts of referencing my game
    objects through module attributes and lists. I'm open to any
    suggestions.

    Thanks in advance for any help!

    Jacob
  • Larry Bates

    #2
    Re: Help with saving and restoring program state

    Take a look at Zope. The ZODB is a highly optimized object
    database that handles the pickling, loading, saving, etc. of
    Python objects for restoring program state. A ZODB beginner's
    tutorial is available here:



    Other info at:




    Hope information helps.

    Larry Bates


    Jacob H wrote:[color=blue]
    > Hello list...
    >
    > I'm developing an adventure game in Python (which of course is lots of
    > fun). One of the features is the ability to save games and restore the
    > saves later. I'm using the pickle module to implement this. Capturing
    > current program state and neatly replacing it later is proving to be
    > trickier than I first imagined, so I'm here to ask for a little
    > direction from wiser minds than mine!
    >
    > When my program initializes, each game object is stored in two places
    > -- the defining module, and in a list in another module. The following
    > example is not from my actual code, but what happens is the same.
    >
    > (code contained in "globalstat e" module)
    > all_fruit = []
    >
    > (code contained in "world" module)
    > class Apple(object): # the class hierarchy goes back to object, anyway
    > def __init__(self):
    > self.foo = 23
    > self.bar = "something"
    > globalstate.all _fruit.append(s elf)
    > apple = Apple()
    >
    > I enjoy the convenience of being able to refer to the same apple
    > instance through world.apple or globalstate.all _fruit, the latter
    > coming into play when I write for loops and so on. When I update the
    > instance attributes in one place, the changes are reflected in the
    > other place. But now comes the save and restore game functions, which
    > again are simplified from my real code:
    >
    > (code contained in "saveload" module)
    > import pickle
    > import world
    > def savegame(path_t o_name):
    > world_data = {}
    > for attr, value in world.__dict__. items():
    > # actual code is selective about which attributes
    > # from world it takes -- I'm just keeping this
    > # example simple
    > world_data[attr] = value
    > fp = open(path_to_na me, "w")
    > pickle.dump(wor ld_data, fp)
    > fp.close()
    >
    > def loadgame(path_t o_name):
    > fp = open(path_to_na me, "r")
    > world_data = pickle.load(fp)
    > for attr, value in world_data.item s():
    > setattr(world, attr, value)
    > fp.close()
    >
    > The problem is that the game objects only get overwritten in the world
    > module. The instances in the globalstate.all _fruit list remain
    > unchanged, which is not the behaviour I want. I started to write code
    > to get around this. I figured that with each loadgame call, I could
    > reset all the lists in globalstate to empty, then reappend each game
    > object to the appropriate list. But this possibility got complicated
    > fast, because all game objects belong to more than one list. My apple
    > instance alone would belong to globalstate.all _things,
    > globalstate.all _fruit, globalstate.all _items, and perhaps others. Some
    > of the game objects contained in these lists don't need to be a part
    > of capturing program state in the first place! But I'm stuck, because
    > unpickling (so far as I understand it) creates a brand new instance
    > that doesn't know it used to have references to itself in the
    > globalstate lists.
    >
    > Any advice out there? I'm looking for a clean, elegant way to
    > overwrite the same class instance in two arbitrary places at once.
    > Perhaps the example code I've provided isn't even the best way of
    > saving and restoring program state. Perhaps I can easily update my
    > globalstate lists and I'm just overlooking the simple way. Or perhaps
    > the solution lies in abandoning the concepts of referencing my game
    > objects through module attributes and lists. I'm open to any
    > suggestions.
    >
    > Thanks in advance for any help!
    >
    > Jacob[/color]

    Comment

    • Terry Reedy

      #3
      Re: Help with saving and restoring program state


      "Jacob H" <jacobsmail@pos tmark.net> wrote in message
      news:85b54e91.0 501241556.d281f 90@posting.goog le.com...[color=blue]
      > I'm developing an adventure game in Python[/color]

      Since you are not the first, have you looked at what others have done to
      save/restore? The Pygame site has code you can look at for adventure (I
      believe) and other game types (I know).

      Terry J. Reedy



      Comment

      • Kent Johnson

        #4
        Re: Help with saving and restoring program state

        Jacob H wrote:[color=blue]
        > Hello list...
        >
        > I'm developing an adventure game in Python (which of course is lots of
        > fun). One of the features is the ability to save games and restore the
        > saves later. I'm using the pickle module to implement this. Capturing
        > current program state and neatly replacing it later is proving to be
        > trickier than I first imagined, so I'm here to ask for a little
        > direction from wiser minds than mine!
        >
        > When my program initializes, each game object is stored in two places
        > -- the defining module, and in a list in another module. The following
        > example is not from my actual code, but what happens is the same.
        >
        > (code contained in "globalstat e" module)
        > all_fruit = []
        >
        > (code contained in "world" module)
        > class Apple(object): # the class hierarchy goes back to object, anyway
        > def __init__(self):
        > self.foo = 23
        > self.bar = "something"
        > globalstate.all _fruit.append(s elf)
        > apple = Apple()
        >
        > I enjoy the convenience of being able to refer to the same apple
        > instance through world.apple or globalstate.all _fruit, the latter
        > coming into play when I write for loops and so on. When I update the
        > instance attributes in one place, the changes are reflected in the
        > other place. But now comes the save and restore game functions, which
        > again are simplified from my real code:[/color]

        My understanding of pickle is that it will correctly handle shared references in the saved data. So
        if you pack all your global dicts into one list and pickle that list, you will get what you want.
        See code changes below:
        [color=blue]
        >
        > (code contained in "saveload" module)
        > import pickle
        > import world[/color]
        import globalstate[color=blue]
        > def savegame(path_t o_name):
        > world_data = {}
        > for attr, value in world.__dict__. items():
        > # actual code is selective about which attributes
        > # from world it takes -- I'm just keeping this
        > # example simple
        > world_data[attr] = value[/color]
        the_whole_sheba ng = [ world_data, globalstate.all _fruit, globalstate.all _items ][color=blue]
        > fp = open(path_to_na me, "w")[/color]
        pickle.dump(the _whole_shebang, fp)[color=blue]
        > fp.close()
        >
        > def loadgame(path_t o_name):
        > fp = open(path_to_na me, "r")[/color]
        the_whole_sheba ng = pickle.load(fp)
        world_data, globalstate.all _fruit, globalstate.all _items = the_whole_sheba ng[color=blue]
        > for attr, value in world_data.item s():
        > setattr(world, attr, value)
        > fp.close()[/color]

        Kent

        Comment

        • M.E.Farmer

          #5
          Re: Help with saving and restoring program state

          Jacob H wrote:[color=blue]
          > Hello list...
          >
          > I'm developing an adventure game in Python (which of course is lots[/color]
          of[color=blue]
          > fun).[/color]

          I am glad you are having fun ,
          after all life is so short,
          isn't that what it is all about ;)
          [color=blue]
          > One of the features is the ability to save games and restore the
          > saves later. I'm using the pickle module to implement this. Capturing
          > current program state and neatly replacing it later is proving to be
          > trickier than I first imagined, so I'm here to ask for a little
          > direction from wiser minds than mine!
          >
          > When my program initializes, each game object is stored in two places
          > -- the defining module, and in a list in another module. The[/color]
          following[color=blue]
          > example is not from my actual code, but what happens is the same.
          >
          > (code contained in "globalstat e" module)
          > all_fruit = []
          >
          > (code contained in "world" module)
          > class Apple(object): # the class hierarchy goes back to object,[/color]
          anyway[color=blue]
          > def __init__(self):
          > self.foo = 23
          > self.bar = "something"
          > globalstate.all _fruit.append(s elf)
          > apple = Apple()[/color]
          [snip]
          Ok here is a guess. (I recently did something similar, maybe this will
          help)
          If you already knew about this stuff then just ignore me :)

          You have defined a class for your objects, which is a nifty
          'container'.
          The apple class can also keep track of the total amount of apple
          instances handed out.
          Sometimes it is better to let the objects handle there own state.
          Py> class Apple(object):
          .... total = 0 # this is a 'class variable' shared by all instances

          .... def __init__(self):
          .... self.__class__. total += 1
          .... self.foo = 23 # this is an 'instance variable/name'
          .... self.bar = "something"
          .... apple = Apple()
          .... apple_two = Apple()
          .... print apple_two.total
          .... 2
          .... apple_three = Apple()
          .... print apple.total
          .... 3
          .... print apple_three.tot al
          .... 3
          Now you can just pickle them and when you unpickle them as usual.

          Also another idea is to use a class instead of a global.
          I'll admit it I have a personal distaste for them, but classes work so
          well I never miss them.

          Py>class Store(object):
          .... pass

          Now just create an instance and add your attributes.
          Py>store = Store()
          ....store.color = 'red'
          ....store.heigh t = 5.7
          ....store.secre t = 42
          And get them back when needed.
          Py>self.SetHieg ht(store.hieght )

          Hth
          M.E.Farmer

          Comment

          Working...