Cycle elements in a python list at least once - python

So I have a simple piece of code:
class Player:
def __init__(self):
self.score = 0
players = [Player() for _ in range(10)]
Now I want to:
Iterate the players in the list indefinitely
Skip players with a negative score
from itertools import cycle
loop = cycle(players)
loop = filter(lambda player: player.score >= 0, loop)
Stop the iteration when there is only one player left with a positive score
Or when there are two or more players with a positive score, every one of them has been iterated at least once and each of them has an equal score
I have a problem with these conditions and I don't know how to bite them.

Solution 1
Here's a solution using mostly itertools.
import itertools
positive_players = lambda : filter(lambda player: player.score >= 0, players)
loop = itertools.cycle(positive_players())
if len(list(positive_players())) <= 1:
loop = positive_players()
if len(set([p.score for p in positive_players()])) <= 1:
loop = positive_players()
Some tests:
3 players, all have score zero: stops after one loop.
3 players with scores [0, 42, 0]: continues forever
3 players with scores [-1, 42, -2]: stops after printing the one positive player.
Solution 2
Here's an alternative solution, using a generator.
def loop_players(players):
inx = 0
positive_count = 0
positive_scores = set()
while True:
p = players[inx]
inx += 1
if p.score < 0:
continue
positive_count += 1
positive_scores.add(p.score)
yield p
if inx == len(players):
inx = 0
if positive_count < 2:
break
if len(positive_scores) < 2:
break

Related

Trying to generate a conditional coin flip

So I'm a trying to create a function which first flips an unbiased coin but if the result is heads it flips a biased coin with 0.75 probability of heads. If it shows tails then the next flip is unbiased. I've tried the following code but I can only run this flow once i.e., if it's a head, then only the next one flip is biased and then the flow is returning to the top of the 'for' loop. Is there any recursion that I can do which can keep it inside the loop?
def prob1():
choices = []
for _ in range (1,501):
x = random.choice(Toss_list)
if x == 0:
y = random.choices(Toss_list, weights=(0.75,0.25))
else:
y = random.choices(Toss_list, weights=(1,1))
choices.append(x)
choices.append(y)
heads = choices.count([0])+choices.count(0)
tails = choices.count([1])+choices.count(1)
return print(f'Count of heads = {heads} and count of tails = {tails}' )
From what I understand, the biasing only depend on the previous choice.
I would simplify the code with this:
import random
tossList = ['H', 'T']
choice = 'T' # first choice will be unbiased
heads,tails = 0,0
for _ in range(500):
weights = (0.5, 0.5) if choice == 'T' else (0.75, 0.25)
choice = random.choices( tossList, weights)
if choice == ['H']:
heads += 1
else:
tails += 1
print( f'Count of heads = {heads} and count of tails = {tails}' )
You can put it in a infinite loop such as
While True:
#Do code here
Or
#Exsample:
tosses = 1
while tosses <= 10:
print(tosses )
tosses += 1
You can try this:
import random
def prob1():
choices = []
biased_flag = 0
for _ in range (1,501):
x = random.choices(Toss_list, weights=(0.75,0.25)) if biased_flag else random.choice(Toss_list)
if x == 0 and biased_flag == 0:
biased_flag = 1
# implement other rules that decide the coin to use for the next toss
choices.append(x)
heads = choices.count([0])+choices.count(0)
tails = choices.count([1])+choices.count(1)
return print(f'Count of heads = {heads} and count of tails = {tails}' )

Lottery ticket generator

I'm trying to create a lottery ticket generator. Lottery tickets in Norway can have 10 rows that you bet on. They contain each 7 numbers. The numbers you can choose from is 1-34. In total i can choose 70 numbers within this range of numbers, but i want every number to be picked two times(68) and two can be picked three times(total of 70 numbers). My program will only give me nine rows of numbers and i can't figure out what I'm doing wrong.
import random as r
# picks random number
def pickNumber():
number = r.randint(1, 34)
return number
# checks if number is in the list
def checkList(lst, number):
if not number in lst:
return True
return False
# checks the amount a number has occured
def checkNumber(lst, number):
my_set = None
if lst[number - 1] == 1:
return False
else:
lst[number - 1] += 1
my_set = set(lst)
if len(my_set) == 1:
for i in range(len(lst)):
lst[i] = 0
return True
# Run program
def main():
occured = []
for i in range(34):
occured.append(0)
ticket = []
counter = 1
while True:
row = []
while True:
number = pickNumber()
if checkList(row, number):
if checkNumber(occured, number):
row.append(number)
if len(row) >= 7:
break
ticket.append(row)
counter += 1
if counter == 10:
break
for i in range(len(ticket)):
print(ticket[i])
main()
(moving comment to answer)
Start with counter = 0. You check for 10 before processing the tenth row.

How do to Count the frequency of an item in a list?

