Understanding the functioning of 'and' and 'or' - python

Here's a doubt I am facing here.
The code with its purpose in docstring is below :
This is the correct code but I am confused about the final 'if statement' in the blackjack_hand_greater_than(a,b) function.
Here, the 'if statement' is not True for total_1 > total_2 even if it is(* checked through print statements). I am not getting what is the need of adding 'or total_2 > 21' .
def blackjack_hand_greater_than(hand_1, hand_2):
"""
Return True if hand_1 beats hand_2, and False otherwise.
In order for hand_1 to beat hand_2 the following must be true:
- The total of hand_1 must not exceed 21
- The total of hand_1 must exceed the total of hand_2 OR hand_2's total must exceed 21
Hands are represented as a list of cards. Each card is represented by a string.
When adding up a hand's total, cards with numbers count for that many points. Face
cards ('J', 'Q', and 'K') are worth 10 points. 'A' can count for 1 or 11.
When determining a hand's total, you should try to count aces in the way that
maximizes the hand's total without going over 21. e.g. the total of ['A', 'A', '9'] is 21,
the total of ['A', 'A', '9', '3'] is 14.
Examples:
>>> blackjack_hand_greater_than(['K'], ['3', '4'])
True
>>> blackjack_hand_greater_than(['K'], ['10'])
False
>>> blackjack_hand_greater_than(['K', 'K', '2'], ['3'])
False
"""
print("hand1 = ",hand_1)
print("hand2 = ",hand_2)
total_1 = get_total(hand_1)
total_2 = get_total(hand_2)
print(total_1 <= 21)
print(total_1 > total_2)
if (total_1 <= 21) and (total_1>total_2 or total_2 > 21):
return True
else :
return False
def get_total(hands) :
values = {'A': 1 ,'2': 2, '3' : 3, '4' : 4 ,'5' : 5, '6' : 6,'7': 7, '8' : 8, '9' : 9, '10' : 10 , 'J' :10 , 'Q':10, 'K':10}
total = 0
aces = 0
for x in hands:
if x == 'A' :
aces += 1
total += values[x]
# print(total)
while aces>0 and total + 10 <= 21 :
total += 10
aces -=1
print(total)
return total
# Check your answer
q3.check()
The error after removing the 2nd operand of 'or', the error received is as follows :
hand1 = ['J', 'A']
hand2 = ['6']
21
6
True
True
hand1 = ['9']
hand2 = ['9', 'Q', '8', 'A']
9
28
True
False
Incorrect: Expected return value of True given hand_1=['9'], hand_2=['9', 'Q', '8', 'A'], but got False instead.

Im shared how can I solved it
1-I split the numbers and letters
2-I sorted the letter in order letter A is the last one
def sum_hand(hand):
#hand.sort(reverse=True)
letter=[]
number=[]
for n in hand:
if n.isnumeric():
number.append(n)
else:
letter.append(n)
#print('letter--',letter)
#print('number--',number)
letter.sort(reverse=True)
number.sort(reverse=True)
number.extend(letter)
hand = number
#hand = sorted(number) + sorted(letter,reverse:True)
print(hand)
#print(hand)
result_hand=0
for card in hand:
if (card == 'J' or card == 'Q' or card == 'K'):
result_hand += 10
elif (card.isdigit()):
result_hand += int(card)
else:
if(result_hand <= 10):
result_hand += 10
else:
result_hand += 1
return result_hand
def blackjack_hand_greater_than(hand_1, hand_2):
result_hand1 = sum_hand(hand_1)
result_hand2 = sum_hand(hand_2)
print('hand1-', result_hand1 , ' hand2', result_hand2)
if result_hand1 > 21:
return False
if result_hand2 > 21:
return True
if (result_hand1 > result_hand2 ):
return True
else:
return False

