counting instances of a class based on attributes - python

Counting the number of instances of a specific attribute value
I have created a class, named: bird. Each instance of that class has two attributes:
creed (which can be either "C" or "D" in value), and
life (which starts with a value of 100, and changes as the program executes).
The program simulates random encounters of two live birds, the birds change the value of life after each encounter. Once reaching 0, the bird is excluded from further interactions (i.e. dead).
After several iterations, I wish to know how many birds of each creed are "alive".
import random
class Bird:
Doves = 100
Crows = 100
# Initializer / Instance Attributes
def __init__(self, creed, life):
self.creed = creed
self.life = life
def slct_parties():
first = random.randint(0, (Bird.Crows + Bird.Doves -1))
second = random.randint(0, (Bird.Crows + Bird.Doves -1))
while first == second or population[first].life < 1 or population[second].life < 1:
first = random.randint(0, (Bird.Crows + Bird.Doves - 1))
second = random.randint(0, (Bird.Crows + Bird.Doves - 1))
return first, second
# initiating Population
population = []
for bird in range(0, Bird.Crows):
population.append(Bird('C', 100))
for bird in range(0, Bird.Doves):
population.append(Bird('D', 100))
for x in range(1, 1000):
Contest = slct_parties()
l1 = population[Contest[0]].life
l2 = population[Contest[1]].life
# battle
if population[Contest[0]].creed != population[Contest[0]].creed:
if population[Contest[0]].creed == 'D':
population[Contest[0]].life += 1
population[Contest[1]].life += 1
else:
population[Contest[0]].life += -5
population[Contest[1]].life += -10
elif population[Contest[0]].creed == 'C':
population[Contest[0]].life += 5
population[Contest[1]].life += -20
else:
population[Contest[0]].life += -20
population[Contest[1]].life += 5
print("The battle was between {} number {} with {} life, and {} number {} with {} life"
.format(population[Contest[0]].creed, Contest[0], population[Contest[0]].life, population[Contest[1]].creed,
Contest[1], population[Contest[1]].life))
After 1,000 battles, some birds have died. How many birds? Which creed?
Short answer
single liner (Thanks to Carcigenicate)
dead_crows = len([bird for bird in population if bird.creed == "c" and bird.life <= 0])
function (Thanks to zixuan)
def DeadConter(crd):
dead = 0
for bird in population:
if bird.life <= 0 and bird.creed == crd:
dead += 1
else:
pass
return dead

You can also define 2 values that both start at 0 before the definition of the class that count how many birds are dead, like adding one cDead += 1 when a bird becomes "dead". After the 1000 battles, subtract 100 from the first value and subtract 100 from the second value. You get then, how many bird of each creed are alive. You can also count how many birds of each creed are dead, like this.
import random
c_dead = 0
d_dead = 0
class Bird:
Doves = 100
Crows = 100
# Initializer / Instance Attributes
def __init__(self, creed, life):
self.creed = creed
self.life = life
def slct_parties():
first = random.randint(0, (Bird.Crows + Bird.Doves -1))
second = random.randint(0, (Bird.Crows + Bird.Doves -1))
while first == second or population[first].life < 1 or population[second].life < 1:
first = random.randint(0, (Bird.Crows + Bird.Doves - 1))
second = random.randint(0, (Bird.Crows + Bird.Doves - 1))
return first, second
# initiating Population
population = []
for bird in range(0, Bird.Crows):
population.append(Bird('C', 100))
for bird in range(0, Bird.Doves):
population.append(Bird('D', 100))
for x in range(1, 1000):
Contest = slct_parties()
l1 = population[Contest[0]].life
l2 = population[Contest[1]].life
# battle
if population[Contest[0]].creed != population[Contest[0]].creed:
if population[Contest[0]].creed == 'D':
population[Contest[0]].life += 1
population[Contest[1]].life += 1
else:
population[Contest[0]].life += -5
population[Contest[1]].life += -10
elif population[Contest[0]].creed == 'C':
population[Contest[0]].life += 5
population[Contest[1]].life += -20
else:
population[Contest[0]].life += -20
population[Contest[1]].life += 5
for bird in population:
if bird.life <= 0:
if bird.creed == "C":
c_dead += 1
elif bird.creed == "D":
d_dead += 1
else:
print("Dead birds failed to count") # should never happen, this is a good check for bugs
print("The battle was between {} number {} with {} life, and {} number {} with {} life"
.format(population[Contest[0]].creed, Contest[0], population[Contest[0]].life, population[Contest[1]].creed,
Contest[1], population[Contest[1]].life))
#print dead birds here
print("Number of alive birds")
print(str(100-c_dead) + ": Doves" + " " + str(100-d_dead) + ": Crows")
I added the else line because this code is untested, I don't know if there are any bugs.
EDIT: The code has been tested now and I've changed a few lines to get it working.

