Reputation: 43
I am very new to python/pygame so please forgive me if I'm not using the right terms.
I am making a game where the player shoots 2 objects. When one object is hit, the health decreases by 3 80% of the time and it decreases by 13 20% of the time. I already have that working by using rand.choice and a list.
I want to redo the way that it is set up so that I know exactly what the outcome will be and in what order.
A friend suggested using a range of length, but he only knows how to do that with a different coding language.
This is my code:
hits = pg.sprite.groupcollide(self.enemies, self.shards, False, True)
for hit in hits:
hit.health -= choice(RANDO)
hit.vel = vec(0, 0)
print('win')
RANDO is defined as:
RANDO = [LOSE, LOSE, JACKPOT, LOSE, LOSE,
LOSE, LOSE, LOSE, LOSE, JACKPOT]
With Lose = 3 and Jackpot = 13
I want the result of shooting the enemy to be what I have listed in random in order EVERY time. So the player will ALWAYS only hit Jackpot on their 3rd and 10th times. Basically, each time the player shoots, the resulting damage will be decided according to what comes next in the list.
I know I'll have to get rid of the rand.choice I'm using to make the game attacks randomly hit at certain damages at a certain percentage, but I won't need it to do that anymore.
If anyone has any idea of what I should use or plug in I'd appreciate it. I just need it to take one value from the list and work its way through it.
Upvotes: 0
Views: 83
Reputation: 43
What ended up working was using a popleft element.
'''for hit in hits:
hit.health -= RANDO.pop()
hit.vel = vec(0, 0)
print('win')'''
And adding deque before the list that I wanted it to run through
'''LOSE = 3
JACKPOT = 13
RANDO = deque([LOSE, LOSE, JACKPOT, LOSE, LOSE,
LOSE, LOSE, LOSE, LOSE, JACKPOT])'''
Now it goes through the list one by one and in order - before it was starting at the end and working its way backwards.
Upvotes: 0
Reputation: 101072
An easy way is to create a list of your expected sequence (as you already did with RANDO
), and then use cycle
, to "cycle" through this sequence:
λ python
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 21:26:53) [MSC v.1916 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> RANDO = ['LOSE', 'LOSE', 'JACKPOT', 'LOSE', 'LOSE', 'LOSE', 'LOSE', 'LOSE', 'LOSE', 'LOSE', 'JACKPOT']
>>> from itertools import cycle
>>> RANDO_GEN = cycle(RANDO)
>>> for _ in range(25):
... print(next(RANDO_GEN))
...
LOSE
LOSE
JACKPOT
LOSE
LOSE
LOSE
LOSE
LOSE
LOSE
LOSE
JACKPOT
LOSE
LOSE
JACKPOT
LOSE
LOSE
LOSE
LOSE
LOSE
LOSE
LOSE
JACKPOT
LOSE
LOSE
JACKPOT
>>>
cycle
returns a generator, and you use next
to get the next element of this infinite sequence; so you just replace your code with:
LOSE = 3
JACKPOT = 13
RANDO = cycle([LOSE, LOSE, JACKPOT, LOSE, LOSE,
LOSE, LOSE, LOSE, LOSE, JACKPOT])
...
for hit in hits:
hit.health -= next(RANDO)
hit.vel = vec(0, 0)
print('win')
Upvotes: 1
Reputation: 77847
You could keep a counter:
hit_count = 0
for hit in hits:
hit.health -= RANDO[hit_count % len(RAND0)]
hit_count += 1
hit.vel = vec(0, 0)
print('win')
If you have only one run through the list, just pop
the elements as needed:
for hit in hits:
hit.health -= RANDO.pop()
hit.vel = vec(0, 0)
print('win')
Functionality check:
LOSE = 3
JACKPOT = 13
RANDO = [LOSE, LOSE, JACKPOT, LOSE, LOSE,
LOSE, LOSE, LOSE, LOSE, JACKPOT]
hit_count = 0
health = 50
for hit in range(10):
health -= RANDO[hit_count % len(RANDO)]
hit_count += 1
print('new health', health)
Output:
new health 47
new health 44
new health 31 JACKPOT
new health 28
new health 25
new health 22
new health 19
new health 16
new health 13
new health 0 JACKPOT
My mistake on the second solution: pop
works from the other end:
for hit in range(10):
health -= RANDO.pop(0)
print('new health', health)
Output:
new health 47
new health 44
new health 31
new health 28
new health 25
new health 22
new health 19
new health 16
new health 13
new health 0
Upvotes: 1