To win a blackjack hand, you need to be closer to 21 than the dealer but not above 21. If you're above 21 ("bust"), you lose, no matter which hand the dealer has. If you're at 21 or below, you win if the dealer busts, or if the dealer does not bust but has fewer points than you do. If we denote the score of your hand as total_1 and the total of the dealer's hand as total_2, then this is logically equivalent to if (total_1 <= 21) and (total_1>total_2 or total_2 > 21): If you bust, the first condition will be False, and since we're in a conjunction, the overall expression will evaluate to False. If you're at 21 or below, you still haven't won for sure - you need to either have more than the dealer, or the delaer must bust. That's the disjunction that forms the second term in the conjunction: total_1>total_2 or total_2 > 21.
In other words, the issue is not one of coding or of logic, but of blackjack rules.

The 'if statement':
if (total_1 <= 21) and (total_1>total_2 or total_2 > 21):
return True
else:
return False
It is saying that if (total_1 is less than or equal to) and (total_1 is greater than total_2) or (total_2 greater than 21)
for example in the the combinations of it would look like this:
if (True) and (True or False):# this would return True because `True and (True or False) make True`
return True
else:
return False

I think I may have got what you are actually wondering about:
If you let the ( ) stay as they are if (total_1 <= 21) and (total_1>total_2 or total_2 > 21):, it is strictly logical that the or condition will return True if only ONE of the operands is True ( total_2 > 21 ) and because total_1 <= 21 is also True the entire expression evaluates to True. No doubt that this is correct.
BUT ... let's remove the parentheses ( ) in the condition and see what happens. Logically the first operand for and is True, but the second is False, so ... the condition should evaluate to False, right? But running the code:
total_1 = 9; total_2 = 28
if total_1 <= 21 and total_1>total_2 or total_2 > 21:
print(True)
else :
print(False)
prints True ...
How does it come?
Python evaluates the expressions from left to the right. So first the and condition will be evaluated and gives False, BUT ... the expression has also an or, so the False from the and condition is now the operand of the or condition which second term is True, so, that the entire expression evaluates then to True.
Is THIS what you are wondering about considering chained and and or?
Check again from scratch: Expected return value of True given hand_1=['9'], hand_2=['9', 'Q', '8', 'A'], but got False instead. Then you will see that it actually can't be as you have it in mind.
Another problem with understanding can be wrong assumptions about the rules of the game as pointed out by Schnitte:
the issue is not one of coding or of logic, but of blackjack rules.

Related

Writing Program to count different letters