How do I check the frequency of an item in a list and then if that item has a frequency of 4 remove all the matching items?
context:
trying to make a go fish game in python and I need to be able to check if a players hand has four matching numbers if the player's hand does then I need to remove all four of the matching items and increase there score by 1
input
score = 0
[1,2,4,3,5,6,1,1,1]
output
[2,4,3,5,6]
score += 1
the player's hand is a list of numbers.
here is the file for the game:
'''
https://github.com/StarSpace-Interactive/GoFish/tree/master/GoFish
Here's a solution:
from collections import Counter
score = 0
hand = [1,2,4,3,5,6,1,1,1]
counts = Counter(hand)
for num, count in counts.items():
if count >= 4:
hand = list(filter((num).__ne__, hand))
score += 1
print(hand)
print(score)
And the output is:
[2, 4, 3, 5, 6]
1
from collections import defaultdict
score = 0
hand = [1,2,4,3,5,6,1,1,1] # current hand
# im guessing you are doing this in a loop
d= defaultdict( int )
for card in hand:
d[card] += 1
fourList = []
for key, value in d.items():
if value >= 4:
fourList.append(key)
hand = [n for n in hand if n not in fourList]
score += len(fourList)
print(hand)
print(score)
You can do achieve your goal by Counter. For example,
from collections import Counter
mylist = [1,2,4,3,5,6,1,1,1]
counter = Counter(mylist)
Then, the counter is
Counter({
1: 4,
2: 1,
4: 1,
3: 1,
5: 1,
6: 1
})
Then, you can write a python function to update the score and the counter.
def update_score(counter, curr_score):
remove_keys = list()
# update score
for key, value in counter.items():
if value >= 4:
curr_score += 1
remove_keys.append(key)
# remove key
for key in remove_keys:
del counter[key]
return counter, curr_score
It will return the new current score and the updated counter back.
Personally, I find pandas value_count function more user-friendly than numpy.histogram suggested above. You could use it like this, assuming your hand is a List (of course this solution is simpler if the hand is a Series):
import pandas as pd
hand = [1,1,2,3,4,1,1]
cards_count = pd.Series.value_counts(hand)
# count how many times each card appears
score += (cards_count>=4).sum()
# add 1 to score for each card that repeats at least 4 times
hand = [card for card in hand if card not in cards_count.index[cards_count>=4]]
# keeps only cards that did not appear >=4 times

python - infinite coin flip that stops when number of heads = number of tails

I'm new to python and I'm trying to create a coinflip loop which will keep flipping and counting the number of flips until the number of heads = the number of tails, where it will stop and print the total number of flips it took to reach that. I'm trying to get the results in order to work on my maths coursework, but I cannot seem to figure out how to get it to stop or print the results, and when I do it prints 0. Here is the code I have so far:
import random
heads = 1
tails = sum(random.choice(['head', 'tail']) == 'tail'
count = 0
while True:
coinresult = random.randint(1, 2) if heads == tails:
break
print("The number of flips was {count}".format(count = heads + tails))
not sure what is going on with your indentation but try this:
import random
heads = 0 #initialize the count variables
tails = 0
while True:
coinresult = random.randint(1, 2) #flip coin
if coinresult == 1: #if result = 1 then increment heads counter
heads += 1
elif coinresult == 2: #if result = 2 then increment tails counter
tails += 1
if heads == tails: #check if counts are equal and break loop if they are
break
print("The number of flips was {count}".format(count = heads + tails))
import itertools as it
import random
def flips():
while True:
yield (random.getrandbits(1)<<1) - 1
def cumsum(seq):
s = 0
for i in seq:
s += i
yield s
def length(seq):
n = 0
for _ in seq:
n += 1
return n
print("The number of flips was {}".format(length(it.takewhile((0L).__cmp__, cumsum(flips())))))
I think this will be a nice implementation
import random
s = 0
iteration = 0
while True:
coin = random.sample([-1,1], 1)[0]
s = s + coin
iteration = iteration + 1
if s == 0:
break
print(iteration)

ConnectFour in python: embedding a while loop under a for loop

So I'm trying to implement a ConnectFour game in python, and I'm having some trouble with counting the pieces (from a single player) that are lined up together in a row. My code:
class ConnectFour(object):
def __init__(self):
self.row=6
self.col=7
self.board = []
#initialize the board
for arow in range(self.row):
row = []
for acol in range(self.col):
row.append(None)
self.board.append(row)
#function for counting the number of the same pieces in a row
def count_it(self, row, column, step_row, step_col):
assert row >= 0 and row < 6 and column >= 0 and column < 7
assert step_row != 0 or step_col != 0
counter1 = 0
counter2 = 0
if self.board[row][column] == None:
return 0
elif self.board[row][column] == 1:
for i in range(6):
while self.board[row + (i*step_row)][column + (i*step_col)] == 1:
counter1 += 1
return counter1
else:
for i in range(6):
while self.board[row + (i * step_row)][column + (i*step_col)] == 2:
counter2 += 1
return counter2
When I input a location and "step" in my function, I would like to get the number of pieces player 1 or player 2 has lined up but when I enter:
x= ConnectFour()
x.board[5][6] = 1
x.board[4][6] = 1
x.count_it(5,6,-1,0)
I get no output.
There is no need for that while inside for: whenever the while condition is true, it will become an infinite loop since the body of that loop does not affect the condition, it just keeps incrementing a counter forever.
One approach would be a single while loop:
while self.board[row + (counter1*step_row)][column + (counter1*step_col)] == 1:
counter1 += 1
Another approach is to leave the for loop, but i and counter1 actually serve the same purpose:
for i in range(6):
if self.board[row + (i*step_row)][column + (i*step_col)] != 1:
break
counter1 += 1
In both cases, take care of array boundaries, either by some ifs, or by placing sentinels at the border of the array.

Categories