Looping functions together for an FSM - python

As many of you have probably seen and/or coded, I'm trying to make a finite state machine; 5 states and 9 transitions, to determine if someone is laughing. I don't necesarrily want the entire answer, cuz I do want to figure out as much as I can by myself. However, the professors and TA's aren't always very quick or helpful when answering, and this place is way more useful anyway.
I just want to be able to type "ha" or "ho" until a "!" is entered, saying "you laughed." Any other characters will end it. There are 3 functions to make; the get_ch(), the find_state(), and the main(), which drives both of the other ones. Here's what I have:
def get_ch(): # prompt for the input in a loop
ch = input("Enter a character or press the Return key to finish: ")
if len(ch) > 1:
print("Invalid input, please try again.")
else:
return ch
def find_state(state, ch):
if state==1:
if ch=="h" or ch=="H":
state=2
return state
else:
state=5
return state
if state==2:
if ch=="a" or ch=="A" or ch=="o" or ch=="O":
state=3
return state
else:
state=5
return state
if state==3:
if ch=="!":
state=4
return state
if ch=="h" or ch=="H":
state=2
return state
else:
state=5
return state
def main():
print("I can recognize if you are laughing or not.")
print("Please enter one character at a time.")
# initialize the variables, for example:
ch=get_ch()
string=""
state=1
#call the functions in a loop
while get_ch():
if len(ch)<1:
print("\nYou entered", string)
print("You are laughing.")
print("You are not laughing.")
else:
if state<4:
find_state(state,ch)
string+=ch
continue
if state==4:
print("\nYou entered", string)
print("You are laughing.")
else:
print("\nYou entered", string)
print("You are not laughing.")
main()
The issue I'm having is that the functions aren't "talking" to each other. I don't know if this is because they are not properly looped in the main() or if the issue lies within the individual functions themselves (such as calling back on get_ch() while in find_state()).

Related

Creating a Python game, working with returns in-between multiple modules