Try adding an external variable before the init, initialize it at zero and increment its value by one in the init (+1 for every instance).
Then create a function that checks if a bird has died or not and if so, decrease the value of the variable by one

If you want to count them after the fact and not keep running tallies, just iterate over the population:
c_dead = 0
d_dead = 0
for bird in population:
if bird.life <= 0: # The bird is dead
if bird.creed == "c":
c_dead += 1 # Figure out what creed it is and increment a counter
else
d_dead += 1
This could be cleaned up using a dictionary or some other container, but I think this is the simplest way to show the idea.
In the comments, you noted that you were looking for something along the lines of count(population, creed="c", life>0). That can't be achieved exactly, but you can use a list comprehension to filter out the birds you don't want to count.
c_dead = len([bird for bird in population if bird.creed == "c" and bird.life <= 0])
d_dead = len([bird for bird in population if bird.creed == "d" and bird.life <= 0])
I wouldn't recommend this way though. This requires two full iterations of the population, whereas the first only requires one. If this operation was frequent, and the populations was large, it could cause performance problems.

Related

minimax algorithm not working in a two-player turn-based game

I am trying to use minimax algo to find a best move for a game.
The game is 2 players take turns to pick a number from a pile [0,1,2,,,8]
Winning Condition: player wins the game if the player contains three numbers and their sum is 14.
The initial game state is given by the argument like:
4 1 2 3 4
The first number indicate the total length and the following numbers are the numbers taken by player each turn. In this example the player A has [1,3] and player B has [2,4]
My problem is the algo can't give the correct answer:
Like when the input is 4 4 1 7 8 my program cannot gives the correct move: it takes 0 not 3 for next move.
import sys
import math
totalMoves = int(sys.argv[1])
pile = [0, 1, 2, 3, 4, 5, 6, 7, 8]
# who are u
you = []
opponent = []
# cards in hand
playerA = []
playerB = []
# get all the cards into hand
for i in range(totalMoves):
# save card into playerB
if i % 2 != 0:
playerB.append(int(sys.argv[i+2]))
# save card into playerA
if i % 2 == 0:
playerA.append(int(sys.argv[i+2]))
# remove sent card in list
pile.remove(int(sys.argv[i+2]))
# identify which player you are
if totalMoves % 2 == 0:
you = playerA
opponent = playerB
else:
you = playerB
opponent = playerA
def find3Numbers(player): # calcluate the card in hand is equal to 14
arr_size = len(player)
if (len(player) >= 3):
for i in range(0, arr_size-2):
for j in range(i + 1, arr_size-1):
for k in range(j + 1, arr_size):
if (player[i] + player[j] + player[k] == 14):
return True
else:
return False
def isNumberLeft(board):
if (len(board) == 0):
return False
else:
return True
def evaluate(player, oppo):
if (find3Numbers(player) == True):
return 10
elif (find3Numbers(oppo) == True):
return -10
else:
return 0
def minimax(board, player, oppo, depth, isMax):
score = evaluate(player, oppo)
if (score == 10):
return score
if (score == -10):
return score
if (isNumberLeft(board) == False):
return 0
if (isMax):
best = -math.inf
for card in board:
player.append(card)
board.remove(card)
best = max(best, minimax(board, player, oppo, depth+1, not isMax))
board.append(card)
player.remove(card)
return best
else:
best = +math.inf
for card in board:
oppo.append(card)
board.remove(card)
best = min(best, minimax(board, player, oppo, depth+1, not isMax))
board.append(card)
oppo.remove(card)
return best
def bestMove():
bestScore = -math. inf
bestNum = -math.inf
for card in pile:
you.append(card)
pile.remove(card)
score = minimax(pile, you, opponent, 0, False)
pile.append(card)
you.remove(card)
if (bestScore < score):
bestNum = card
bestScore = score
return bestNum
you.append(bestMove())

