Need ideas and insights on a project...

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

    #16
    Originally posted by true911m
    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...)
    Skip that -- I found it:

    Code:
    self.name=name # passed in when instantiated

    Comment

    • bartonc
      Recognized Expert Expert
      • Sep 2006
      • 6478

      #17
      Originally posted by true911m
      Skip that -- I found it:

      Code:
      self.name=name # passed in when instantiated
      actually I was thinking of this line:
      Originally posted by bartonc
      Code:
          # it is legal to access the variables directly
          print inst1.cv1
      It is not only legal, but common practice. I, however, try to avoid it.

      Comment

      • true911m
        New Member
        • Dec 2006
        • 92

        #18
        Originally posted by bartonc
        It is not only legal, but common practice. I, however, try to avoid it.
        I know you prefer setters and getters. (You'll be proud of me in my results post, in a minute). I get that it could be dicey if you write to vars from the outside, based on our earlier discussion. I'm not as clear on why it's a bad practice to "read", or return results from, internal vars, however. Is it just a purity thing?

        Comment

        • true911m
          New Member
          • Dec 2006
          • 92

          #19
          Early results:

          Here's BingoCard() that consists of 25 Square() objects. The instances are named individually (thanks Barton!) and also stored in a compound list, and able to be referenced directly (item[x][y]).

          I chose to skip the listcomp for now to simplify my own comprehension (ptp). However, I've seen evidence that the listcomp is actually more efficient, and I will make the conversion after all of my logic is worked out.

          Here's my starter code:

          Code:
          import random
          
          class BingoCard:
              
              def __init__(self):
                  self.card=[]
              def FillGrid(self):
                  for row in range(5):
                      self.rowlist=[]
                      for col in range(5):
                          self.rowlist.append(Square(self,"%d"%row,"%d"%col))
                      self.card.append(self.rowlist[:])
                                  
              def ShowGrid(self):
                  for row in self.card:
                      print 
                      for sq in row:
                          sq.ShowName()
                  
          class Square:
              
              def __init__(self, parent, row,col):
                  self.row=row
                  self.col=col
                  self.name="square-"+str(row)+"-"+str(col)
                  self.parent=parent
              
              def ShowName(self):
                  print self.name+"  ",
              
          
          card=BingoCard()
          card.FillGrid()
          card.ShowGrid()
          print
          print
          card.card[2][1].ShowName()
          and here's my output:

          Code:
          square-0-0   square-0-1   square-0-2   square-0-3   square-0-4  
          square-1-0   square-1-1   square-1-2   square-1-3   square-1-4  
          square-2-0   square-2-1   square-2-2   square-2-3   square-2-4  
          square-3-0   square-3-1   square-3-2   square-3-3   square-3-4  
          square-4-0   square-4-1   square-4-2   square-4-3   square-4-4  
          
          square-2-1
          Now that the object distribution is working, I can replicate it for the BingoMixer() and BingoBall()s, and start adding smarts to the objects. I'm pretty psyched. :)

          Comment

          • bartonc
            Recognized Expert Expert
            • Sep 2006
            • 6478

            #20
            Getting there... one little thing that I noticed:
            There's no need for the extra lookup required by self. references here.
            Code:
                def FillGrid(self):
                    for row in range(5):
                        self.rowlist=[]
                        for col in range(5):
                            self.rowlist.append(Square(self,"%d"%row,"%d"%col))
                        self.card.append(self.rowlist[:])
            Use function scope variables for things like this. ie
            Code:
                def FillGrid(self):
                    for row in range(5):
                        rowlist=[]
                        for col in range(5):
                            rowlist.append(Square(self,"%d"%row,"%d"%col))
                        self.card.append(rowlist[:])    # since you want [:] probably don't need to slice

            Comment

            • true911m
              New Member
              • Dec 2006
              • 92

              #21
              Originally posted by bartonc
              Getting there... one little thing that I noticed:
              There's no need for the extra lookup required by self. references here.
              OK, I got the function (method?) local thing.

              I was concerned that, because I was using rowlist in a loop, to populate the card, that I didn't want any crosslinks between items on different rows, so I forced a copy [:] in the append. I see that wasn't necessary after trying it, but I err on the side of caution since all those rules for mutables aren't yet second-nature for me.

              Comment

              • true911m
                New Member
                • Dec 2006
                • 92

                #22
                BINGO!!!

                I've got a working model.

                Don't know if I should post the code, it's a little over 200 lines. Could probably be more elegant, but the logic's good, and objects abound!

                Thanks guys. Give me the go-ahead if I should put it up here; if it's too much, no problem. Is there a separate area for uploads etc.?

                Comment

                • bartonc
                  Recognized Expert Expert
                  • Sep 2006
                  • 6478

                  #23
                  Originally posted by true911m
                  BINGO!!!

                  I've got a working model.

                  Don't know if I should post the code, it's a little over 200 lines. Could probably be more elegant, but the logic's good, and objects abound!

                  Thanks guys. Give me the go-ahead if I should put it up here; if it's too much, no problem. Is there a separate area for uploads etc.?
                  Post away (up to 10000 character limit).

                  Comment

                  • bartonc
                    Recognized Expert Expert
                    • Sep 2006
                    • 6478

                    #24
                    Originally posted by true911m
                    OK, I got the function (method?) local thing.
                    Yes, to use proper OO parlance, "method" is, of course, correct. Scope rules for functions still apply, though.
                    Originally posted by true911m
                    I was concerned that, because I was using rowlist in a loop, to populate the card, that I didn't want any crosslinks between items on different rows, so I forced a copy [:] in the append. I see that wasn't necessary after trying it, but I err on the side of caution since all those rules for mutables aren't yet second-nature for me.
                    What is actually taking place is:
                    1. create an empty list and assign it to the name "rowlist"
                    2. fill it in the loop
                    -now here's the fun part-
                    3. assign a reference (self.card[i]) to that object (internally, refcount += 1) - creating two refferences to the same object
                    4. reassign the value of "rowlist" to an empty list (refcount -= 1) - only self.card[i] remains "pointing" to to the list.
                    and so on.

                    As a bonus when refcount = 0 the object will be garbage collected. This is the reason we don't ever worry about memory management. Some programmers will
                    Code:
                    del objcect
                    to free up memory immediately and make the reference to "object" invalid, some will
                    Code:
                    object = None
                    (which keeps "object" assigned, but releases the memory for GC). For large objects the former is probably a good practice. Most often it's OK to just leave the object hanging around.

                    Comment

                    • true911m
                      New Member
                      • Dec 2006
                      • 92

                      #25
                      Originally posted by bartonc
                      Post away (up to 10000 character limit).
                      Okie Dokie.

                      Let's start with my output. We start with a randomly generated bingo card. Then we're given the number of balls pulled from the machine, and their order, followed by BINGO!!!, and the final winning card with matched numbers blacked out for the visual effect. This allows us to validate the program operation against the initial random values chosen.

                      Code:
                      B	I	N	G	O
                      
                      8	26	36	48	75	
                      2	22	38	58	64	
                      10	24	##	51	63	
                      3	30	44	59	69	
                      15	25	41	53	62	
                      
                      30 balls drawn:
                      
                      46 55 53 26 58 16 30 22 64 49 67 32 50 4 21 20 6 2 18 27 62 11 23 15 35 5 51 66 47 38
                      
                      BINGO!!!
                      
                      B	I	N	G	O
                      
                      8	##	36	48	75	
                      ##	##	##	##	##	
                      10	24	##	##	63	
                      3	##	44	59	69	
                      ##	25	41	##	##
                      Of course, while testing, I had stuff printing all over the place at various intervals, but in the end it condensed nicely to this compact display.

                      The code has a lot of logic redundancy since the BingoCard and BingoSquare behave very similarly to the BingoMixer and BingoBall, with the exception of the 5x5 requirement for the layout of the card, and the fact that each column only contains a subset of the random numbers drawn, ensuring a somewhat smooth distribution across the card.

                      My only lazy point, I realize this morning, is that I believe the numbers in a column on a real bingo card are sorted in ascending order. If I'd thought of this, I probably would have populated them in a column-first order, which would allow me to sort the elements of that sublist easily. As it is, I generated the card in a row-first order, and although I can visualize the solution, I don't feel like messing with it right now. :) So here goes:

                      Code:
                      import random
                      
                      class BingoCard:
                          
                          def __init__(self,prnt):
                              self.card=[]
                              self.parent=prnt
                              self.BingoPatterns=[\
                                      [[0,0],[0,4],[2,2],[4,0],[4,4]],\
                                      [[0,0],[1,1],[2,2],[3,3],[4,4]],\
                                      [[4,0],[3,1],[2,2],[1,3],[0,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]],\
                                      [[0,0],[1,0],[2,0],[3,0],[4,0]],\
                                      [[0,1],[1,1],[2,1],[3,1],[4,1]],\
                                      [[0,2],[1,2],[2,2],[3,2],[4,2]],\
                                      [[0,3],[1,3],[2,3],[3,3],[4,3]],\
                                      [[0,4],[1,4],[2,4],[3,4],[4,4]]\
                                      ]
                                                  
                          def FillCard(self):
                              if len(self.card):
                                  for row in self.card:
                                      for square in row:
                                          square.ResetMatched()
                                          square.ResetNumber()                
                              else:
                                  for row in range(5):
                                      rowlist=[]
                                      for col in range(5):
                                          rowlist.append(BingoSquare(self,"%d"%row,"%d"%col))
                                      self.card.append(rowlist)
                                                              
                          def ShowCard(self):
                              print; print'B\tI\tN\tG\tO'
                              for row in self.card:
                                  print
                                  for square in row:
                                      if square.GetMatched():
                                          print '##\t',
                                      else:                    
                                          print '%d\t' % square.GetNumber(),
                              print
                                      
                          def NewGame(self):
                              NumbersLeft=[]
                              for i in range(5):
                                  NumbersLeft.append(range(1+(i*15),16+(i*15)))
                              self.FillCard()
                              for row in self.card:
                                  for i in range(5):                
                                      rnum=random.randint(0,len(NumbersLeft[i])-1)
                                      row[i].SetNumber(NumbersLeft[i][rnum])
                                      #print i,NumbersLeft[i][rnum]
                                      #print square.GetNumber()
                                      NumbersLeft[i]=NumbersLeft[i][:rnum]+NumbersLeft[i][rnum+1:]
                                      #print NumbersLeft        
                              self.card[2][2].SetNumber(0)
                              self.card[2][2].SetMatched()  
                              #self.ShowCard()
                          
                          def CheckMatches(self,num):
                              for row in self.card:
                                  for square in row:
                                      if square.GetNumber()==num:
                                          square.SetMatched()
                          
                          def CheckBingo(self):
                              for set in self.BingoPatterns:
                                  bingo=True            
                                  for coords in set:
                                      if not self.card[coords[0]][coords[1]].GetMatched():
                                          bingo=False
                                          break                    
                                  if bingo: return True
                              return False
                              
                      
                      class BingoSquare:
                          
                          def __init__(self, prnt, row,col):
                              self.row=row
                              self.col=col
                              self.name="sqr"+str(row)+str(col)
                              self.parent=prnt
                              self.number=0
                              self.matched=False
                          
                          def ShowName(self):
                              pass
                              print self.name+"  ",
                      
                          def SetNumber(self,num):
                              self.number=num
                              
                          def ResetNumber(self):
                              self.number=None
                          
                          def GetNumber(self):
                              return self.number
                          
                          def SetMatched(self):
                              self.matched=True
                              
                          def ResetMatched(self):
                              self.matched=False
                              
                          def GetMatched(self):
                              return self.matched
                          
                          
                      
                      class BingoMixer:
                          
                          def __init__(self,prnt):
                              self.balls=[]
                              self.parent=prnt
                          
                          def FillBox(self):
                              if len(self.balls):
                                  for ball in self.balls:
                                      ball.ResetDrawn()
                                      ball.ResetNumber()                
                              else:
                                  for ball in range(75):
                                      self.balls.append(BingoBall(self,"%d"%ball))
                                                      
                          def ShowBox(self):
                              for ball in self.balls:
                                  ball.ShowName()
                                  
                          def ShowBalls(self):
                              for ball in self.balls:
                                  print ball.GetNumber(), # ball.GetDrawn()
                                  
                          def ShowDrawn(self):
                              for i in range(len(self.balls)):
                                  if not self.balls[i].GetDrawn():
                                      self.drawnBalls=self.balls[:i]
                                      print; print '%d balls drawn:' % len(self.drawnBalls)
                                      print
                                      for ball in self.drawnBalls:                    
                                          print ball.GetNumber(),
                                      break
                              print
                          
                          def NewGame(self):
                              NumbersLeft=range(1,76)
                              self.FillBox()
                              for ball in self.balls:
                                  rnum=random.randint(0,len(NumbersLeft)-1)
                                  ball.SetNumber(NumbersLeft[rnum])
                                  #print ball.GetNumber()
                                  NumbersLeft=NumbersLeft[:rnum]+NumbersLeft[rnum+1:]
                                  #print NumbersLeft
                              #self.ShowBalls()      
                              
                      
                      class BingoBall:
                          
                          def __init__(self, parent, ballno):
                              self.name="ball"+str(ballno)
                              self.parent=parent
                              self.number=0
                              self.drawn=False
                          
                          def ShowName(self):
                              print self.name,
                              
                          def SetNumber(self,num):
                              self.number=num
                              
                          def ResetNumber(self):
                              self.number=None
                          
                          def GetNumber(self):
                              return self.number
                          
                          def SetDrawn(self):
                              self.drawn=True
                              
                          def ResetDrawn(self):
                              self.drawn=False
                              
                          def GetDrawn(self):
                              return self.drawn
                          
                      class BingoGame:
                          import random
                          random.seed()
                      
                          def __init__(self):        
                              self.card=BingoCard(self)
                              self.mixer=BingoMixer(self)
                          
                          def Play(self):
                              bingo=False
                              self.card.NewGame()
                              self.mixer.NewGame()
                              self.card.ShowCard()
                              
                              for ball in self.mixer.balls:
                                  thisNum=ball.GetNumber()
                                  ball.SetDrawn()
                                  #print;print thisNum
                                  self.card.CheckMatches(thisNum)
                                  #self.card.ShowCard()
                                  if self.card.CheckBingo():
                                      break
                              
                              self.mixer.ShowDrawn()    
                              print; print 'BINGO!!!'
                              self.card.ShowCard()
                              quit()
                          
                              
                      if __name__ == '__main__':
                          game=BingoGame()
                          game.Play()
                      I left my quit() in an inopportune place, but it doesn't really affect the outcome. What's the proper way to end something? Just have it come back to main and drop off the bottom, or do you have to load and use sys.exit() all the time?

                      Plenty of room here for tightening, especially since my use of objects was an academic exercise. Learning about object use and efficiency was my primary goal here, so object-related critique would be most helpful to my learning process.

                      Thanks all!

                      Comment

                      • bvdet
                        Recognized Expert Specialist
                        • Oct 2006
                        • 2851

                        #26
                        Mark,

                        That's really cool. It works fine in Pythonwin without the quit(). Thanks for posting.

                        BV

                        Comment

                        • bartonc
                          Recognized Expert Expert
                          • Sep 2006
                          • 6478

                          #27
                          Originally posted by true911m
                          The code has a lot of logic redundancy since the BingoCard and BingoSquare behave very similarly to the BingoMixer and BingoBall, with the exception of the 5x5 requirement for the layout of the card, and the fact that each column only contains a subset of the random numbers drawn, ensuring a somewhat smooth distribution across the card.
                          I'm still having a look at this. I may be time to start exploring "inheritanc e" where a super class has the common elements in it and subclasses inherit and/or override aspects of the parent class.

                          Originally posted by true911m
                          What's the proper way to end something? Just have it come back to main and drop off the bottom?
                          That's it!
                          Originally posted by true911m
                          Plenty of room here for tightening, especially since my use of objects was an academic exercise. Learning about object use and efficiency was my primary goal here, so object-related critique would be most helpful to my learning process.
                          As I say, I'm still having a look. I'll get back to you.
                          PS It's good to see you messing around in the other forums. It can be fun.

                          Comment

                          • bartonc
                            Recognized Expert Expert
                            • Sep 2006
                            • 6478

                            #28
                            Originally posted by bartonc
                            What is actually taking place is:
                            1. create an empty list and assign it to the name "rowlist"
                            2. fill it in the loop
                            -now here's the fun part-
                            3. assign a reference (self.card[i]) to that object (internally, refcount += 1) - creating two refferences to the same object
                            4. reassign the value of "rowlist" to an empty list (refcount -= 1) - only self.card[i] remains "pointing" to to the list.
                            and so on.
                            The same type of thing happens when a function uses a local (functions scope) variable to (say) build a list and then returns that list to the caller. The local reference parishes but the object is kept alive because the caller now has a reference to it.

                            Comment

                            Working...