No matter how many times I google variations of my question, I cannot seem to find a solution. I am a beginner programmer, trying to build a game that randomly generates events as you progress through the stages. The problem I am running into are return statements, and passing the values between different modules. Each method for each file are inside of classes. They are all static methods, and calling these methods is not my problem. It is transferring the value of the variables. I'm not sure where I am going wrong, whether it is how I am structuring it, or if I just don't understand how these return statements work.
This is the first File I am starting from. Print statements will be filled out after everything functions properly.
def story():
print("---Intro Story Text here--- ... we will need your name, Traveler. What might it be?")
user_prompt = Introduction.PlayerIntroduction
name = user_prompt.player_info(1)
print(f"Welcome {name}!")
print(f"----After name is received, more story... how old might you be, {name}?")
age = user_prompt.player_info(2)
This is the file I am trying to get the values from. File: Introduction, Class: PlayerIntroduction
#staticmethod
def player_info(funct_select):
if funct_select == 1:
name = PlayerIntroduction.get_player_name()
player_name = name
elif funct_select == 2:
age = PlayerIntroduction.get_player_age()
player_age = age
return player_name, player_age
#staticmethod
def get_player_name():
print("\n\n\nWhat is your name?")
players_name = input("Name: ")
while True:
print(f"Your name is {players_name}?")
name_response = input("Yes/No: ")
if name_response == "Yes" or name_response == "yes":
name = "Traveler " + players_name
break
elif name_response == "No" or name_response == "no":
print("Let's fix that.")
PlayerIntroduction.get_player_name()
else:
print("Please respond with 'Yes' or 'No'.")
return name
#staticmethod
def get_player_age():
print("\n\n\nHow old are you?")
age = input("Age: ")
while True:
print(f"Your age is {age}?")
age_response = input("Yes/No: ")
if age_response == "Yes" or age_response == "yes":
break
elif age_response == "No" or age_response == "no":
print("Let's fix that.")
PlayerIntroduction.get_player_age()
else:
print("Please respond with 'Yes' or 'No'.")
return age
I would like to use the values for "name" and "age" throughout multiple modules/multiple methods within my program. But in order to get those values, I need to assign a variable to the function call.. Resulting in prompting the user to re-enter their name/age at later stages in the game. My idea to combat this was in the first method of this module, creating a conditional statement "if 'example' == 1: 'run the name prompt' and elif == 2: run age prompt, thinking the initial run with the arguments defined would run these prompts, store the values into the variables (name, age), and finally pass the values to the new variables that are NOT assigned to the function call (p_name, p_age), avoiding triggering the user prompt over and over. Ultimately, this failed, and as the code sits now I am getting:
UnboundLocalError: local variable 'player_age' referenced before assignment
Why is this? The only instance 'player_age' is called that is reachable at this point is in the return statement, indented in-line with the conditional statement. The code should read (If I understand incorrectly, please explain) from top to bottom, executing in that order. The 'if' condition is met, so it should run that. If I were to define 'player_name' and 'player_age' as null at the top of this method to avoid this error, then every time I would need to reference these values initially entered by the user, they would be re-assigned to 'null', negating everything I am trying to do.
Thank you all for your patience, I tried to explain what I was doing and my thought process the best I could. Any feedback, criticism, and flaws within my code or this post are GREATLY appreciated. Everything helps me become a better programmer!! (:

Python: Being asked for input twice and outputting duplicate print statements

I am trying to finish off my program my adding a menu that allows the user to select a few options that allow the user to store website names and passwords in lists. But there was a problem as soon as I have appended some website names and passwords into their respective vaults where whenn I try to select an option after appending the website names and passwords, "1" for example is the expected input to call the viewapp() function to see the websites and passwords stored so far. The thing is it takes more than twice to call the viewapp() function, where it rejects the first expected input but accepts the 2nd one strangely. Also when I select the 3rd option for the purpose to call summary(), the whole printed summary would print out twice, which is a similar pattern to the menu only accepting the 2nd expected input. The program is doing what I want except for this annoying bug where selecting those four options makes it ask for input a second time when it's supposed to straight away jump to that function. Help would be appreciated.
appvault = []
passvault = []
def logged():
print("----------------------------------------------------------------------\n")
print("Hello, welcome to the password vault console. ")
modea = input("""Below are the options you can choose from in the password vault console:
##########################################################################\n
1) Find the password for an existing webiste/app
2) Add a new website/app and a new password for it
3) Summary of the password vault
4) Exit
##########################################################################\n
> """).strip()
return modea
def viewapp():
if len(appvault) > 0:
for app in appvault:
print("Here is the website/app you have stored:")
print("- {}\n".format(app))
if len(passvault) > 0 :
for code in passvault:
print("Here is the password you have stored for the website/app: ")
print("- {}\n".format(code))
else:
print("You have no apps or passwords entered yet!")
def addapp():
while True:
validapp = True
while validapp:
new_app = input("Enter the new website/app name: ").strip().lower()
if len(new_app) > 20:
print("Please enter a new website/app name no more than 20 characters: ")
elif len(new_app) < 1:
print("Please enter a valid new website/app name: ")
else:
validapp = False
appvault.append(new_app)
validnewpass = True
while validnewpass:
new_pass = input("Enter a new password to be stored in the passsword vault: ")
if not new_pass.isalnum():
print("Your password for the website/app cannot be null, contain spaces or contain symbols \n")
elif len(new_pass) < 8:
print("Your new password must be at least 8 characters long: ")
elif len(new_pass) > 20:
print("Your new password cannot be over 20 characters long: ")
else:
validnewpass = False
passvault.append(new_pass)
validquit = True
while validquit:
quit = input("\nEnter 'end' to exit or any key to continue to add more website/app names and passwords for them: \n> ")
if quit in ["end", "End", "END"]:
logged()
else:
validquit = False
addapp()
return addapp
def summary():
if len(passvault) > 0:
for passw in passvault:
print("----------------------------------------------------------------------")
print("Here is a summary of the passwords stored in the password vault:\n")
print("The number of passwords stored:", len(passvault))
print("Passwords with the longest characters: ", max(new_pass for (new_pass) in passvault))
print("Passwords with the shortest charactrs: ", min(new_pass for (new_pass) in passvault))
print("----------------------------------------------------------------------")
else:
print("You have no passwords entered yet!")
while True:
chosen_option = logged()
print(chosen_option)
if chosen_option == "1":
viewapp()
elif chosen_option == "2":
addapp()
elif chosen_option == "3":
summary()
elif chosen_option == "4":
break
else:
print("That was not a valid option, please try again: ")
print("Goodbye")
This happens because you call logged() when exiting addapp():
if quit in ["end", "End", "END"]:
logged()
Then, the choice you enter is returned by logged(), and thrown away as it isn't assigned to anything.
You're now back at the end of the previous block in addapp(), and the next instruction is return addapp, that will bring you back to your main loop, where you'll be sent to logged() again by chosen_option = logged()
Note that in return addapp, you return the addapp function itself, which is certainly not what you want to do. So, as you don't need a return value for addapp(), just use return, or nothing at all, Python will automatically return at the end of the function.
So, to solve your problem: directly return when you're done entering sites:
if quit in ["end", "End", "END"]:
return
Note also that you recursively call addapp() from itself when you add more sites.
You should generaly avoid that unless you really want to use some recursive algorithm, and rather use a loop as you did in your main loop. By default, Python limits you to 1000 recursion levels - so you could even crash your app by entering more than 1000 sites in a row ;)
The summary problem is only caused by the unnecessary for loop in summary()
You are nearly there. The issue is in the addapp() function at line 63:
if quit not in ["end", "End", "END"]:
logged()
if you replace
logged()
with
pass
Then everything will work a ok.
You are not handling the result of the logged function here anyway.
You also do not need to process the logged function here. The addapp will exit and the logged function will be called and handled in the while loop the addapp function was called from.