Im writing a program that takes in a string and 2 parameters to count the amount of letter e's that fall under the specified parameter. I get the correct count for the 1st and last possibility but not the in between 2 steps. Here is my function:
def count_letter_e(string_to_be_counted,ignore_case=True,ignore_accent=True):
"""
Return the number of times 'e' and its variations appears in a string given the parameters specified.
Parameters
----------
string_to_be_counted: str
A string containing e's that need to be counted
Returns
-------
total: int
Number of times 'e' and the specified variations appear in the given string
"""
#counting individual letters to be used to calculate totals in if statements
#Gets all counts of lowercase 'e'
e_counted=string_to_be_counted.count('e')
é_counted=string_to_be_counted.count('é')
ê_counted=string_to_be_counted.count('ê')
è_counted=string_to_be_counted.count('è')
#Get all counts of Uppercase 'E'
E_counted=string_to_be_counted.count('E')
É_counted=string_to_be_counted.count('É')
Ê_counted=string_to_be_counted.count('Ê')
È_counted=string_to_be_counted.count('È')
#Create a total variable
total=0
#check which parameters have been set
if ignore_case == True and ignore_accent == True:
total=e_counted + é_counted + ê_counted + è_counted + E_counted + É_counted + Ê_counted + È_counted
return total
total=0
elif ignore_case == True and ignore_accent == False:
total= e_counted + E_counted
return total
total=0
elif ignore_case == False and ignore_accent == True:
total= e_counted + é_counted + ê_counted + è_counted
return total
total=0
elif ignore_case == False and ignore_accent == False:
total=e_counted
return total
total=0
Here are my sentences that im testing:
sentence_1=("ThE weEk will bè frÊe until thÉre is a shÈèp that is freêd from thé pen")
sentence_2=("Thé redEyê fèlt likE a rÊal pain until I got hit in the hÊel by a freE sÈed")
sentence_3=("The frée pÊa made a gêtaway towards thé hèêl of a pÉnquin but only made it to the knEÈ")
sentence_4=("ThErÉ is a knêe that nèÊds to meÈt the queen for tÈsting of léaning pizza")
Here are the output vs the desire output for each
sentence 1: 14 v 14 (This is good)
setnence 2: 7 v 8 (This is not good)
sentence 3: 10 v 7 (This is not good)
sentence 4: 5 v 5 (This is good)
Any help would be appreciated!
Here is the improvement for your function:
def count_letter_e(string_to_be_counted,ignore_case=True,ignore_accent=True):
chars_to_count = { # chars that will be counted
# based on the "ignore_case+ignore_accent" state
(True, True):'eéêèEÉÊÈ',
(True, False):'eE',
(False, True):'eéêè',
(False, False):'e'
}
condition = (ignore_case, ignore_accent)
result = 0
for c in chars_to_count[condition]:
result += string_to_be_counted.count(c)
return result
Or just the same in a shortcut way:
def count_letter_e(string_to_be_counted,ignore_case=True,ignore_accent=True):
chars_to_count = {
(True, True):'eéêèEÉÊÈ',
(True, False):'eE',
(False, True):'eéêè',
(False, False):'e'
}
return sum([string_to_be_counted.count(c) for c in chars_to_count[(ignore_case, ignore_accent)]])
The value of this approach is not only in a significant code reduction, but also in the fact that all the settings of your function are now in one place - in the dictionary chars_to_count - and you can quickly and flexibly change them for other count-tasks.
Results:
sentence_1 = "ThE weEk will bè frÊe until thÉre is a shÈèp that is freêd from thé pen"
sentence_2 = "Thé redEyê fèlt likE a rÊal pain until I got hit in the hÊel by a freE sÈed"
sentence_3 = "The frée pÊa made a gêtaway towards thé hèêl of a pÉnquin but only made it to the knEÈ"
sentence_4 = "ThErÉ is a knêe that nèÊds to meÈt the queen for tÈsting of léaning pizza"
print(count_letter_e(sentence_1, True, True)) # 14
print(count_letter_e(sentence_2, True, False)) # 8
print(count_letter_e(sentence_3, False, True)) # 10
print(count_letter_e(sentence_4, False, False)) # 5
Note that your original code produces the same results.
And it seems that there is no error - based on the logic of the program, the desired results should be the same as in the printout above.
I like #MaximTitarenko's approach, but here's another option. It's not as DRY as it could be, but it makes the counting logic very clear.
def count_letter_e(string, ignore_case=True, ignore_accent=True):
if ignore_case and ignore_accent:
counts = [
string.count('e'),
string.count('é'),
string.count('ê'),
string.count('è'),
string.count('E'),
string.count('É'),
string.count('Ê'),
string.count('È'),
]
elif ignore_case and not ignore_accent:
counts = [
string.count('e'),
string.count('E'),
]
elif not ignore_case and ignore_accent:
counts = [
string.count('e'),
string.count('é'),
string.count('ê'),
string.count('è'),
]
elif not ignore_case and not ignore_accent:
counts = [
string.count('e'),
]
return sum(counts)
sentence_1 = 'ThE weEk will bè frÊe until thÉre is a shÈèp that is freêd from thé pen'
sentence_2 = 'Thé redEyê fèlt likE a rÊal pain until I got hit in the hÊel by a freE sÈed'
sentence_3 = 'The frée pÊa made a gêtaway towards thé hèêl of a pÉnquin but only made it to the knEÈ'
sentence_4 = 'ThErÉ is a knêe that nèÊds to meÈt the queen for tÈsting of léaning pizza'
print(count_letter_e(sentence_1, True, True))
print(count_letter_e(sentence_2, True, False))
print(count_letter_e(sentence_3, False, True))
print(count_letter_e(sentence_4, False, False))

