0

I am working on my first Python game but before I get started, I am working through some tutorials and trying to modify them. I found a great "bejeweled" style game that I am trying to make some changes to, however I am running into one problem.

The game normally used seven different images. When the game would start, it would place the gems in a somewhat random order but it checked to make sure it wasn't putting a ton of the same gems next to each other.

What I am wanting to do is greatly increase the number of images to seventeen. All the images load correctly, however some of the images I want to limit the number of times they appear. For example, I want gem1 through gem3 to be the more common gem, while all the others do not appear as often. I am thinking of doing something like using random. Have it pick a number between 1-5. If 1-4 is picked, either gem1, gem2, or gem3 will be picked. If 5 is picked, any of the other gems will appear but it always needs to follow the possibleGems code to make sure a bunch of the same images are not appearing next to each other. Any ideas on how to make this work?

I have included some of the tutorial code in the places that are the most important to the gems. You can also look up the full source code by searching for gemgem.py in google.

possibleGems = list(range(len(GEMIMAGES)))
            for offsetX, offsetY in ((0, -1), (1, 0), (0, 1), (-1, 0)):
                # Narrow down the possible gems we should put in the
                # blank space so we don't end up putting an two of
                # the same gems next to each other when they drop.
                neighborGem = getGemAt(boardCopy, x + offsetX, y + offsetY)
                if neighborGem != None and neighborGem in possibleGems:
                    possibleGems.remove(neighborGem)

            newGem = random.choice(possibleGems)
            boardCopy[x][y] = newGem
            dropSlots[x].append(newGem)

Code to load the images

# Load the images
GEMIMAGES = []
for i in range(1, NUMGEMIMAGES+1):
    gemImage = pygame.image.load('gem%s.png' % i)
    if gemImage.get_size() != (GEMIMAGESIZE, GEMIMAGESIZE):
        gemImage = pygame.transform.smoothscale(gemImage, (GEMIMAGESIZE, GEMIMAGESIZE))
    GEMIMAGES.append(gemImage)
Badge
  • 61
  • 5

2 Answers2

0

the simpler way would be something like this. Basically, instead of creating a list like [0,1,2], you repeat each element as many times as you want the relative probability.

gem_frequency = [10, 8, 7, 3, 1, 1, 1, 1, 1]
gem_lists = []
for index, gf in enumerate(gem_frequency):
    gem_lists.append([index] * gf)

gem_prob = chain(*gem_lists)

gem_prob
[0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,4,5,6,7,8]

len(gem_prob)
33

random.choice(gem_prob)
0
1
0
3
1
3
8
0
2
4

So, entry 2 was listed as frequency 10. It should appear about 10 times as often as entry 8 (which has a frequency of only 1). The total weights for these is 33, and 0 will be chosen approximately 10/33 of the time.

If the list gets too long, it might consume a lot of memory, but usually this is sufficient.

or use a weighted choice like this:

A weighted version of random.choice

Community
  • 1
  • 1
Corley Brigman
  • 11,633
  • 5
  • 33
  • 40
0

I recommend something like this, for keeping the distribution neat and easily modifiable:

gemOptions = []
gemOptions += ['red'] * 4
gemOptions += ['blue'] * 3
gemOptions += ['green'] * 2

In [6]: gemOptions
Out[6]: ['red', 'red', 'red', 'red', 'blue', 'blue', 'blue', 'green', 'green']

Then you can simply do

random.choice(gemOptions)

and you have a simple weighted average. You can do whatever error checking you need to ensure that appropriate gems are not next to each other, and if you need to choose another random gem you can do so.

Chris Arena
  • 1,602
  • 15
  • 17
  • I like this approach but I am totally new to python and fairly new to programming as a whole so I am lost as to were code like this belongs in the tutorial I am trying to modify. It appears the code stores each gem image to a list of GEMIMAGES and assigns each one a number. It then uses these numbers to verify if a correct match of three (or more) has happened. I can't figure out how to take this approach and add it into the tutorial game without making a ton of changes that will most likely end with me breaking something. Any advice on how to put this code into the tutorial so it runs? – Badge Oct 07 '13 at 17:18