How to sort multiple integers without making them array or list in Python

Im just learning programming and I ve picked up Python for start. I have this task to make:
Simulate game with 4 players. Each player is throwing a dice until 6 is thrown, then next player proceedes to throw. Player who throws 6 in most tries is winner. Program should write who player was throwing and how many tries did he get. If 2 players throw 6 on same count of tries the player who was throwing earlier wins.
Task is from pythonladies BTW, currently im stuck sorting tries in descending order and picking the winner. I dont want to put in many conditions (if, ifelse) and also Im on chapter 5 and I didnt learn arrays/lists so I want to make it withou using it. Here is my code so far:
hrac means player
pokusy means tries
from random import randrange, random
hrac1 = 0
pokusy1 = 0
hrac2 = 0
pokusy2 = 0
hrac3 = 0
pokusy3 = 0
hrac4 = 0
pokusy4 = 0
while hrac4 != 6:
while True:
if hrac1 != 6:
hrac1 = randrange(1, 7)
pokusy1 = pokusy1 + 1
print("Hráč 1 hodil: ", hrac1, " Toto bol jeho: ",pokusy1," pokus")
else:<br>
break
while True:<br>
if hrac2 != 6:
hrac2 = randrange(1, 7)
pokusy2 = pokusy2 + 1
print("Hráč 2 hodil: ", hrac2, " Toto bol jeho: ",pokusy2," pokus")
else:
break
while True:<br>
if hrac3 != 6:
hrac3 = randrange(1, 7)
pokusy3 = pokusy3 + 1
print("Hráč 3 hodil: ", hrac3, " Toto bol jeho: ",pokusy3," pokus")
else:
break
while True:
if hrac4 != 6:
hrac4 = randrange(1, 7)
pokusy4 = pokusy4 + 1
print("Hráč 4 hodil: ", hrac4, " Toto bol jeho: ",pokusy4," pokus")
else:
break
Also if you have and idea to simplify this code Id be glad :)
As you don't know about the lists and arrays then i can tell you the solution from old times when i was a C++ programmer :)
lets imagine these sample numbers for the number of tries:
pokusy1 = 1
pokusy2 = 2
pokusy3 = 3
pokusy4 = 4
temp = 0
then you just need to compare them in this way:
if(pokusy1 > pokusy2):
temp = pokusy1
else:
temp = pokusy2
if(pokusy3 > temp):
temp = pokusy3
if(pokusy4 > temp):
temp = pokusy4

Mastermind Python coding