Check whether the last three flips were all heads or all tails in Python

So I have a challenge, in which I have to create a programme that simulates a coin flip, by generating a random number corresponding to either heads or tails. When three simultaneous 'H' (heads) or 'T' (tails) are outputted my programme should stop. I have tried to get this to work, here is my code so far:
import random
active=True
list1 = []
b = 0
while active:
l=random.randint(0,1)
b += 1
i='a'
if l == 0:
i = 'H'
else:
i = 'T'
list1.append(i)
if list1[:-3] is ['H','H','H']:
active = False
elif list1[:-3] is ['T','T','T']:
active = False
else:
active = True
print(list1),
It seems that the only thing not working is the part that checks for 3 corresponding heads or tails, does anybody know how I may code this part correctly?
The problem, as was mentioned in the comments above, is that list1[:-3] should be list1[-3:] (getting the last three elements of the list, instead of everything up to the last three elements) and comparisons should be done with == instead of is. The adjusted program would be:
import random
active=True
list1 = []
b = 0
while active:
l=random.randint(0,1)
b += 1
i='a'
if l == 0:
i = 'H'
else:
i = 'T'
list1.append(i)
if list1[-3:] == ['H','H','H']:
active = False
elif list1[-3:] == ['T','T','T']:
active = False
else:
active = True
print(list1)
However, I think it might also be useful to see a condensed approach at writing the same program:
import random
flips = []
while flips[-3:] not in (['H'] * 3, ['T'] * 3):
flips.append(random.choice('HT'))
print(flips)
You can do this by tracking a running list of flips. If the new flip is the same as the previous, append it to the list. Else, if the new flip is not the same as the previous, clear the list and append the new flip. Once the length reaches 3, break from the while loop:
import random
flipping = True
flips = []
flip_status = {0: "H", 1: "T"}
current_flip = None
while flipping:
current_flip = flip_status[random.randint(0,1)]
print current_flip
if len(flips) == 0:
flips.append(current_flip)
else:
if current_flip == flips[-1]:
flips.append(current_flip)
if len(flips) == 3:
break
else:
flips = []
flips.append(current_flip)
print "Flips: " + str(flips)
Here's a sample run:
T
T
H
T
T
H
T
H
H
T
T
T
Flips: ['T', 'T', 'T']

Returned result is false with numpy conditions

