How to consolidate if / elif statements in Python - if-statement

I looked around and did some research, but for some reason I still couldn't get it to work as planned. Basically, as a beginner, I wrote a Mastermind code game- same rules and all. Here's the code:
import random
trial = 0
def geuss():
geuss = raw_input("What is your geuss? ")
global g1
global g2
global g3
global g4
a = geuss[:-3]
b = geuss[1:-2]
c = geuss[2:-1]
d = geuss[3:]
if a == peg1:
g1 = 'R'
elif a == peg2:
g1 = 'W'
elif a == peg3:
g1 = 'W'
elif a == peg4:
g1 = 'W'
else:
g1 = 'X'
if b == peg2:
g2 = 'R'
elif b == peg1:
g2 = 'W'
elif b == peg3:
g2 = 'W'
elif b == peg4:
g2 = 'W'
else:
g2 = 'X'
if c == peg3:
g3 = 'R'
elif c == peg1:
g3 = 'W'
elif c == peg2:
g3 = 'W'
elif c == peg4:
g3 = 'W'
else:
g3 = 'X'
if d == peg4:
g4 = 'R'
elif d == peg1:
g4 = 'W'
elif d == peg2:
g4 = 'W'
elif d == peg3:
g4 = 'W'
else:
g4 = 'X'
print g1, g2, g3, g4
global trial
trial = trial + 1
return trial
colour = ['B', 'G', 'Y', 'P', 'R']
peg1 = random.choice(colour)
peg2 = random.choice(colour)
peg3 = random.choice(colour)
peg4 = random.choice(colour)
g1 = 0
g2 = 0
g3 = 0
g4 = 0
print ""
while g1 != 'R' or g2 != 'R' or g3 != 'R' or g4 != 'R':
geuss()
print "Congratulations! It took you %d tries to crack the code!" % trial
print ""
print "The code was %s%s%s%s." % (peg1, peg2, peg3, peg4)
As you can see the if and elif statements in the function 'geuss()' are needlessly wrong- but when I tried putting them together the script would always put a W.
if a == peg1:
g1 = 'R'
elif a == peg2 or peg 3 or peg4:
g1 = 'W'
else:
g1 = 'X'
Even when I put "QWER" in as an input, I would get an X. Is there some way I can consolidate them while still getting the correct response?
Also, off topic, if there are any other suggestions you can give me on the script as I am a beginner, that would be much appreciated! Thank you!

When you use or or and, you need to specify which operation you are using. Here is what you wrote...
if a == peg1:
g1 = 'R'
elif a == peg2 or peg 3 or peg4:
g1 = 'W'
else:
g1 = 'X'
The elif in that asks if a is equal to peg2, and then if peg3 or peg4 exists. You need to change it so a == peg3/4 also. Like this...
elif a == peg2 or a == peg3 or a == peg4:

In regards to your if/elif question a typical Python idiom to use a dictionary for a switch statement.
// http://stackoverflow.com/questions/374239/why-doesnt-python-have-a-switch-statement
{'option1': function1,
'option2': function2,
'option3': function3,
'option4': function4,
}.get(value, defaultfunction)()
However, in this case I believe you are taking the wrong approach. "Thinking" in Python is a little different than other languages and takes awhile to get used to doing things "the Python way". You seem to understand lists, and string slices which is good. You can leverage that a bit more to simplify your Mastermind program as shown below.
import random
trial = 0
colour = ['B', 'G', 'Y', 'P', 'R']
pegs = [random.choice(colour), random.choice(colour), random.choice(colour), random.choice(colour)]
guess_pegs = ['?', '?', '?', '?']
def main():
print "Generating a code"
print pegs
guess()
print "Congratulations! It took you %d tries to crack the code!\n" % trial
print "The code was: " + ', '.join(pegs)
def guess():
global trial
global pegs
global guess_pegs
entry_list = ['?', '?', '?', '?']
while pegs != guess_pegs :
entry_list = raw_input("What is your guess? ").split(' ')
trial = trial + 1
if len(pegs) == len(entry_list) :
for i in range(0,4) :
if(entry_list[i] == pegs[i]) :
guess_pegs[i] = entry_list[i]
print guess_pegs
guess()
# Kick things off
main()

An experienced python programmer would write:-
elif a == peg2 or a == peg3 or a == peg4:
as:-
elif a in (peg2, peg3, peg4):

Related

breaking a string equation into two parts in python3

