Python: Code is ignoring the if and else


K

kevin4fong

I'm trying to create a game of Go Fish in Python. But I've stumbled onto a little problem that I can't seem to figure out how to deal with.

There is a human player (player 0) and three computer players (from 1-3). The human player goes first and chooses a target player. And then a card rank (for example, the player could target player two and choose jacks, then the computer would have to give the player all its jacks).

What I have so far is below but the problem I'm having is right at the bottom of the code. So far, the code generates a deck, creates hands for every player, and then shows the player his/her cards. Then the player is asked which computer player he/she wants to target as well as the rank of cards.

The problem I'm having is with the last set of lines (the def player_0_hitman) at the bottom of the code. Any help would be much appreciated. There are basically three issues I'm having problems with.

Basically, my code is ignoring the if's and else's. I don't get why. Everything appears to be positioned correctly, but for some odd reason, even after an if, the program also runs the else as well.

the "hit" is not being returned. Even though in the definition, I have the hit set to hit = hit - 1 for the last else, it still reruns the wholedefinition again as if it the hit was 1

I'm trying to use the count line to count how many cards are being transferred so the program will tell the player how many cards he gains when hegets a successful guess but I only get a statement saying I got 1 card each time no matter what (whether I get no cards or I get more than one).

I understand the basics of what I need to do but I can't seem to get a working code for this. I've tried changing the "for" to "if" but I get all sorts of errors so I don't think that will work. Then I tried converting "hit" into another code before entering the definition, changing it while inside,then converting it back before returning it but that also seems to do nothing, and I still get the same issues.


CODE:

import random

def SetDeck():
suitList = ["s", "c", "d", "h"]
rankList = ["a", "2", "3", "4", "5", "6", "7", "8", "9", "t", "j", "q", "k"]
deck = []
for suite in range(4):
for rank in range(13):
deck.append(rankList[rank]+suitList[suite])
return deck

def Shuffle(deck):
nCards = len(deck)
for i in range(nCards):
j = random.randint(i,nCards-1)
deck, deck[j] = deck[j], deck
return deck

def GetTopCard(shuffledDeck):
return shuffledDeck.pop(0)

def DealInitialCards(nPlayers,nCards,shuffledDeck):
playersCards = [["" for j in range(nCards)] for i in range(nPlayers)]
for j in range(nCards):
for i in range(nPlayers):
playersCards[j] = GetTopCard(shuffledDeck)
return playersCards

def Sort(cards):
rankString = "a23456789tjqk"
swapped=True
while swapped:
swapped = False
for i in range(len(cards)-1):
if rankString.find(cards[0])>rankString.find(cards[i+1][0]):
cards,cards[i+1]=cards[i+1],cards
swapped = True
return


def ShowCards(player,cards):
print("\n****************************************************")
print("************Player "+str(player)+" has**************")
print("****************************************************\n")
for i in range(len(cards)):
print(cards),
print("\n")
return

def ShowMessage(msg):
print("****************************************************")
print(str(msg))
print("****************************************************\n")
return

def remove_suits(player):
new_hand = []
for card in pHands[player]:
new_card = card[0]
new_hand.append(new_card)
return new_hand

def choosing_target():
target_player = raw_input ("Who do you want to ask? (1-3)")
while target_player.isdigit() == False or 1 > int(target_player) or3 < int(target_player):
print "Error: Must type a valid player id (from 1 to 3)"
target_player = raw_input ("Who do you want to ask? (1-3)")
target_player = int(target_player)
return target_player

def target_rank():
target_card = raw_input ("What rank are you seeking? (" + str(",".join(new_hand)) + ")")
while target_card not in new_hand:
print "Error: Must type one of the follow valid single character card ranks"
print str(",".join(new_hand))
target_card = raw_input ("What rank are you seeking? (" + str(","..join(new_hand)) + ")")
return target_card

print("~"*70)
print("~"*25+"WELCOME TO GO FISH!"+"~"*26)
print("~"*70)

nPlayers = 4
nCards = 10
deck = SetDeck()
sDeck = Shuffle(deck[:])
pHands = DealInitialCards(nPlayers,nCards,sDeck)
Sort(pHands[0])
ShowCards(0,pHands[0])

hit = 1

while hit == 1 :
ShowMessage("TURN: Player 0, its your turn.")
target_player = choosing_target()
new_hand = remove_suits(0)
target_card = target_rank()
ShowMessage("Target: Player " + str(target_player) + " is being targeted for the rank <" + str(target_card) + ">")
temp_hit = player_0_hitman(hit)
print "hit = " + str(hit)

