How to return to beginning of program from inside of if statement? - for-loop

I'm practicing some basic coding, I'm running a simple math program running in the terminal on Visual Studio Code.
How do I create an option to return to the beginning of the program, or exit the program after getting caught in an if statement?
Example:
#beginning of program
user_input=input('Please select "this" or "that": ')
findings=user_input
If findings == this:
print(this)
# How can I redirect back to first user input question, instead
# of just ending here?
if findings == that:
print (that)
# Again, How do I redirect back to first user input, instead of
# the program ending here?
# Can I setup a Play_again here with options to return to user_input,
# or exit program? And then have all other If statements
# redirect here after completion? How would I do that? with
# another If? or with a for loop?
#end program

You can try wrapping the whole program in a while loop like this:
while(True):
user_input=input('Please select "this" or "that": ')
this = 'foo'
if user_input == this:
print(this)
continue
if user_input == this:
print(this)
continue

Unfortunately, that 'another technique' I thought of using didn't work.
Here's the code (the first example modified):
import sys
def main():
# Lots of setup code here.
def start_over():
return #Do nothing and continue from the next line
condition = 1==1 #Just a sample condition, replace it with "check(condition)".
float_condition = condition
def play(*just_define:bool):
if not just_define:
play_again = input('play again? "y" or "n"')
if play_again == 'y':
start_over() #Jump to the beginning of the prohram.
if play_again == 'n':
sys.exit() #Exit the program
while True:
if float_condition == True:
# print(float_condition)
play() #skip to play_again from here?
if float_condition == False:
#print(float_condition)
play() #skip to play_again from here?
#I removed the extra "main()" which was here because it'd cause an infinite loop-like error.
main()
Output:
play again? "y" or "n"y
play again? "y" or "n"n
Process finished with exit code 0
The * in the play(*just_define:bool) function makes the just_define parameter optional. Use the parameter if you want to only tell Python to search for this function, so it doesn't throw a ReferenceError and not execute anything that's after the line if not just_define:. How to call like so: play(just_define=True).
I've used nested functions. I've defined play so that you can call it from other places in your code.

Thanks to #Hack3r - I was finally able to choose to return back to the beginning of the program or exit out. But it resulted in a new issue. Now my print(results) are printing 4 or 5 times...
Here is the actual code I built and am working with:
def main():
math_Options=['Addition +','Subtraction -','Multiplication *','Division /']
math_func=['+','-','*','/']
for options in math_Options:
print(options)
print('Lets do some Math! What math function would you like to use? ')
while True:
my_Math_Function = input('Please make your choice from list above using the function symbol: ')
my_Number1=input('Please select your first number: ')
x=float(my_Number1)
print('Your 1st # is: ', x)
my_Number2=input('Please select your Second Number: ')
y=float(my_Number2)
print('Your 2nd # is: ', y)
z=float()
print('')
for Math_function in math_func:
if my_Math_Function == math_func[0]:
z=x+y
if my_Math_Function == math_func[1]:
z=x-y
if my_Math_Function == math_func[2]:
z=x*y
if my_Math_Function == math_func[3]:
z=x/y
if (z % 2) == 0 and z>0:
print(z, ' Is an EVEN POSITIVE Number')
if (z % 2) == 1 and z>0:
print(z, ' IS a ODD POSTIVE Number')
if (z % 2) == 0 and z<0:
print(z, ' Is an EVEN NEGATIVE Number')
if (z % 2) ==1 and z<0:
print(z, ' IS a ODD NEGATIVE Number')
if z==0:
print(z, 'Is is Equal to Zero')
print('')
play_again=input('Would you like to play again? "y" or "n" ')
if play_again == 'y':
continue
if play_again == 'n':
break
main()
main()

Related

The wav file wont play after using pyinstaller --onefile.I just hear the windows 'beep'