I have a string such as
'(((a+b)+a)+c)' which I'd like to break into two parts, the result would be ('((a+b)+a)','c').
If I were to run it again on the first element of the result it would give me ('(a+b)', 'a')
and if I ran it again on '(a+b)' it would return ('a', 'b').
I was thinking I could do this via a regular expression but I couldn't figure this out and went down the path of having many if statements checking for opening and closing brackets but it gets a bit messy
Here is an example that works on examples such as yours:
def breakit(s):
count = 0
for i, c in enumerate(s):
if count == 1 and c in '+-':
return s[1:i].strip(), s[i+1:-1].strip()
if c == '(': count +=1
if c == ')': count -= 1
return s
breakit(s)
>> ('((a+b)+a)', 'c')
breakit(_[0])
('(a+b)', 'a')
breakit(_[0])
('a', 'b')
voila:
#!/usr/bin/python3.5
def f(s):
p=s.rsplit('+',1)
return [p[0][1:],p[1][:-1]]
s='(((a+b)+a)+c)'
for i in range(3):
k=f(s)
s=k[0]
print(k)
output:
['((a+b)+a)', 'c']
['(a+b)', 'a']
['a', 'b']
I thought I'd post my answer as well, not quite as elegant as the chosen solution but it works
def break_into_2(s):
if len(s) == 1:
# limiting case
return s
# s[0] can either be a digit or '('
if s[0].isdigit():
# digit could be 10,100,1000,...
idx = 0
while s[idx].isdigit():
idx += 1
a = s[:idx]
b = s[idx+1:]
return a, b
# otherwise, s[0] = '('
idx = 1
counter = 1
# counter tracks opening and closing parenthesis
# when counter = 0, the left side expression has
# been found, return the idx at which this happens
while counter:
if s[idx] == '(':
counter+=1
elif s[idx] == ')':
counter -=1
idx +=1
if s[:idx] == s:
# this case occurs when brackets enclosing entire expression, s
# runs the function again with the same expression from idxs 1:-1
return break_into_2(s[1:-1])
return s[:idx], s[idx+1:]

My if/elif statement only returns if [duplicate]