def player_0_hitman(hit):
for card in pHands[target_player]:
if target_card[0] == card[0]:
count = pHands[target_player].count(card)
pHands[0].append(card)
pHands[target_player].remove(card)
ShowMessage("HIT: " + str(count) + " card(s) transferred")
else:
if target_card[0] != card[0]:
top_card = GetTopCard(sDeck)
pHands[0].append(top_card)
if top_card[0] == target_card[0]:
ShowMessage("HIT: LUCKILY Player 0 has fished up a rank <" + str(top_card[0]) + ">!!!")
else:
ShowMessage("MISS: You fished up the rank <" + str(top_card[0]) + ">")
hit = hit - 1
return hit
 
Ad

Advertisements

M

MRAB

I'm trying to create a game of Go Fish in Python. But I've stumbled onto a little problem that I can't seem to figure out how to deal with.

There is a human player (player 0) and three computer players (from 1-3). The human player goes first and chooses a target player. And then a card rank (for example, the player could target player two and choose jacks, then the computer would have to give the player all its jacks).

What I have so far is below but the problem I'm having is right at the bottom of the code. So far, the code generates a deck, creates hands for every player, and then shows the player his/her cards. Then the player is asked which computer player he/she wants to target as well as the rank of cards.

The problem I'm having is with the last set of lines (the def player_0_hitman) at the bottom of the code. Any help would be much appreciated. There are basically three issues I'm having problems with.

Basically, my code is ignoring the if's and else's. I don't get why. Everything appears to be positioned correctly, but for some odd reason, even after an if, the program also runs the else as well.

the "hit" is not being returned. Even though in the definition, I have the hit set to hit = hit - 1 for the last else, it still reruns the whole definition again as if it the hit was 1

I'm trying to use the count line to count how many cards are being transferred so the program will tell the player how many cards he gains when he gets a successful guess but I only get a statement saying I got 1 card each time no matter what (whether I get no cards or I get more than one).

I understand the basics of what I need to do but I can't seem to get a working code for this. I've tried changing the "for" to "if" but I get all sorts of errors so I don't think that will work. Then I tried converting "hit" into another code before entering the definition, changing it while inside, then converting it back before returning it but that also seems to do nothing, and I still get the same issues.
[snip]

def player_0_hitman(hit):
for card in pHands[target_player]:
if target_card[0] == card[0]:
count = pHands[target_player].count(card)
pHands[0].append(card)
pHands[target_player].remove(card)
ShowMessage("HIT: " + str(count) + " card(s) transferred")
else:
if target_card[0] != card[0]:
top_card = GetTopCard(sDeck)
pHands[0].append(top_card)
if top_card[0] == target_card[0]:
ShowMessage("HIT: LUCKILY Player 0 has fished up a rank <" + str(top_card[0]) + ">!!!")
else:
ShowMessage("MISS: You fished up the rank <" + str(top_card[0]) + ">")
hit = hit - 1
return hit
You have "else" lined up with "for".

In Python a "for" loop can have an "else" clause, which is run if it
didn't "break" out of the loop but finished.
 
J

John Ladasky

Basically, my code is ignoring the if's and else's. I don't get why.
Everything appears to be positioned correctly, but for some odd reason, even
after an if, the program also runs the else as well.

Look carefully at your indentation. One "else" statement is at the same indentation as a "for" statement rather than an "if" statement. So what, you say?

http://docs.python.org/2/tutorial/controlflow.html

"Loop statements may have an else clause; it is executed when the loop terminates through exhaustion of the list (with for) or when the condition becomes false (with while), but not when the loop is terminated by a break statement."

I don't know of any other computer programming language besides Python which has the "for...break...else" idiom. However, I know quite a few that do not. I find it useful in many situations.
 
T

Terry Reedy

Nonsense: they are executed just as you ask, even though what you ask is
not what you meant.

def player_0_hitman(hit):
for card in pHands[target_player]:
if target_card[0] == card[0]:
count = pHands[target_player].count(card)
pHands[0].append(card)
pHands[target_player].remove(card)
ShowMessage("HIT: " + str(count) + " card(s) transferred")
else: else: # indent to match if
if target_card[0] != card[0]:
# delete this if line, see below.
top_card = GetTopCard(sDeck)
pHands[0].append(top_card)
if top_card[0] == target_card[0]:
ShowMessage("HIT: LUCKILY Player 0 has fished up a rank <" + str(top_card[0]) + ">!!!")
else:
ShowMessage("MISS: You fished up the rank <" + str(top_card[0]) + ">")
hit = hit - 1
return hit

This executes the for loop multiple times and the the else: clause of
the *for* statement (see the ref manual). I believe you want the whole
else: clause indented so that it will be executed when the if condition
is false. If so, the second if is redundant and should just be removed.
 
K

kevin4fong

Look carefully at your indentation. One "else" statement is at the same indentation as a "for" statement rather than an "if" statement. So what, you say?



http://docs.python.org/2/tutorial/controlflow.html



"Loop statements may have an else clause; it is executed when the loop terminates through exhaustion of the list (with for) or when the condition becomes false (with while), but not when the loop is terminated by a break statement."