This program displays a home circuit breaker panel. the user can view what is on each breaker on the panel (data taken from an imported dictionary of entered breaker panel info) or the user can check what breakers control any list zone (kitchen basement, etc) The breakerville program closes when the user decides and is supposed to play a wave file at the close. It doesn't play after the program is made into an exe with pyinstaller just the windows 'beep'.
I am suspecting that I may need to edit the spec file to get the wave file to work after compiled. Is this correct and if so how? Do I need to modify the spec file?
from playsound import playsound # CURRENTLY USING
from chart import chart
from BreakerZones import BreakerZones
import time
import sys
import colorama
import yaml # to print the nested_lookup results(n) on separate lines
from nested_lookup import nested_lookup, get_all_keys # importing 2 items from nested_lookup
from colorama import Fore, Back, Style
colorama.init(autoreset=True) # If you don't want to print Style.RESET_ALL all the time,
# reset automatically after each print statement with True
print(colorama.ansi.clear_screen())
print('\n'*4) # prints a newline 4 times
print(Fore.MAGENTA + ' Arriving-' + Fore.GREEN + ' *** BREAKERVILLE USA ***')
def main():
print('\n' * 2)
print(Fore.BLUE + ' Breaker Numbers and Zones')
k = get_all_keys(BreakerZones)
# raw amount of keys even repeats , has quotes
new_l = [] # eliminate extra repeating nested keys
for e in k: # has quotes
if e not in new_l and sorted(e) not in new_l: #
new_l.append(e) #
print()
new_l.sort() # make alphabetical
newer_l = ('%s' % ', '.join(map(str, new_l)).strip("' ,")) # remove ['%s'] brackets so they don't show up when run
print(' ', yaml.dump(newer_l, default_flow_style=False)) # strip("' ,") or will see leading "' ," in output
print(Fore.BLUE + ' ENTER A BREAKER # OR ZONE', Fore.GREEN + ': ', end='')
i = input().strip().lower() # these lines is workaround for the colorama
print() # user input() issue of 'code' appearing in screen output
if i in k:
n = (nested_lookup(i, BreakerZones, wild=False, with_keys=False)) # wild=True means key not case sensitive,
print(yaml.dump(n, default_flow_style=False)) # 'with_keys' returns values + keys also
# for key, value in n.items(): eliminated by using yaml
# print(key, '--', value) eliminated by using yaml
else:
print(Fore.YELLOW + ' Typo,' + Fore.GREEN + ' try again')
main()
print()
print(Fore.GREEN + ' Continue? Y or N: C for breaker chart : ', end='') # see comments ENTER A BREAKER
ans = input().strip().lower() # strip() removes any spaces before or after user input
if ans == 'c':
chart()
print()
print(Fore.GREEN + ' Continue? Y or N : ', end='')
ans = input().strip().lower() # strip() removes any spaces before or after user input
if ans == 'y': # shorter version 'continue Y or N' after printing breaker chart
main()
else:
print()
print(Fore.MAGENTA + ' Departing -' + Fore.GREEN + ' *** BREAKERVILLE ***')
playsound('train whistle.wav')
time.sleep(2) # delay to exit program
sys.exit()
elif ans != 'y':
print()
print(Fore.MAGENTA + ' Good Day -' + Fore.GREEN + ' *** BREAKERVILLE ***')
playsound('train whistle.wav') #CURRENTLY USING
time.sleep(2) # delay to exit program
sys.exit()
else:
main()
main()
For the records: The issue is fixed by providing full path to the sound file.
This is probably linked to the implementation of playsound and how it determines what is the current working directory. Please refer to https://pyinstaller.readthedocs.io/en/stable/runtime-information.html#run-time-information for a better understanding of that topic with pyinstaller

Tool/Algorithm for text comparision after every key hit