Ok I have a feeling that this is a simple simple issue but I have been staring at this code for about 10 hours now.
The issue I am having is in mastermind is that once I get it to recognize that I have the correct colors in the right spot I can get it to display the right spots with X and the wrong spots with O. I need to be able to convert that so instead of X and O I need it to tell the user that he/she has 2 blacks and one white
For example: The secret code is RGYB The user enters RGOY so then Python relays "You have 2 blacks(The R and G spots) and one 1 White (The Y because it's the right color just in the wrong index) As of right now I got it to display X for the right color in the right spot and anything else it is an O
I will post what I have been working with now but today I am at my wit's end
https://pastebin.com/HKK0T7bQ
if correctColor != "XXXX":
for i in range(4):
if guess[i] == tempCode[i]:
correctColor += "X"
if guess[i] != tempCode[i] in tempCode:
correctColor += "O"
print (correctColor + "\n")
if correctColor == "XXXX":
if attempts == 1:
print ("You think you are sweet because you got it right on the first try? Play me again!")
else:
print ("Well done... You needed " + str(attempts) + " attempts to guess.")
game = False
A few comments
X and O
you use X and 0 to denote the success, it will be easier and faster to use a list or tuple or booleans for this, that way you can use sum() to count how many colors and locations were correct. Then whether you represent that with X and O or red and white pins is a matter for later
compartmentalization
Your game logic (guess input, input validation, do you want to continue, etc) is mixed with the comparison logic, so it would be best to separate the different functions of your program into different methods.
This is an fineexample to introduce object oriented programming, but is so simple it doesn't need OO, but it can help. What you need is a method which takes a series of colours and compares it to another series of colours
Standard library
Python has a very extended standard library, so a lot of stuff you want to do probably already exists
Correct colours
to count the number of letters which occur in 2 strings, you can use collections.Counter
guess = "RGOY "
solution = "RGYB"
a = collections.Counter(guess)
b = collections.Counter(solution)
a & b
Counter({'G': 1, 'R': 1, 'Y': 1})
correct_colours = sum((a & b).values())
3
So the user guessed 3 colours correctly
Correct locations
can be solved with an easy list comprehension
[g == s for g, s in zip(guess, solution)]
[True, True, False, False]
sum(g == s for g, s in zip(guess, solution))
2
so the used put 2 colours on the correct location
This is a MasterMind I made in Python. Hope you like it and it helped you! :)
import random
import time
from tkinter import *
def select_level():
global level
level = level_selector.get()
root.destroy()
root = Tk()
level_selector = Scale(root, from_=1, to=3, tickinterval=1)
level_selector.set(0)
level_selector.pack()
Button(root, text="Select a difficulty level", command=select_level).pack()
mainloop()
cpc_1_digit = 0
cpc_2_digit = 0
cpc_3_digit = 0
cpc_4_digit = 0
p_1_digit = 0
p_2_digit = 0
p_3_digit = 0
p_4_digit = 0
correct_correct = 0
correct_wrong = 0
chances = 0
if level == 1:
chances = 15
elif level == 2:
chances = 10
else:
chances = 7
cpc_1_digit = random.randint(0, 9)
while cpc_2_digit == cpc_1_digit or cpc_2_digit == cpc_3_digit or cpc_2_digit ==
cpc_4_digit:
cpc_2_digit = random.randint(0, 9)
while cpc_3_digit == cpc_1_digit or cpc_3_digit == cpc_2_digit or cpc_3_digit ==
cpc_4_digit:
cpc_3_digit = random.randint(0, 9)
while cpc_4_digit == cpc_1_digit or cpc_4_digit == cpc_2_digit or cpc_4_digit ==
cpc_3_digit:
cpc_4_digit = random.randint(0, 9)
while chances > 0:
correct_correct = 0
correct_wrong = 0
answer = input("Enter a four-digit number with different digits (e.g 1476): ")
p_1_digit = int(answer[0])
p_2_digit = int(answer[1])
p_3_digit = int(answer[2])
p_4_digit = int(answer[3])
if p_1_digit == cpc_1_digit:
correct_correct = int(correct_correct) + 1
elif p_1_digit == cpc_2_digit or p_1_digit == cpc_3_digit or p_1_digit ==
cpc_4_digit:
correct_wrong = int(correct_wrong) + 1
else:
pass
if p_2_digit == cpc_2_digit:
correct_correct = correct_correct + 1
elif p_2_digit == cpc_1_digit or p_2_digit == cpc_3_digit or p_2_digit ==
cpc_4_digit:
correct_wrong = int(correct_wrong) + 1
else:
pass
if p_3_digit == cpc_3_digit:
correct_correct = int(correct_correct) + 1
elif p_3_digit == cpc_1_digit or p_3_digit == cpc_2_digit or p_3_digit ==
cpc_4_digit:
correct_wrong = int(correct_wrong) + 1
else:
pass
if p_4_digit == cpc_4_digit:
correct_correct = int(correct_correct) + 1
elif p_4_digit == cpc_1_digit or p_4_digit == cpc_3_digit or p_4_digit ==
cpc_2_digit:
correct_wrong = int(correct_wrong) + 1
else:
pass
print("")
if int(correct_correct) == 4:
print("Congratsulations! You found the computer's number!")
break
elif int(correct_wrong) > 0 or int(correct_correct) >= 1 and int(correct_correct)
< 4:
print("You got " + str(correct_correct) + " correct digit(s) in the correct
place, and " + str(correct_wrong) + " correct digit(s) but in wrong place.")
elif int(correct_correct) == 0 and int(correct_wrong) == 0:
print("You didn't guess any number, try again!")
else:
raise Exception("CheckError: line 69, something went wrong with the
comparings.")
exit()
print("")
chances = chances - 1
if chances == 0:
print("You lost... The secret number was " + str(cpc_1_digit) + str(cpc_2_digit)
+ str(cpc_3_digit) + str(cpc_4_digit) + ". Try again by rerunning the program.")
time.sleep(4)

Dice Poker Scoring System (Function producing NoneType)

So in my coding class we are required to make a "Dice Poker" game. We need to implement a scoring system, however, mine keeps returning a "None", therefore causing issues when I want to add the accumulated score to the base score of 100, since NoneTypes and integers can not be added. I'm aware that I need to fix whatever is causing the None, but I'm not sure how. I believe the problem could be in the "scoring" function, but perhaps it is more lurking in the later parts (After the #Choosing Last Roll or #Scoring output comments) of the function "diceGame". I'm very new to coding, and after hours of looking at this thing I'm not really sure what I'm looking at anymore. Thank you so much for your help!
Text-based dice game
from random import randint
def rollFiveDie():
allDie = []
for x in range(5):
allDie.append(randint(1,6))
return allDie
def outputUpdate(P, F):
print(P)
print(F)
def rollSelect():
rollSelected = input("Which die would you like to re-roll? (Choose 1, 2, 3, 4 and/or 5 from the list) ")
print(" ")
selectList = rollSelected.split()
return selectList
def rollPicked(toRollList, diceList):
for i in toRollList:
diceList[int(i) - 1] = randint(1,6)
def scoring(dList):
counts = [0] * 7
for value in dList:
counts[value] = counts[value] + 1
if 5 in counts:
score = "Five of a Kind", 30
elif 4 in counts:
score = "Four of a Kind", 25
elif (3 in counts) and (2 in counts):
score = "Full House", 15
elif 3 in counts:
score = "Three of a Kind", 10
elif not (2 in counts) and (counts[1] == 0 or counts[6] == 0):
score = "Straight", 20
elif counts.count(2) == 2:
score = "Two Pair", 5
else:
score = "Lose", 0
return score
def numScore(diList):
counts = [0] * 7
for v in diList:
counts[v] = counts[v] + 1
if 5 in counts:
finScore = 30
elif 4 in counts:
finScore = 25
elif (3 in counts) and (2 in counts):
finScore = 15
elif 3 in counts:
finScore = 10
elif not (2 in counts) and (counts[1] == 0 or counts[6] == 0):
finScore = 20
elif counts.count(2) == 2:
finScore = 5
else:
finScore = 0
return finScore
def printScore(fscore):
print(fscore)
print(" ")
def diceGame():
contPlaying = True
while contPlaying:
playPoints = 30
if playPoints > 9:
playPoints -= 10
else:
print("No more points to spend. Game Over.")
contPlaying = False
playing = input("Would you like to play the Dice Game? (Answer 'y' or 'n'): ")
print(' ')
if playing == 'y':
#First Roll
fiveDie = rollFiveDie()
outputUpdate("Your roll is...", fiveDie)
#Choosing Second Roll/Second Roll execution
pickDie = input("Which die would you like to re-roll? (Choose 1, 2, 3, 4 and/or 5 from the list) ")
print(" ")
pickDie = pickDie.split()
rollPicked(pickDie, fiveDie)
outputUpdate("Your next roll is...", fiveDie)
#Choosing Last Roll
pickDie = rollSelect()
rollPicked(pickDie, fiveDie)
outputUpdate("Your final roll is...", fiveDie)
#Scoring output
scoring(fiveDie)
finalScore = numScore(fiveDie)
playPoints += finalScore
print(playPoints)
else:
contPlaying = False
def main():
diceGame()
main()

simplegui indentation error: SyntaxError: bad input (' ')

I'm doing a mini-project on Coursera and I can run most parts of my code. However there's an error in the critical part about the game's match or not checking.
# implementation of card game - Memory
import simplegui
import random
# helper function to initialize globals
def new_game():
global turns, state, pairs, cards
turns = 0
state = 0
pairs = []
cards = range(9) * 2
random.shuffle(cards)
# define event handlers
def mouseclick(pos):
# add game state logic here
global turns, state, pairs
pointed = pos[0] // 50
if pointed in pairs:
pass
else:
if state == 0:
state = 1
pairs.append(pointed)
elif state == 1:
state = 2
turns += 1
label.set_text('Turns =' + str(turns))
pairs.append(pointed)
# if cards[pairs[-2]] == cards[[pairs[-1]]:
# flag = True
# else:
# flag = False
else:
state = 1
if flag == False:
del pairs[-2:]
pairs.append(pointed)
# cards are logically 50x100 pixels in size
def draw(canvas):
for n in range(1, 16):
canvas.draw_line((n * 50, 0), (n * 50, 100), 1, 'Green')
for n in pairs:
canvas.draw_line((n * 50 + 25, 0), (n * 50 + 25, 100), 50, 'White')
for n in pairs:
canvas.draw_text(str(cards[n]), (n * 50 + 15, 65), 50, 'Black')
# create frame and add a button and labels
frame = simplegui.create_frame("Memory", 800, 100)
frame.set_canvas_background('Red')
frame.add_button("Reset", new_game)
label = frame.add_label("Turns = 0")
# register event handlers
frame.set_mouseclick_handler(mouseclick)
frame.set_draw_handler(draw)
# get things rolling
new_game()
frame.start()
# Always remember to review the grading rubric
I commented out Line 31 to 34 and that's the part where I have a problem. The console keeps telling me Line 31: SyntaxError: bad input (' ') but I think the indentation is correctly made.
Please help me figure out why it's a 'bad input', thanks a lot!
Update:
Thanks to Russell's help, this function works now.
# define event handlers
def mouseclick(pos):
# add game state logic here
global turns, state, pairs, flag
pointed = pos[0] // 50
if pointed in pairs:
pass
else:
if state == 0:
state = 1
pairs.append(pointed)
elif state == 1:
state = 2
turns += 1
label.set_text('Turns =' + str(turns))
pairs.append(pointed)
if cards[pairs[-2]] == cards[pairs[-1]]:
flag = True
else:
flag = False
else:
state = 1
if flag == False:
del pairs[-2:]
pairs.append(pointed)
Your if statement is indented too far.
elif state == 1:
state = 2
turns += 1
label.set_text('Turns =' + str(turns))
pairs.append(pointed)
if cards[pairs[-2]] == cards[pairs[-1]]:
flag = True
else:
flag = False
else:
state = 1
if flag == False:
del pairs[-2:]
pairs.append(pointed)

Categories

Resources