I don't know of any other computer programming language besides Python which has the "for...break...else" idiom. However, I know quite a few that do not. I find it useful in many situations.

Yeah, I already know about that. But if I try to change it, I'm not even able to start the program. If I try to change the if statement that it corresponds with, I get a an error saying "card" is not a global. And if I try toshift it in, for some reason...the program runs through the MISS line multiple times.
 
K

kevin4fong

Nonsense: they are executed just as you ask, even though what you ask is

not what you meant.



def player_0_hitman(hit):
for card in pHands[target_player]:
if target_card[0] == card[0]:
count = pHands[target_player].count(card)
pHands[0].append(card)
pHands[target_player].remove(card)

ShowMessage("HIT: " + str(count) + " card(s) transferred")

else: # indent to match if
if target_card[0] != card[0]:

# delete this if line, see below.


top_card = GetTopCard(sDeck)
pHands[0].append(top_card)

if top_card[0] == target_card[0]:
ShowMessage("HIT: LUCKILY Player 0 has fished up a rank <" + str(top_card[0]) + ">!!!")

ShowMessage("MISS: You fished up the rank <" + str(top_card[0]) + ">")
hit = hit - 1
return hit



This executes the for loop multiple times and the the else: clause of

the *for* statement (see the ref manual). I believe you want the whole

else: clause indented so that it will be executed when the if condition

is false. If so, the second if is redundant and should just be removed.

Yeah, thanks for the advice. But unfortunately, I already tried that and I ended up with a whole bunch of new errors.
 
Ad

Advertisements

C

Chris Angelico

Yeah, I already know about that. But if I try to change it, I'm not even able to start the program. If I try to change the if statement that it corresponds with, I get a an error saying "card" is not a global. And if I try to shift it in, for some reason...the program runs through the MISS line multiple times.

Okay. Stop, take a step back, and simplify your problems. You're
currently exhibiting a technique of shotgun programming that may be
getting in your way; you're just trying things without really knowing
what you're doing. Play with individual control structures in
interactive Python (eg IDLE), and get to know what's really happening.
Read the docs. Be sure you're structuring your code the way you think
you are. You'll find everything easier once you understand why your
code is doing what it's doing.

ChrisA
 
J

Joshua Landau

Yeah, I already know about that. But if I try to change it, I'm not even
able to start the program. If I try to change the if statement that it
corresponds with, I get a an error saying "card" is not a global. And if I
try to shift it in, for some reason...the program runs through the MISS
line multiple times.

You have a car with a broken engine and a broken tire and are telling us
that you refuse to fix the engine because it highlights the problem of the
broken tire.

Take the fix and move on to the next problem.

One piece of advice is about scoping. This is perhaps the hardest "gotcha"
of Python conceptually, but it's sensible once you understand the
justifications.

Run the four commands below and try and understand why this applies to your
code.

a = 1

def access_global():
print(a)

def set_variable():
a = 2
print(a)

def broken_set():
a = a + 1
print(a)

def also_broken():
print(a)
return
a = 1 # Never run!

The fix for the broken variants is to start the functions with "global a".
 
K

kevin4fong

Yeah, I already know about that. But if I try to change it, I'm not even able to start the program. If I try to change the if statement that it corresponds with, I get a an error saying "card" is not a global. And if I try to shift it in, for some reason...the program runs through the MISS line multiple times.





You have a car with a broken engine and a broken tire and are telling us that you refuse to fix the engine because it highlights the problem of the broken tire.


Take the fix and move on to the next problem.




One piece of advice is about scoping. This is perhaps the hardest "gotcha" of Python conceptually, but it's sensible once you understand the justifications.


Run the four commands below and try and understand why this applies to your code.




a = 1


def access_global():
    print(a)


def set_variable():
    a = 2
    print(a)


def broken_set():


    a = a + 1
    print(a)


def also_broken():
    print(a)
    return
    a = 1 # Never run!


The fix for the broken variants is to start the functions with "global a"..

I'll take a look at those. I used that fix you brought up as well but the main issue I get after that is:

I'll try to explain the main issue I'm having as accurately as possible. Basically, I've changed the indentations around but the main issue I get is that the GetTopCard(sDeck) line is being run multiple times for some reason.So when I run the program, I get "MISS: You fished up the rank......" multiple times and my list pHands[0] is increased by several number combinations when I only want it to increase by one. I also updated that last definition in my main code.



def player_0_hitman(hit):
for card in pHands[target_player]:
if target_card[0] == card[0]:
count = pHands[target_player].count(card)
pHands[0].append(card)
pHands[target_player].remove(card)
ShowMessage("HIT: " + str(count) + " card(s) transferred")
else:
top_card = GetTopCard(sDeck)
pHands[0].append(top_card)
if top_card[0] == target_card[0]:
ShowMessage("HIT: LUCKILY Player 0 has fished up a rank <" + str(top_card[0]) + ">!!!")
else:
ShowMessage("MISS: You fished up the rank <" + str(top_card[0]) + ">")
hit = hit - 1
 