I am struggling to find a text comparison tool or algorithm that can compare an expected text against the current state of the text being typed.
I will have an experimentee typewrite a text that he has in front of his eyes. My idea is to compare the current state of the text against the expected text whenever something is typed. That way I want to find out when and what the subject does wrong (I also want to find errors that are not in the resulting text but were in the intermediate text for some time).
Can someone point me in a direction?
Update #1
I have access to the typing data in a csv format:
This is example output data of me typing "foOBar". Every line has the form (timestamp, Key, Press/Release)
17293398.576653,F,P
17293398.6885,F,R
17293399.135282,LeftShift,P
17293399.626881,LeftShift,R
17293401.313254,O,P
17293401.391732,O,R
17293401.827314,LeftShift,P
17293402.073046,O,P
17293402.184859,O,R
17293403.178612,B,P
17293403.301748,B,R
17293403.458137,LeftShift,R
17293404.966193,A,P
17293405.077869,A,R
17293405.725405,R,P
17293405.815159,R,R
In Python
Given your input csv file (I called it keyboard_records.csv)
17293398.576653,F,P
17293398.6885,F,R
17293399.135282,LeftShift,P
17293399.626881,LeftShift,R
17293401.313254,O,P
17293401.391732,O,R
17293401.827314,LeftShift,P
17293402.073046,O,P
17293402.184859,O,R
17293403.178612,B,P
17293403.301748,B,R
17293403.458137,LeftShift,R
17293404.966193,A,P
17293405.077869,A,R
17293405.725405,R,P
17293405.815159,R,R
The following code does the following:
Read its content and store it in a list named steps
For each step in steps recognizes what happened and
If it was a shift press or release sets a flag (shift_on) accordingly
If it was an arrow pressed moves the cursor (index of current where we insert characters) – if it the cursor is at the start or at the end of the string it shouldn't move, that's why those min() and max()
If it was a letter/number/symbol it adds it in curret at cursor position and increments cursor
Here you have it
import csv
steps = [] # list of all actions performed by user
expected = "Hello"
with open("keyboard.csv") as csvfile:
for row in csv.reader(csvfile, delimiter=','):
steps.append((float(row[0]), row[1], row[2]))
# Now we parse the information
current = [] # text written by the user
shift_on = False # is shift pressed
cursor = 0 # where is the cursor in the current text
for step in steps:
time, key, action = step
if key == 'LeftShift':
if action == 'P':
shift_on = True
else:
shift_on = False
continue
if key == 'LeftArrow' and action == 'P':
cursor = max(0, cursor-1)
continue
if key == 'RightArrow' and action == 'P':
cursor = min(len(current), cursor+1)
continue
if action == 'P':
if shift_on is True:
current.insert(cursor, key.upper())
else:
current.insert(cursor, key.lower())
cursor += 1
# Now you can join current into a string
# and compare current with expected
print(''.join(current)) # printing current (just to see what's happening)
else:
# What to do when a key is released?
# Depends on your needs...
continue
To compare current and expected have a look here.
Note: by playing around with the code above and a few more flags you can make it recognize also symbols. This will depend on your keyboard. In mine Shift + 6 = &, AltGr + E = € and Ctrl + Shift + AltGr + è = {. I think this is a good point to start.
Update
Comparing 2 texts isn't a difficult task and you can find tons of pages on the web about it.
Anyway I wanted to present you an object oriented approach to the problem, so I added the compare part that I previously omitted in the first solution.
This is still a rough code, without primary controls over the input. But, as you asked, this is pointing you in a direction.
class UserText:
# Initialize UserText:
# - empty text
# - cursor at beginning
# - shift off
def __init__(self, expected):
self.expected = expected
self.letters = []
self.cursor = 0
self.shift = False
# compares a and b and returns a
# list containing the indices of
# mismatches between a and b
def compare(a, b):
err = []
for i in range(min(len(a), len(b))):
if a[i] != b[i]:
err.append(i)
return err
# Parse a command given in the
# form (time, key, action)
def parse(self, command):
time, key, action = command
output = ""
if action == 'P':
if key == 'LeftShift':
self.shift = True
elif key == 'LeftArrow':
self.cursor = max(0, self.cursor - 1)
elif key == 'RightArrow':
self.cursor = min(len(self.letters), self.cursor + 1)
else:
# Else, a letter/number was pressed. Let's
# add it to self.letters in cursor position
if self.shift is True:
self.letters.insert(self.cursor, key.upper())
else:
self.letters.insert(self.cursor, key.lower())
self.cursor += 1
########## COMPARE WITH EXPECTED ##########
output += "Expected: \t" + self.expected + "\n"
output += "Current: \t" + str(self) + "\n"
errors = UserText.compare(str(self), self.expected[:len(str(self))])
output += "\t\t"
i = 0
for e in errors:
while i != e:
output += " "
i += 1
output += "^"
i += 1
output += "\n[{} errors at time {}]".format(len(errors), time)
return output
else:
if key == 'LeftShift':
self.shift = False
return output
def __str__(self):
return "".join(self.letters)
import csv
steps = [] # list of all actions performed by user
expected = "foobar"
with open("keyboard.csv") as csvfile:
for row in csv.reader(csvfile, delimiter=','):
steps.append((float(row[0]), row[1], row[2]))
# Now we parse the information
ut = UserText(expected)
for step in steps:
print(ut.parse(step))
The output for the csv file above was:
Expected: foobar
Current: f
[0 errors at time 17293398.576653]
Expected: foobar
Current: fo
[0 errors at time 17293401.313254]
Expected: foobar
Current: foO
^
[1 errors at time 17293402.073046]
Expected: foobar
Current: foOB
^^
[2 errors at time 17293403.178612]
Expected: foobar
Current: foOBa
^^
[2 errors at time 17293404.966193]
Expected: foobar
Current: foOBar
^^
[2 errors at time 17293405.725405]
I found the solution to my own question around a year ago. Now i have time to share it with you:
In their 2003 paper 'Metrics for text entry research: An evaluation of MSD and KSPC, and a new unified error metric', R. William Soukoreff and I. Scott MacKenzie propose three major new metrics: 'total error rate', 'corrected error rate' and 'not corrected error rate'. These metrics have become well established since the publication of this paper. These are exaclty the metrics i was looking for.
If you are trying to do something similiar to what i did, e.g. compare the writing performance on different input devices this is the way to go.

Why isn't .replace working in Ruby Shoes?

I am programming a little game based on the Fate RPG. When the dice are rolled, I want to replace a string with another string using .replace. I can get it to work in an isolated environment, but when I try to call the function from inside my program; it is as if Shoes is completely unaware of it.
Here is a simple example of how the function works that is executing correctly:
Shoes.app {
#push = button "Push me"
#note = para "Nothing pushed so far"
#push.click { #note.replace "Aha! Click!" }
}
And here is the relevant code from my game:
$results = para "Roll results go here.", :align => "center",
:margin_bottom => 20, :margin_top => 8
#roll_button.click {
current_roll = Die.new
current_roll.roll
current_roll.display_dice
current_roll.tally
current_roll.calc_total_roll(1) #param = skill level
$shift = current_roll.calc_total_shift(2) #param = opposition
$results.replace "Actual results"
}
The $results block is in a different position in the code than the #roll_button.click block, but I have tries moving the click block to many different places in the code, and it didn't make a difference, so I don't think its relevant. Thanks.
*edit: Removed unnecessary '=' after $results.replace
I finally got it to work. The problem was the .display_dice function running just before .replace. The offending code is here:
if $result1 == 1
$die1.path = "dice_plus-1.png"
elsif $result1 == 0
$die1.path = "dice_nil-1.png"
elsif $result1 == -1
$die1.path = "dice_minus-1.png"
else
exit(1)
end
I intended the exit(1) to let me know if my dice were receiving values they shouldn't, but it somehow prevented the next line of code from running, even though the flow of the program avoided those lines. The fixed code is here:
if $result1 == 1
$die1.path = "dice_plus-1.png"
elsif $result1 == 0
$die1.path = "dice_nil-1.png"
else $result1 == -1
$die1.path = "dice_minus-1.png"
end
You're not calling a replace method, you're calling a replace= method which probably doesn't exist. Try it without the equals sign.