This question already has answers here:
How to test multiple variables for equality against a single value?
(31 answers)
Closed 8 years ago.
I just want to start by saying i have only just started programing and am only interested in learning.
in a very simple turn-based fighting game, i give my player the choice to attack or defend but when i input a "d" for defend it will return the attack code.
import random
import time
play = 'y'
name = ' '
playerHp = 20
attack = 4
enemyHp = 0
enemyAttack = 0
def intro ():
global name
print('''
welcome to the scary forrest!
dangerous monsters live in this
area and you must destroy or
be destroyed! attack and defend
correctly and you may survive.''')
time.sleep (2)
print ('what is your name, adventurer?')
name = input()
def randomEnemy ():
x = random.randint (3,5)
global enemyHp
global enemyAttack
enemyHp = x * 5
enemyAttack = x
print('''A goblin has jumped out to attack you, prepare to fight!''')
def battle ():
global enemyHp
global enemyAttack
global playerHp
global attack
while enemyHp > 0 and playerHp > 0:
print ('you have ' + str(playerHp) + ' health left')
time.sleep (2)
print ('the goblin has ' + str(enemyHp) + ' health left')
time.sleep (2)
print ('(a)ttack or (d)efend)
choice = input()
if choice == 'a' or 'attack':
finalattack = attack + random.randint (-1,2)
print ('you swing at the goblin and do ' + str(finalattack) + ' damage')
time.sleep(2)
print ('the goblin strikes you for ' + str(enemyAttack) + ' damage')
playerHp = playerHp - enemyAttack
enemyHp = enemyHp - finalattack
choice = 0
elif choice == 'd' or 'defend':
print ('the goblin strikes at you!')
print ('but you block his attack')
heal = random.randint (5,6) - enemyAttack
playerHp += heal
print ('you heal for ' + str(heal) + ' Hp')
choice =0
if playerHp <= 0:
print('you lose... noone finds your body because the \ngoblin drags you into his cave')
if enemyHp <= 0:
print ('you stand victorious over your foe, but noone is \nreally impressed except yo\' momma')
intro()
randomEnemy()
battle()
is there a problem with my if statement?
if some one can help me and use small words that would be greatly appreciated.
Yes, you need to test their choice with:
if choice == 'a' or choice == 'attack':
and:
elif choice == 'd' or choice == 'defend':
Your original statement:
elif choice == 'a' or 'attack':
Will always yield True as the string 'attack' is effectively True (not to mention it should be if and not elif; thanks to #chepner for spotting that).
(I haven't checked all your code).
The problem is that
elif choice == 'a' or 'attack':
is not doing what you think. Python's parser evaluates it as:
elif bool(choice == 'a') or bool('attack'):
and the boolean value of a non empty string is True. What you want is:
if choice == 'a' or choice == 'attack':
Note that I have replaced elif by a simple if, as it is the first one. (elif is short for else if).

raw_input() invalid syntax

I want to input a string of five numbers with spaces between them and use raw_input() for it. However the second item(the portion that's between the first and second spaces) is claimed to be a syntax error. Code below:
#class for final output - used as an ad hoc static string
class StatString:
outstring = ""
#function to check if Boom or Trach or both
def BoomTrach(num,B,T):
Boom = False
Trach = False
temp = num
while temp != 0:
if num % B == 0:
Boom == True
break
if (temp % 10) % B == 0:
Boom = True
break
temp = (temp - temp % 10) / 10
temp = num
while temp != 0:
if num % T == 0:
Trach = True
break
if (temp % 10) % T == 0:
Trach = True
break
temp = (temp - temp % 10) / 10
if Boom and Trach:
herestring.outstring = herestring.outstring + "Boom-Trach"
elif Boom:
herestring.outstring = herestring.outstring + "Boom"
elif Trach:
herestring.outstring = herestring.outstring + "Trach"
else:
herestring.outstring = herestring.outstring + str(num)
#start of "main" portion
def main():
inS = raw_input() <<<--- Input here
arr = inS.split(' ')
X = int(arr[0])
Y = int(arr[1])
CountFrom = int(arr[2])
jump = int(arr[3])
CountUntil = int(arr[4])
#variable for error check
error = False
#checking for errors
if X < 1 or X > 9 or Y < 1 or Y > 9:
print "X and Y must be between 1 and 9"
error = True
if jump == 0:
print "jump cannot be 0"
error = True
elif (CountUntil - CountFrom) % jump != 0:
print "cannot jump from %d to %d",CountFrom,CountUntil
error = True
if error:
exit()
if CountFrom < 0 and CountUntil < 0 and jump > 0:
jump = jump * (-1)
herestring = StatString()
while CountFrom != CountUntil:
BoomTrach(CountFrom,X,Y)
CountFrom = CountFrom + jump
if(CountFrom != CountUntil):
herestring.outstring = herestring.outstring + ","
print herestring.outstring
error message: (the second 1 was marked as the source of the error)
>>> 1 1 1 1 1
SyntaxError: invalid syntax
>>>
I know what happened. You just run this module, and you thought that you start running it from the main function (like in C for example).
There is no problem with the raw_input line (the first line of the input). The problem is that your module does not try to read anything! You just typed "1 1 1 1 1" which is of course syntax error...
Append to your code this line to run the main function:
main()
You can also write the code of the main function not in some function, to get the same effect.

Tic-Tac-Toe TypeError: 'NoneType' object has no attribute '__getitem__'

I am programming a Tic-Tac-Toe game. I have most of the program done. But I keep getting the following error and I don't understand what I am doing wrong. I have tried formatting it differently.
Traceback (most recent call last):
File "C:/Users/Akshay Sastry/Documents/CS 303E/Tic-Tac-Toe.py", line 66, in <module>
main()
File "C:/Users/Akshay Sastry/Documents/CS 303E/Tic-Tac-Toe.py", line 3, in main
while isWinner(board) == 0 and movesLeft(board) == True:
File "C:/Users/Akshay Sastry/Documents/CS 303E/Tic-Tac-Toe.py", line 20, in isWinner
if (b[0][0]=='x') and (b[0][0]==b[0][1]==b[0][2]):
TypeError: 'NoneType' object has no attribute '__getitem__'
This is my code:
def main():
board = makeBoard()
while isWinner(board) == 0 and movesLeft(board) == True:
printBoard(board)
p1row, p1col = input("Enter a row and column for x: ")
board[p1row][p1col] = 'x'
if isWinner(board) == 0 and movesLeft(board) == True:
printBoard(board)
p2row, p2col = input("Enter a row and column for o: ")
board[p2row][p2col] = 'o'
if isWinner(board) != 0:
print isWinner(board), 'won!'
else:
print 'Tie game.'
def makeBoard():
board = [['*','*','*'],['*','*','*'],['*','*','*']]
def isWinner(b):
if (b[0][0]=='x') and (b[0][0]==b[0][1]==b[0][2]):
return 'x'
elif (b[1][0]=='x') and (b[1][0]==b[1][1]==b[1][2]):
return 'x'
elif (b[2][0]=='x') and (b[2][0]==b[1][1]==b[2][2]):
return 'x'
elif (b[0][0]=='x') and (b[0][0]==b[1][0]==b[2][0]):
return 'x'
elif (b[0][1]=='x') and (b[0][1]==b[1][1]==b[2][1]):
return 'x'
elif (b[0][2]=='x') and (b[0][2]==b[1][2]==b[2][2]):
return 'x'
elif (b[0][0]=='x') and (b[0][0]==b[1][1]==b[2][2]):
return 'x'
elif (b[0][2]=='x') and (b[0][2]==b[1][1]==b[2][0]):
return 'x'
elif (b[0][0]=='o') and (b[0][0]==b[0][1]==b[0][2]):
return 'o'
elif (b[1][0]=='o') and (b[1][0]==b[1][1]==b[1][2]):
return 'o'
elif (b[2][0]=='o') and (b[2][0]==b[1][1]==b[2][2]):
return 'o'
elif (b[0][0]=='o') and (b[0][0]==b[1][0]==b[2][0]):
return 'o'
elif (b[0][1]=='o') and (b[0][1]==b[1][1]==b[2][1]):
return 'o'
elif (b[0][2]=='o') and (b[0][2]==b[1][2]==b[2][2]):
return 'o'
elif (b[0][0]=='o') and (b[0][0]==b[1][1]==b[2][2]):
return 'o'
elif (b[0][2]=='o') and (b[0][2]==b[1][1]==b[2][0]):
return 'o'
else:
return 0
def printBoard(board):
for i in range(3):
for j in range(3):
print board[i][j],
print
def movesLeft(board):
if board[0].count("*") != 0 or board[1].count("*") != 0 or board[2].count("*") != 0:
return True
else:
return False
main()
Your makeBoard() function returns None. You should make it like this:
def makeBoard():
return [['*','*','*'],['*','*','*'],['*','*','*']]
Your isWinner function can be made 3x smaller, as follows
def isWinner(b):
for i in range(3):
if (b[i][0] != '*') and (b[i][0]==b[i][1]==b[i][2]): # all rows
return b[i][0]
if (b[0][i] != '*') and (b[0][i]==b[1][i]==b[2][i]): # all cols
return b[0][i]
if (b[0][0] != '*') and (b[0][0]==b[1][1]==b[2][2]): # tl-br diag
return b[0][0]
elif (b[0][2] != '*') and (b[0][2]==b[1][1]==b[2][0]): # bl-tr diag
return b[0][2]
else:
return 0
For a larger board such as connect 4, however, you'd iterate over all points on the board and write a method that checked in a loop an arbitrary distance in every direction, rather than hard-coding every place a row can be in.

List index out of range ? It should not be

def trav(r,c):
#print("(",r,",",c,")")
ch = a[r+1][c+1]
lu= a[r][c]
#print(lu)
u = a[r][c+1]
#print(u)
ru= a[r][c+2]
#print(ru)
l = a[r+1][c]
#print(l)
r = a[r+1][c+2]
#print(r)
ld= a[r+2][c]
#print(ld)
d = a[r+2][c+1]
#print(d)
rd= a[r+2][c+2]
#print(rd)
a1 = a2 = a3 = a4 = a5 = a6 = a7 = a8 = 0
if(ch == lu-1):
a1 = trav(r-1,c-1)
if(ch == u-1):
a2 = trav(r-1,c)
if(ch == ru-1):
a3 = trav(r-1,c+1)
if(ch == l-1):
a4 = trav(r,c-1)
if(ch == r-1):
a5 = trav(r,c+1)
if(ch == ld-1):
a6 = trav(r+1,c-1)
if(ch == d-1):
a7 = trav(r+1,c)
if(ch == rd-1):
a8 = trav(r+1,c+1)
return max(a1,a2,a3,a4,a5,a6,a7,a8) + 1
while(1):
row,col = [int(x) for x in input().split(" ")]
if(row == 0):
break
a = []
for index in range(10):
a.append([])
for jindex in range(10):
a[index].append('a')
b = []
for index in range(row):
str = input()
for jindex in range(col):
a[index+1][jindex + 1] = ord(str[jindex])
if(str[jindex] == 'A'):
b.append([index,jindex])
#print (a)
#print (b)
ans = max([trav(x[0],x[1]) for x in b])
print(ans)
The code is generating the following error
Traceback (most recent call last): File "C:/Users/DELL/Desktop/ABCPATH.py", line 80, in <module>
ans = max([trav(x[0],x[1]) for x in b]) File "C:/Users/DELL/Desktop/ABCPATH.py", line 80, in <listcomp>
ans = max([trav(x[0],x[1]) for x in b]) File "C:/Users/DELL/Desktop/ABCPATH.py", line 17, in trav
ld= a[r+2][c] IndexError: list index out of range
But according to me it should not, and as I am extremely new to python , I am not able to debug it. Please help
sample input taken:
4 3
ABC
CFG
BDH
ABC
It has to break
r = a[r+1][c+2]
you're reassigning the value of 'r' in that line. please also note that you shouldn't name your string "str" as it is the name of the python string module and you won't be able to use it.