errors with Elif expected indented block

I'm trying to create a menu for my application, the menu has 4 options and each of these options should return with the correct information when the user has entered the chosen value. i keep getting an error with the Elif statements.
I am a newbie so please understand where am coming from.
much appreciation.
when i indent the while ans: i will receive an error says invalid syntax after indenting the elif ans==2.
elif ans==2 <--- this error keeps saying indention block error or syntex invalid when i indent it.
def print_menu(self,car):
print ("1.Search by platenumber")
print ("2.Search by price ")
print ("3.Delete 3")
print ("4.Exit 4")
loop=True
while loop:
print_menu()
ans==input("Please choose from the list")
if ans==1:
print("These are the cars within this platenumber")
return platenumber_
while ans:
if ans==2:
elif ans==2:
print("These are the prices of the cars")
return price_
elif ans==3:
print("Delete the cars ")
return delete_
elif ans==4:
return Exit_
loop=False
else:
raw_input("please choose a correct option")
You have a while loop without a body. Generally speaking, if there is an indentation error message and the error is not on the line mentioned, it's something closely above it.
loop=True
while loop:
print_menu()
ans = int(input("Please choose from the list"))
if ans==1:
print("These are the cars within this platenumber")
# return some valid information about plate numbers
elif ans==2:
print("These are the prices of the cars")
# return some valid information about pricing
elif ans==3:
print("Delete the cars ")
# Perform car deletion action and return
elif ans==4:
# I am assuming this is the exit option? in which case
# return without doing anything
else:
# In this case they have not chosen a valid option. Send
# A message to the user, and do nothing. The while loop will run again.
print("please choose a correct option")
Also, your code is a bit confusing to me. It looks like you're going to return car_ no matter what, which means your loop will only execute once. Also, = is assignment and == is equality. Be careful.

Glitch with code?

I have this code. If you run it everything works fine if you follow the instructions. However I want to dummyproof it but when you enter too make troops and then you fix your mistake you get an error after fixing the mistake when functions restarts itself.
Please take a look and help me fix it.
import time
warriors = 100
def deploy(): #Calls fighters to front lines
amount = input('How many warriors would you like to send to the front lines? Your limit is %i warriors. Keep in mind that enemy invaders have been spotted inside your base. You must keep 10 warriors in base at all times. ' %(warriors))
try:
amount = int(amount)
except ValueError:
print('Please use numbers.')
time.sleep(1.5)
deploy()
if amount <= warriors:
print (type(amount))
elif amount > warriors:
print("You can't send that many warriors. You only have %i warriors." %(warriors))
time.sleep(1.5)
amount=0
deploy()
else:
print("You did something wrong. Try again.")
time.sleep(1.5)
deploy()
fighters = deploy()
warriors = warriors - fighters
You shouldn't use recursion (e.g. a function calling itself repeatedly) to try and do validation. For some general examples of good patterns for this, the canonical question is a good start. In your case I might refactor slightly.
import time
warriors = 100
def deploy():
while True:
amount = input("...") # your text here
try:
amount = int(amount)
except ValueError:
print("Please use numbers.")
# move the time.sleep to the end
else: # only execute if the try block succeeds
if amount > warriors:
print("You can't send that many warriors. "
"You only have %i warriors." % warriors)
else:
# everything went right!
print(type(amount)) # why are you doing this...?
return amount # did you forget this in your sample code?
# if you get here: something broke
time.sleep(1.5)
That said, this is kind of ugly since it's so deeply nested. Remember the Zen: "Flat is better than nested." Let's refactor a bit to make a new function that does the validation for us.
import time
warriors = 100
def int_less_than(prompt, ceil, type_error_msg=None,
value_error_msg=None, callback=None):
"""Returns a validated integer
input(prompt) must be less than ceil. Print to console a std error msg
if none is specified. If you specify a callback: run the callback if any
errors are detected.
"""
while True:
user_in = input(prompt)
try:
user_in = int(user_in)
except ValueError:
print(type_error_msg or "You must enter a number")
else:
if user_in > ceil:
print(value_error_msg or "You must enter a number "
"less than {}".format(ceil))
else:
return user_in
if callback is not None:
callback() # lets us insert a time.sleep call
def deploy():
amount = int_less_than("How many warriors would you like to...",
warriors,
callback=lambda: time.sleep(1.5))
return amount