D

Dave Angel

I'm trying to create a game of Go Fish in Python. But I've stumbled onto a little problem that I can't seem to figure out how to deal with.
<snip>

Please list the program the way you are actually running it. The
present one will not run very long before producing the error:

Traceback (most recent call last):
File "kevin.py", line 100, in <module>
temp_hit = player_0_hitman(hit)
NameError: name 'player_0_hitman' is not defined

Next, tell us the environment it runs in. In this case that means the
version of Python you're using. In some places you include parens
around the print arguments, like needed in Python 3, but in others your
code could only work up to version 2.7 So we have to do some detective
work just to discover you're using version 2.x

Next, when telling us of an error, quote the exact traceback, don't just
say something like: "I get a an error saying "card" is not a global"

Next, what on earth does the following mean:
" And if I try to shift it in" ?? Are you perhaps referring to Perl
grammar, or to DOS batch files?

Next, comments like: "tried that and I ended up with a whole bunch of
new errors" don't tell us much. Likewise " I'm not even able to start
the program. If I try to change the if statement that it corresponds
with" The last noun was "program" so I don't know which of the
program's if statements you're changing.

There are multiple things wrong with the code, and you can't expect any
one of us to be able to spot them all. Some are clear by inspection,
and others would probably require actually running the code, after you
fix the problem with player_0_hitman above. Example of inspection: you
have the line:
temp_hit = player_0_hitman(hit)

but never actually use the temp_hit variable.

Similarly, the line:
pHands[target_player].remove(card)

is going to mess up the loop it's in, When you're iterating over a
list, you can't normally add or remove items from that list.

Even after you fix that, the loop is still all wrong. The count method
will never get more than one, since all the cards are unique. You want
to count up the cards that match a particular rank, regardless of suit.
And that loop effectively does that, transferring one at a time. But
you don't do anything to keep track of how many you transferred.

As for the misplaced else, it doesn't belong there at all. What you
presumably want to do is after exiting the loop, you want to check the
corrected count value to decide how many cards were transferred. If
that is non zero, then the logic should be executed, including
decrementing the hit value and returning it.


Is this your own program? If so, you should be able to
siimplify it to ask a question. Few of us are willing to figure out
the logic of go-fish, but many of us are willing to figure out what
indentation makes sense for a given function.
 
T

Terry Reedy

On 8/2/2013 10:24 PM, (e-mail address removed) wrote:

Looking at this again, I believe you actually had the structure almost
right before. You want to look through *all* of the target players cards
and if *none* of them match, (ie the search fails), you want to draw 1
card. What you were missing before is break or return

def player_0_hitman(hit):
for card in pHands[target_player]:
if target_card[0] == card[0]:
count = pHands[target_player].count(card)
pHands[0].append(card)
pHands[target_player].remove(card)
ShowMessage("HIT: " + str(count) + " card(s) transferred")
return True

# else: needed if just break above, but not with return

top_card = GetTopCard(sDeck)
pHands[0].append(top_card)
if top_card[0] == target_card[0]:
ShowMessage("HIT: LUCKILY Player 0 has fished up a rank <" +
str(top_card[0]) + ">!!!")
return True
else:
ShowMessage("MISS: You fished up the rank <" +
str(top_card[0]) + ">")
hit = hit - 1
return False

The returns are based on what I remember of the rules from decades ago,
that a hit either in the hand or the draw allowed another turn by the
player.
 
Ad

Advertisements

K

kevin4fong

On 8/2/2013 10:24 PM, (e-mail address removed) wrote:



Looking at this again, I believe you actually had the structure almost

right before. You want to look through *all* of the target players cards

and if *none* of them match, (ie the search fails), you want to draw 1

card. What you were missing before is break or return



def player_0_hitman(hit):

for card in pHands[target_player]:

if target_card[0] == card[0]:

count = pHands[target_player].count(card)

pHands[0].append(card)

pHands[target_player].remove(card)

ShowMessage("HIT: " + str(count) + " card(s) transferred")

return True



# else: needed if just break above, but not with return



top_card = GetTopCard(sDeck)

pHands[0].append(top_card)

if top_card[0] == target_card[0]:

ShowMessage("HIT: LUCKILY Player 0 has fished up a rank <" +

str(top_card[0]) + ">!!!")

return True

else:

ShowMessage("MISS: You fished up the rank <" +

str(top_card[0]) + ">")

hit = hit - 1

return False



The returns are based on what I remember of the rules from decades ago,

that a hit either in the hand or the draw allowed another turn by the

player.

Thank you, that information worked quite well and is much appreciated.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top