I wrote a little script in order to return a list of 'characters' from a list of values :
List of values :
11
11
14
6
6
14
My script :
# -*- coding:utf-8 -*-
import numpy as np
data = np.loadtxt('/Users/valentinjungbluth/Desktop/produit.txt',
dtype = int)
taille = len(data)
for j in range (0, taille) :
if data[j] == 1 or 2 or 3 or 11 or 12 or 13 :
print 'cotisation'
if data[j] == 14 :
print 'donation'
else :
print 'part'
What I need to get :
'cotisation'
'cotisation'
'donation'
'part'
'part'
'donation'
What I get :
cotisation
part
cotisation
part
cotisation
donation
I don't see where I made an error ..
If someone could read my script and maybe correct him ?
Thank you
Try:
for j in range(0, taille):
if data[j] in {1, 2, 3, 11, 12, 13}:
print ("cotisation")
elif data[j] == 14:
print ("donation")
else:
print ("part")
There are a couple issues here:
if x == 1 or 2 or 3 or ... does not do what you are expecting.
Each clause is evaluated independently, so python does not know you are implying if x == 1 or x == 2 or x == 3, etc. It instead interprets this as if x == 1 or if 2 or if 3 ... if 2 and the like is actually a sensical if statement in python and is basically tantamount to asking if True (all non-zero integer values have a "truthiness" of True). So your statement is really equivalent to if data[j] == 1 or True or True or True or True, which reduces to if True. In other words, the condition is always satisfied regardless of the value. What you probably meant was:
if data[j] == 1 or data[j] == 2 or data[j] == 3 or data[j] == 11 ...
Your if-else construction has two blocks when one is intended
Currently boils down to something like the following in pseudocode:
if some condition:
print 'something'
now regardless of the first condition, if some other disjoint condition:
print 'something else'
otherwise:
print 'does not match other condition'
In other words, by using two ifs, the second if block, of which the else is a part, is treated as completely independent of the first if. So cases that satisfy the first condition could also satisfy the else, which is sounds like is not what you wanted as each character should print exactly once. If you want it to be 3 disjoint cases, you need to use elif instead so it is all considered part of a single block:
E.g.
if condition:
print 'something'
elif other condition:
print 'something else'
else:
print 'does not match EITHER of the two above condtions'
Scimonster point out your 1st issue in the code, you need elif for the second if.
The 2nd issue is the or part, your if condition is being intepret as
if (data[j] == 1) or 2 or 3 or 11 or 12 or 13
You could fixed them as below
if data[j] in [1, 2, 3, 11, 12, 13] :
print 'cotisation'
elif data[j] == 14 :
print 'donation'
else :
print 'part'
if data[j] == 1 or 2 or 3 or 11 or 12 or 13 :
print 'cotisation'
if data[j] == 14 :
print 'donation'
else :
print 'part'
You have two separate ifs here, and one has an else. They should all flow together, so the second should be elif.

Finding the length of longest repeating?