Why does that loop sometimes click randomly on screen?

I have made that loop my self and Iam trying to make it faster, better... but sometimes after it repeat searching for existing... it press random ( i think cuz its not similar to any img iam using in sikuli ) place on the screen. Maybe you will know why.
Part of this loop below
while surowiec_1:
if exists("1451060448708.png", 1) or exists("1451061746632.png", 1):
foo = [w_lewo, w_prawo, w_dol, w_gore]
randomListElement = foo[random.randint(0,len(foo)-1)]
click(randomListElement)
wait(3)
else:
if exists("1450930340868.png", 1 ):
click(hemp)
wait(1)
hemp = exists("1450930340868.png", 1)
elif exists("1451086210167.png", 1):
click(tree)
wait(1)
tree = exists("1451086210167.png", 1)
elif exists("1451022614047.png", 1 ):
hover("1451022614047.png")
click(flower)
flower = exists("1451022614047.png", 1)
elif exists("1451021823366.png", 1 ):
click(fish)
fish = exists("1451021823366.png")
elif exists("1451022083851.png", 1 ):
click(bigfish)
bigfish = exists("1451022083851.png", 1)
else:
foo = [w_lewo, w_prawo, w_dol, w_gore]
randomListElement = foo[random.randint(0,len(foo)-1)]
click(randomListElement)
wait(3)
I wonder if this is just program problem with img recognitions or I have made a mistake.
You call twice the exist method indending to get the same match (the first one in your if statement, the second time to assign it to the value. You ask sikuli to evaluate the image twice, and it can have different results.
From the method's documentation
the best match can be accessed using Region.getLastMatch() afterwards.

Cucumber and variables internal to methods called indirectly

Please note: I am new to TDD & cucumber, so the answer may be very easy.
I am creating a basic image editor for a test (the image is just a sequence of letters).
I have written a Cucumber story:
Scenario Outline: edit commands
Given I start the editor
And a 3 x 3 image is created
When I type the command <command>
Then the image should look like <image>
The step
Scenarios: colour single pixel
| command | image |
| L 1 2 C | OOOCOOOOO |
always fails, returning
expected: "OOOCOOOOO"
got: " OOOOOOOO" (using ==) (RSpec::Expectations::ExpectationNotMetError)
This is the step code:
When /^I type the command (.*)$/ do |command|
#editor.exec_cmd(command).should be
end
The function exec_cmd in the program recognizes the command and launches the appropriate action. In this case it will launch the following
def colorize_pixel(x, y, color)
if !#image.nil?
x = x.to_i
y = y.to_i
pos = (y - 1) * #image[:columns] + x
#image[:content].insert(pos, color).slice!(pos - 1)
else
#messenger.puts "There's no image. Create one first!"
end
end
However, this always fails unless I hardcode the values of the two local variables (pos and color) in the function in the program itself.
Why? It doesn's seem I'm doing anything wrong in the program itself: the function does what it's supposed to do and those two variables are only useful locally. So I'd think this is a problem with my use of cucumber. How do I properly test this?
---edit---
def exec_cmd(cmd = nil)
if !cmd.nil?
case cmd.split.first
when "I" then create_image(cmd[1], cmd[2])
when "S" then show_image
when "C" then clear_table
when "L" then colorize_pixel(cmd[1], cmd[2], cmd[3])
else
#messenger.puts "Incorrect command. " + "Commands available: I C L V H F S X."
end
else
#messenger.puts "Please enter a command."
end
end
When /^I type the command (.*)$/ do |command|
#output = #editor.exec_cmd(command)
end
Then /^the image should look like (.)*$/ do |expected_image|
#output.should == expected_image
end
Hope this may help you.
It's not a cucumber issue.
The problem was that, in exec_cmd, split was called only in the "case" clause, not in the "when"s. This meant that, since the command's format was "a 1 2 b", cmd[1] in the "when" would call the second character of the string, a space, not the second value of the array, and the other functions would convert that to_i, returning 0.
I changed exec_cmd like this:
def exec_cmd(cmd = nil)
if !cmd.nil?
cmd = cmd.split
case cmd.first
when "I" then create_image(cmd[1], cmd[2])
[...]
end
which fixed the issue.

Resources