Need ideas and insights on a project...

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • true911m
    New Member
    • Dec 2006
    • 92

    Need ideas and insights on a project...

    I would like to solicit your thoughts and ideas (code can come later) about how you would approach a project idea I just tossed together. I chose this as a testbed for me to play with objects, specifically multiple instances of a few specific objects, and as I thought about it, it raised a lot of questions about how to manage, contain, signal all of those objects that do almost the same thing at the same time.

    I want to build an OO bingo simulator. While it is not necessarily the most efficient approach, let's academically assume it needs to be object-oriented.

    We have 75 ball objects, which can be picked randomly by a machine, and which therefore need an awareness of being picked(), since no ball can come up twice in a game.

    We have a scorecard grid with 25 square objects on it, and appropriate values for each column of the grid (B: 1-15,i:16-30, etc.), which are chosen randomly on each card. If we work with all 75 possible numbers (maybe not the best approach), each number needs to know if it's on the bingo card for this game, whether it's matched a number that's already been picked(), and whether it's a Freebie (middle square on the card - 'FREE' instead of a number)

    Initial questions:

    Can like objects be grouped by some mechanism such that changing an external parameter has them respond to that change, or do they each need to be iterated/manipulated each time to become "aware" of global changes? For example, a number is picked() - can the squares "know" if one matches the new number, or do I need to trigger each one to check?

    Maybe I'm thinking in more of a parallel-thread mode here, one thread per object, which remains "active" during the game. Is that way out there? It's probably over my head at this point anyway.

    Reel me in; tell me what you think.
  • bartonc
    Recognized Expert Expert
    • Sep 2006
    • 6478

    #2
    Originally posted by true911m
    We have 75 ball objects, which can be picked randomly by a machine, and which therefore need an awareness of being picked(), since no ball can come up twice in a game.
    Actually, I believe that the machine is the object in question and that balls are data that it dispences. The machine (object) has a better chance of encapsulating awareness of which numbers have been dispensed than a ball does.

    Originally posted by true911m
    We have a scorecard grid with 25 square objects on it, and appropriate values for each column of the grid (B: 1-15,i:16-30, etc.), which are chosen randomly on each card. If we work with all 75 possible numbers (maybe not the best approach), each number needs to know if it's on the bingo card for this game, whether it's matched a number that's already been picked(), and whether it's a Freebie (middle square on the card - 'FREE' instead of a number)

    Initial questions:

    Can like objects be grouped by some mechanism such that changing an external parameter has them respond to that change, or do they each need to be iterated/manipulated each time to become "aware" of global changes? For example, a number is picked() - can the squares "know" if one matches the new number, or do I need to trigger each one to check?
    I've got similar thoughts here. Going to look for some examples

    Originally posted by true911m
    Maybe I'm thinking in more of a parallel-thread mode here, one thread per object, which remains "active" during the game. Is that way out there? It's probably over my head at this point anyway.

    Reel me in; tell me what you think.
    Do you have Robin Dunn's book: wxPython in Action?

    Comment

    • true911m
      New Member
      • Dec 2006
      • 92

      #3
      Originally posted by bartonc
      Actually, I believe that the machine is the object in question and that balls are data that it dispences. The machine (object) has a better chance of encapsulating awareness of which numbers have been dispensed than a ball does.



      I've got similar thoughts here. Going to look for some examples



      Do you have Robin Dunn's book: wxPython in Action?
      I haven't read it all, just looked up a few things.

      I'm not really interested in the GUI in particular, more the logic. If the GUI objects are easier to build/attach to than abstract code items, that's fine.

      Comment

      • true911m
        New Member
        • Dec 2006
        • 92

        #4
        The reason for the balls, instead of the machine, as objects is that I want to exercise multiple identical objects in action. JFYI.

        Comment

        • bartonc
          Recognized Expert Expert
          • Sep 2006
          • 6478

          #5
          Originally posted by true911m
          The reason for the balls, instead of the machine, as objects is that I want to exercise multiple identical objects in action. JFYI.
          Ok, I'll buy that. So if each ball instance needs to know which number was just picked() here's how I'd (almost) lay out the structure:

          Code:
          # I do this a bit differently, but Mr. Dunn says something like this:
          
          class NumberDispenser(object):
              def __init__(self):
                  self.clients = []
          
              def RegisterClient(self, client):
                  self.clients.append(client)
          
              def UpdateClients(self, data):
                  for client in self.clients:
                      client.Update(data)     # This part I don't like:
                                              # having to know the name of the client function here
          
          class NumberClient(object):
              def __init__(self, server, name):
                  self.name = name
                  server.RegisterClient(self)
          
              def Update(self, data):
                  print self.name, data
          
          
          if __name__ == "__main__":
              server = NumberDispenser()
              client1 = NumberClient(server, "client #1")
              client2 = NumberClient(server, "client #2")
          
              # call this in response to some event or whatever
              server.UpdateClients(6545)

          Comment

          • bartonc
            Recognized Expert Expert
            • Sep 2006
            • 6478

            #6
            Originally posted by true911m
            I haven't read it all, just looked up a few things.

            I'm not really interested in the GUI in particular, more the logic. If the GUI objects are easier to build/attach to than abstract code items, that's fine.
            Actually, I don't use the GUI stuff from the book. I really like (and use similar design) the Model-View-Controler idea. There is also threading discussion toward the end.

            Comment

            • true911m
              New Member
              • Dec 2006
              • 92

              #7
              Originally posted by bartonc
              Actually, I don't use the GUI stuff from the book. I really like (and use similar design) the Model-View-Controler idea. There is also threading discussion toward the end.
              OK, that's not ringing any bells. Can you elaborate on this - what, where, refs?

              Comment

              • true911m
                New Member
                • Dec 2006
                • 92

                #8
                Originally posted by bartonc
                Ok, I'll buy that. So if each ball instance needs to know which number was just picked() here's how I'd (almost) lay out the structure:

                Code:
                    def UpdateClients(self, data):
                        for client in self.clients:
                            client.Update(data)     # This part I don't like:
                                                    # having to know the name of the client function here
                
                ...
                if __name__ == "__main__":
                    server = NumberDispenser()
                    client1 = NumberClient(server, "client #1")  # <===
                    client2 = NumberClient(server, "client #2")  # <===



                Regarding that, my original thought, which is admittedly BASIC-esque, was to define an array where each element would become an instance. I don't know how to translate that here, but such a construct would alleviate much of the naming overhead. I guess it would also be redundant, since if I did that I wouldn't need the objects at all. :) But like I said, it's an academic exercise...

                Can I use some form of eval() to create something like (this is just off the top of my head, trying to get the idea across):
                Code:
                varhdr = 'client'
                
                for i in range(75):
                    eval(varhdr+str(i)+' = NumberClient(server, "client #'+str(i)+'")')
                Don't know if that's close to a proper use of eval; in SB we had a means of constructing dynamic lines of code like that so they could be reused, as in a loop.

                This problem is what I was referring to when I mentioned a curiousity about how people would "group"cont rol of these objects.

                Actually, the use of a class variable, as discussed in that other thread, may make sense here. Such as, when a number is picked,

                Code:
                NumberClient.LastPicked=32
                
                for square in grid:
                    # execute instance.CheckPicked code here
                    # each instance of NumberClient class now has 
                    # a self.LastPicked value of 32 to process against

                Comment

                • bartonc
                  Recognized Expert Expert
                  • Sep 2006
                  • 6478

                  #9
                  Originally posted by true911m
                  Regarding that, my original thought, which is admittedly BASIC-esque, was to define an array where each element would become an instance. I don't know how to translate that here, but such a construct would alleviate much of the naming overhead. I guess it would also be redundant, since if I did that I wouldn't need the objects at all. :) But like I said, it's an academic exercise...

                  Can I use some form of eval() to create something like (this is just off the top of my head, trying to get the idea across):
                  Code:
                  varhdr = 'client'
                  
                  for i in range(75):
                      eval(varhdr+str(i)+' = NumberClient(server, "client #'+str(i)+'")')
                  Don't know if that's close to a proper use of eval; in SB we had a means of constructing dynamic lines of code like that so they could be reused, as in a loop.

                  This problem is what I was referring to when I mentioned a curiousity about how people would "group"cont rol of these objects.

                  Actually, the use of a class variable, as discussed in that other thread, may make sense here. Such as, when a number is picked,

                  Code:
                  NumberClient.LastPicked=32
                  
                  for square in grid:
                      # execute instance.CheckPicked code here
                      # each instance of NumberClient class now has 
                      # a self.LastPicked value of 32 to process against
                  A list comprehension is what you are looking for. A comprehension is a very handy tool when you don't need much stuff going on in a loop, but you do need elements appended to a list. This technique creates the list object and fills it in all at once. Notice, also, the C-line string formatting. I use it all the time.


                  Code:
                  class NumberDispenser(object):
                      def __init__(self):
                          self.clients = []
                  
                      def RegisterClient(self, client):
                          self.clients.append(client)
                  
                      def UpdateClients(self, data):
                          for client in self.clients:
                              client.Update(data)     # This part I don't like:
                                                      # having to know the name of the client function here
                  
                  class NumberClient(object):
                      def __init__(self, server, name):
                          self.name = name
                          server.RegisterClient(self)
                  
                      def Update(self, data):
                          print self.name, data
                  
                  
                  if __name__ == "__main__":
                      server = NumberDispenser()
                      # list comprehension syntax uses [] on around the expession, generators use ()
                      instanceList = [NumberClient(server, "client%d" %i) for i in range(5)]
                      for inst in instanceList:
                          print inst.name

                  Comment

                  • bartonc
                    Recognized Expert Expert
                    • Sep 2006
                    • 6478

                    #10
                    The list comprehension here
                    Code:
                    instanceList = [NumberClient(server, "client%d" %i) for i in range(5)]
                    is equivalent to
                    Code:
                    instanceList = []
                    for i in range(5):
                        instanceList.append(NumberClient(server, "client%d" %i))
                    which may be easier to read. I learned comprehensions so long ago that I have forgotten if the benefits actually outweigh the mashed syntax. If I get a break, I'll look it up and get back to you.

                    Comment

                    • true911m
                      New Member
                      • Dec 2006
                      • 92

                      #11
                      Originally posted by bartonc
                      The list comprehension here
                      Code:
                      instanceList = [NumberClient(server, "client%d" %i) for i in range(5)]
                      is equivalent to
                      Code:
                      instanceList = []
                      for i in range(5):
                          instanceList.append(NumberClient(server, "client%d" %i))
                      which may be easier to read. I learned comprehensions so long ago that I have forgotten if the benefits actually outweigh the mashed syntax. If I get a break, I'll look it up and get back to you.
                      Not sure what you're looking up, but I get the listcomp. That does what I was thinking; it didn't occur to me to use the inline string formatting to achieve the desired result.

                      Comment

                      • bvdet
                        Recognized Expert Specialist
                        • Oct 2006
                        • 2851

                        #12
                        I have a couple of simple thoughts on your Bingo project:
                        The balls could be a list.
                        Code:
                        x = random.sample(range(1, 26, 1),25)
                        >>> x
                        [17, 23, 12, 18, 9, 6, 13, 10, 24, 7, 15, 3, 22, 4, 11, 8, 2, 14, 20, 25, 1, 19, 16, 5, 21]
                        When it is time to select a ball, pop it from the list.

                        The 'game' could be a dictionary of lists. The dictionary keys are 'card1', 'card2',...... and each list would be filled randomly with unique numbers. When a number is selected, each player's card is scanned for a match, and if a match is found, the list position is set to False.
                        Code:
                        for card in dd.keys():
                            if ball in dd[card]:
                                dd['card1'][dd.['card1'].index(ball)] == False
                        After a match is found, a card scan method could be called to check for Bingo.

                        My contribution to this tread is probably be limited by my experience. I try to keep things simple. Most of the applications I have developed involve calculations in 3D space, manipulation of lists, dictionaries, tuples and strings, and reading/writing small data files. Classes incorporate instance variables and functions and sometimes methods when useful. Typically I do not modify instance data externally. I have a Python project coming up - add a steel angle brace between two structural steel beams. At the right time I'll start a thread on it.

                        Please keep this thead going - I want to know how it turns out.

                        Best Regards,
                        BV

                        ps - tru911m (Mark), Are you from Baltimore, MD? I detailed the structural steel for the Hippodrome PAC on N. Eutah a few years ago. Beautiful structure.

                        Comment

                        • true911m
                          New Member
                          • Dec 2006
                          • 92

                          #13
                          Hi BV,

                          Yes, I'm a lifelong Baltimoron as we jokingly say. I remember the Hippodrome from its declining days as a moviehouse back in the 70s. It's great that that area is receiving some deserved attention to (at lease some of ) the irreplaceable structures there. It used to be the grand shopping mecca downtown, before malls and the burbs took over.

                          As for the bingo, I'm pretty straightforward myself. In fact I keep slipping off the path I've laid for myself, in that this project has the arbitrary requirement that these items use objects to accomplish the task, even though it can be directly handled without them.

                          I'm trying, through use, to exercise my understanding of the interactions and management of simple objects, and I really want to create a couple of classes (balls in machine, squares on the bingo card) that must be instantiated many times (75 numbers, 25 squares) to get the hang of dealing with them all.

                          In fact, one misconception I keep falling back to is that an 'object' is more like a 'bot' - as if each of these items takes up CPU on its own in a separate thread, and all I have to do is 'talk' to them like IRC bots or something. In fact, I know better, that I have to go 'process' each one based on some sort of event, but that's what I keep seeing in my head, and I'm trying to shake it.

                          Comment

                          • true911m
                            New Member
                            • Dec 2006
                            • 92

                            #14
                            OK, getting a really basic start here. I apologize if any of this repeats -- until it clicks, I'm having some issues retaining a few things.

                            Based on Barton's tutorial on variables in classes, I just received an unexpected result. Here's a sample:

                            Code:
                            class BingoCard:
                                def __init__(self):
                                    self.card=[]
                                def FillGrid(self):
                                    for row in range(5):
                                        for col in range(5):
                                            self.card.append((row,col))  # replace tuples with objects
                                def ShowGrid(self):
                                    print self.card
                            
                            card=BingoCard()
                            card.FillGrid()
                            card.ShowGrid()
                            print card.card
                            I expected to need ShowGrid() to get at my generated bingo card. What I didn't expect is that the last line, print, will also display the grid.

                            Since self.card is defined in BingoCard.__ini t__, I thought it would be inaccessible from the outside world, but the output shows differently:

                            Code:
                            [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4)]
                            [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4)]
                            What am I forgetting?

                            Comment

                            • true911m
                              New Member
                              • Dec 2006
                              • 92

                              #15
                              Originally posted by true911m
                              Not sure what you're looking up, but I get the listcomp. That does what I was thinking; it didn't occur to me to use the inline string formatting to achieve the desired result.
                              I'm still having my original dilemma on these results.

                              I see how the listcomp generates the strings, but how do I make each string result become the name of a variable that I use to instantiate my object, all "hands off"?

                              (I'm working on this part right now...)

                              Comment

                              Working...