I have tried plenty of different methods to achieve this, and I don't know what I'm doing wrong.
reps=[]
len_charac=0
def longest_charac(strng)
for i in range(len(strng)):
if strng[i] == strng[i+1]:
if strng[i] in reps:
reps.append(strng[i])
len_charac=len(reps)
return len_charac
Remember in Python counting loops and indexing strings aren't usually needed. There is also a builtin max function:
def longest(s):
maximum = count = 0
current = ''
for c in s:
if c == current:
count += 1
else:
count = 1
current = c
maximum = max(count,maximum)
return maximum
Output:
>>> longest('')
0
>>> longest('aab')
2
>>> longest('a')
1
>>> longest('abb')
2
>>> longest('aabccdddeffh')
3
>>> longest('aaabcaaddddefgh')
4
Simple solution:
def longest_substring(strng):
len_substring=0
longest=0
for i in range(len(strng)):
if i > 0:
if strng[i] != strng[i-1]:
len_substring = 0
len_substring += 1
if len_substring > longest:
longest = len_substring
return longest
Iterates through the characters in the string and checks against the previous one. If they are different then the count of repeating characters is reset to zero, then the count is incremented. If the current count beats the current record (stored in longest) then it becomes the new longest.
Compare two things and there is one relation between them:
'a' == 'a'
True
Compare three things, and there are two relations:
'a' == 'a' == 'b'
True False
Combine these ideas - repeatedly compare things with the things next to them, and the chain gets shorter each time:
'a' == 'a' == 'b'
True == False
False
It takes one reduction for the 'b' comparison to be False, because there was one 'b'; two reductions for the 'a' comparison to be False because there were two 'a'. Keep repeating until the relations are all all False, and that is how many consecutive equal characters there were.
def f(s):
repetitions = 0
while any(s):
repetitions += 1
s = [ s[i] and s[i] == s[i+1] for i in range(len(s)-1) ]
return repetitions
>>> f('aaabcaaddddefgh')
4
NB. matching characters at the start become True, only care about comparing the Trues with anything, and stop when all the Trues are gone and the list is all Falses.
It can also be squished into a recursive version, passing the depth in as an optional parameter:
def f(s, depth=1):
s = [ s[i] and s[i]==s[i+1] for i in range(len(s)-1) ]
return f(s, depth+1) if any(s) else depth
>>> f('aaabcaaddddefgh')
4
I stumbled on this while trying for something else, but it's quite pleasing.
You can use itertools.groupby to solve this pretty quickly, it will group characters together, and then you can sort the resulting list by length and get the last entry in the list as follows:
from itertools import groupby
print(sorted([list(g) for k, g in groupby('aaabcaaddddefgh')],key=len)[-1])
This should give you:
['d', 'd', 'd', 'd']
This works:
def longestRun(s):
if len(s) == 0: return 0
runs = ''.join('*' if x == y else ' ' for x,y in zip(s,s[1:]))
starStrings = runs.split()
if len(starStrings) == 0: return 1
return 1 + max(len(stars) for stars in starStrings)
Output:
>>> longestRun("aaabcaaddddefgh")
4
First off, Python is not my primary language, but I can still try to help.
1) you look like you are exceeding the bounds of the array. On the last iteration, you check the last character against the character beyond the last character. This normally leads to undefined behavior.
2) you start off with an empty reps[] array and compare every character to see if it's in it. Clearly, that check will fail every time and your append is within that if statement.
def longest_charac(string):
longest = 0
if string:
flag = string[0]
tmp_len = 0
for item in string:
if item == flag:
tmp_len += 1
else:
flag = item
tmp_len = 1
if tmp_len > longest:
longest = tmp_len
return longest
This is my solution. Maybe it will help you.
Just for context, here is a recursive approach that avoids dealing with loops:
def max_rep(prev, text, reps, rep=1):
"""Recursively consume all characters in text and find longest repetition.
Args
prev: string of previous character
text: string of remaining text
reps: list of ints of all reptitions observed
rep: int of current repetition observed
"""
if text == '': return max(reps)
if prev == text[0]:
rep += 1
else:
rep = 1
return max_rep(text[0], text[1:], reps + [rep], rep)
Tests:
>>> max_rep('', 'aaabcaaddddefgh', [])
4
>>> max_rep('', 'aaaaaabcaadddddefggghhhhhhh', [])
7

Python "if" statement ignored [duplicate]

This question already has answers here:
Why does "a == x or y or z" always evaluate to True? How can I compare "a" to all of those?
(8 answers)
Closed 6 months ago.
I'm triggering loop within loop in Python, if one of the multiple conditions ("or") is met.
The script seems to skip the "if" statement and enters inner loop without meeting required conditions.
Code
# Begin TestCase
# Main logic: execute RemoteController macro, if expected state == true, set 'Success', else: Fail
for macroname_n in range (32):
handler("RemoteController", "SET", "[{0}_{1}_{2}]".format(testcase, macroname_n, platform), "")
result = pbc_json(disk, testcase_area, testcase, platform, filename_n, coord_n)
filename_n += 1
coord_n += 1
if macroname_n == 15 or 20:
success_counter = 0
for extra_loop in range(15):
handler("RemoteController", "SET", "\"down 4\"", "")
result = pbc_json(disk, testcase_area, testcase, platform, filename_n, coord_n)
filename_n += 1
if result >= 50:
success_counter += 1
if success_counter <> 15:
result = 0
Thanks in advance!
This line does not do what you want:
if macroname_n == 15 or 20:
This is parsed as follows:
if (macroname_n == 15) or (20):
Since 20 is always true in a boolean context, the statement is always true. What you actually want is this:
if macroname_n in (15, 20):
20 always evaluates to true in a boolean context. Therefore, macroname_n == 15 or 20 is always true.
You probably want to write:
if macroname_n == 15 or macroname_n == 20:
success_counter = 0
# ...
if macroname_n == 15 or 20:
should be:
if macroname_n == 15 or macroname_n == 20:
otherwise will it always read 20 as true.

Categories

Resources