How do I change a sum for string for it to work?

This is my whole program I'm working on (with the function not in the right place due to the code needing to be indented) but anyway there is a problem that I'm not sure how to fix.
How do I change it so that this would work along with my program? It says that it is in a string but am not sure how to change this so it calculates the variables from the rest of my program. I am sorry seeming how this is not the only problem I am new to this and am just getting used to how this works.
import time
import random
def welcome():
ready="no"
while ready=="no":
print("Welcome To Encounter Simulator Inc. Where We Provide You with combat..")
print("Readying Start Up Sequence....")
time.sleep(0.5)
print("Welcome Are You Ready? Yes or No")
ready=input(str())
while ready!="yes" and ready!="no":
print("Yes or No Please")
ready=input(str())
def name():
areyousure="no"
while areyousure!="yes":
print("What do you want your 1st character to be named?")
name=input()
print("Are You Sure?(yes or no)")
areyousure=input(str())
if areyousure!="yes" and areyousure!="no":
print("Yes or No Please")
areyousure=input(str())
return name
def name2():
areyousure2="no"
while areyousure2!="yes":
print("What do you want your 2nd character to be named?")
name2=input()
print("Are You Sure?(yes or no)")
areyousure2=input(str())
if areyousure2!="yes" and areyousure2!="no":
print("Yes or No Please")
areyousure2=input(str())
return name2
def inputtingfor1(name):
areyousure3="no"
while areyousure3!="yes":
print("Please Input",name,"'s Attributes..")
skill1=input("The Skill Attribute= ")
strength1=input("The Strength Attribute= ")
print("Are You Sure? (Yes or No)")
areyousure3=input(str())
return skill1,strength1
def inputtingfor2(name2):
areyousure4="no"
while areyousure4!="yes":
print("Please Input",name2,"'s Attributes..")
skill2=input("The Skill Attribute= ")
strength2=input("The Strength Attribute= ")
print("Are You Sure (Yes or No)")
areyousure4=input(str())
return skill2,strength2
def difference1(skill1,skill2):
if skill1 >= skill2:
result0=skill1-skill2
result1=result0/5
elif skill1==skill2:
print("There Will Be No Skill Modifier")
result1=0
else:
result0=skill2-skill1
result1=result0/5
return result1
def difference2(strength1,strength2):
if strength1 >= strength2:
result10=strength1-strength2
result2=result10/5
elif strength1==strength52:
print("There Will Be No Strength Modifier")
result2=0
else:
result10=strength2-strength1
result2=result10/5
return result2
def dicerolling1():
print()
time.sleep(1)
print("This Will Determin Who Gets The Modifiers And Who Loses Them..")
dicenumber1=random.randint(1,6)
print(" The Dice Is Rolling For",name1,)
time.sleep(1)
print("And The Number",name1,"Got Was...",dicenumber1,)
return dicenumber1
def dicerolling2():
print()
time.sleep(1)
print("This Will Determin Who Gets The Modifiers And Who Loses Them..")
dicenumber2=random.randint(1,6)
print(" The Dice Is Rolling For",name2,)
time.sleep(1)
print("And The Number",name2,"Got Was...",dicenumber2,)
return dicenumber2
welcome()
name=name()
name2=name2()
skill1,strength1=inputtingfor1(name)
skill2,strength2=inputtingfor2(name2)
difference1(skill1,skill2)
difference2(strength1,strength2)
dicenumber1=dicerolling1()
dicenumber2=dicerolling2()
From the comment thread on the original question, the issue is that skill1 and skill2 are strings, which do not support the - operand. You need to cast them to ints before you perform any mathematical operation on them:
def difference1(skill1,skill2):
try:
s1 = int(skill1)
s2 = int(skill2)
except exceptions.ValueError:
print("Could not cast to int")
return None
if s1 >= s2:
result0 = s1-s2
result1=result0/5
elif s1==s2:
print("There Will Be No Skill Modifier")
result1 = 0
else:
result0=s2-s1
result1=result0/5
return result1
Depending on what you pass into difference1, you may not be left with an integer. If skill1 and skill2 could be parsed as floats, you'll hit an exception when you try to cast them to ints. If you know this will never be the case, you can remove the try-except block.
When skill1==skill2, result1 is not defined.
fix:
elif skill1==skill2:
print("There Will Be No Skill Modifier")
return 0

Categories

Resources