Countdown Timer that can be extended by user input? - python

I am trying to make a little game.
I need a timer, that starts counting down in the background when the game begins (it shows the lifespan of a bonfire).
There is no need to print the remaining duration (fire_time) every second, but the user should be able to input a command (like fire) to get the remaining seconds.
The user should also be able to input words that add different amounts of seconds to the timer (like "paper", "wood", etc.)
I've tried to create a timer in a thread that is counting down with the following code:
for seconds in range(fire_time, 0, -1):
fire_timer = Timer(0, fire_time_calc, [fire_time])
fire_timer.start()
#print(f"'Fire_time' aus for-loop = {fire_time}")
time.sleep(1)
fire_time -= 1
and I've got a function that is called, that prints the time (fire_time_calc).
Currently the function is only to show how the countdown is proceeding, but I don't know if I really need it.
Currently the timer is working fine because it counts down to zero.
The problem is, that no user input is allowed until it reaches zero.
The variable fire_time needs to be updated and accessible outside of the for-loop to add time to the countdown...
Anybody got an idea how to solve this?

Related

How to fix infinite loop and functions in tkinter typing test?

Let me start off by saying I know I have several problems and errors with this code, but I am have been searching for answers and trying to solve them for many days now.
I am trying to make a basic typing test app, which calculates wpm and errors. It should last for sixty seconds on the main screen, and then an end screen should appear with your score.
My problems are:
I can't get the input from the Text widget.
My start time for the length of the test restarts with every iteration of the loop.
The main problem is getting the three main functions to work together, since one of them needs a while loop, but I cannot have the function with the while loop within the tk.mainloop(), or else it creates an infinite loop and my program breaks. If I nest the end_screen() and wpm_calc() functions in the main_screen() function, it makes the variables accessible, but the problem with the wpm_calc() function is the looping, and with the end_screen() function it is creating the new window and destroying the main one, as well as using the restart button.
I have tried some workaround with variables defined outside the functions, with global variables, and with nesting or combining the functions in various ways, none of which have worked. For the Text.get(), I have tried using text_area.get('1.0','end-1c'). This also hasn't worked.
This is close to a minimal working example.
def main_screen():
tk=Tk()
tk.title('Typing Test')
tk.geometry('800x500')
tk.iconbitmap('typing test.ico')
main_title=Label(tk,text='1 Minute Typing Test',font=('Times',36))
main_title.pack(pady=5)
directions=Label(tk,text='Start Typing to Begin!',font=('Times',14))
directions.pack()
base_text=Label(tk,text=randomizer(),bg='#E0E0EE',font=('Helvetica',12),wraplength=600,justify=LEFT)
base_text.pack(pady=10)
text_area=Text(tk,font=('Times',14),width=72,height=8,wrap='word')
text_area.pack()
target_text=randomizer()
typed_text=[]
wpm=0
errors=0
start_time=time.time()
while True:
time_elapsed=max(time.time()-start_time,1)
if time_elapsed==60:
break
wpm=round((len(typed_text)/(time_elapsed/60))/5)
key=text_area.get(0.0,END)
typed_text.append(key)
for x in typed_text:
if x != target_text:
errors += 1
end_screen()
def end_screen():
tk.destroy()
end=Tk()
end.title('Typing Test')
end.geometry('800x500')
end.iconbitmap('typing test.ico')
main_title=Label(end,text='Test Over',font=('Times',36))
main_title.pack(pady=10)
speed=Label(end,text='WPM: '+str(wpm),font=('Times',20))
speed.pack(padx=10,pady=5)
accuracy=Label(end,text='Errors: '+str(errors),font=('Times',20))
accuracy.pack(padx=10,pady=5)
restart=Button(end,text='Click to Restart',padx=10,pady=10,fg='white',bg='black',command=main_screen)
restart.pack(pady=10,padx=10)
end.mainloop()
main_screen()

Is there a known issue with Python's Threading and waiting a long time?

Sorry if this is a strange or not completely detailed question, but I have a music app, and when you pause music, then resume a long time later the app will occasionally crash. It is not consistent, around 15% of the time it'll crash, and I have not found a common cause for this. The app will crash with a:
Exception in thread Thread-46 (resume):
Traceback (most recent call last):
File "C:\Users\my_name\AppData\Local\Programs\Python\Python310\lib\threading.py", line 1009, in _bootstrap_inner
Process finished with exit code -1073741819 (0xC0000005)
The initial call calls a fuction:
def resume_thread(self):
self.is_playing = True
self.thr = KThread(target=self.resume)
self.thr.start()
self.song_begin = time.time()
It basically calls 'resume' on a thread, the other two variables are just for keeping track of internal stuff, not important. self.resume looks like:
def resume(self):
self.exited.clear()
self.resume_list.append(self.pause_time)
self.song_count -= 1
new_time = 0
self.controller.music_obj = self.current_playlist[self.song_count]
self.song = AudioSegment.from_file(self.controller.music_obj.Savelocation)
for true_time in self.resume_list:
new_time += true_time
self.song = self.song[new_time:]
self.coming_from_loop = False
self.testsong("sent")
So this function (top to bottom): clears a class variable that holds a threading.Event(). Calculates how much time is left in the song. Corrects the song index. Sends the current song to the 'controller' (MVC model). Adds up all of the time that has been paused, removes that time from the current song (so amount of song that has been played already). sets classs var (coming_from_loop (not important)), and finally, calls 'testsong', which plays the music. I have also noticed that there are two main things affecting the odds of a crash:
1). A module I use to use 'global keybinds'. Called 'system_hotkey'. I noticed that the app will have a much higher crash chance if this keybind is used to call 'pause' versus manually clicking a button (in tkinter). The app has crashed before without using it, but it produced a slightly different error that I have forgotten to document. I'll add it if I manage to reproduce it.
2). Change in how the 'time elapsed' is calculated. Before, it was a system based on the time between playing & pausing. So if you pause, then resumed 10 minutes later, it would've used that to calculate how much of the song is left. Now, it is a timer that counts down while playing music, and pauses when the song is paused. This significantly reduced how often the crash occured
3). Only ever occurs when it has been a long time elapsed since pause. Has never occurred within a smaller timeframe like 30 seconds.
I can't say for sure what causes it, as it is fairly hard to reproduce, but it seems to occur because the thread is trying to do a calculation after waiting a while (like creating a Pydub.Audiosegment), during which, it fails to do so and crashes. If you want to view all of the source code, all of it is in: https://github.com/nednoodlehead/punge/blob/master/punge_main.py Line 433-896.
Any help or thoughts are greatly appreciated.
Solution ended up being something off screen. Where the collective pause-time of one track was longer than the next track, that data would 'leak' over and try to begin the music at after it's total length. Guess it didnt audibly become apparent because it would overwrite that audiosegment with a new one, but if it failed to write the first one, the crash would occur.

Function that substracts a certain number every second on Python

I have been wondering if there is a way to create a function that subtracts one number from another but only at a given amount of time. I have read the time library, but I am still trying to figure it out. For example:
def TimeFunction:
t = 60
#What should I need to put here so for every second that passes, it subtracts 1?
This is what you are literally asking for:
import time
def TimeFunction():
t = 60
while True:
time.sleep(1)
t -= 1
Although this is not very satisfying, because your program blocks on sleep() and nothing else would be able to see the value of t.
Do you want to modify your question now and ask for something slightly different?

trying to count how many times a script inside a function is used

I am trying to use a counter how many times an object moves. There is two functions, the first one is here, the second one is here.
Here's the question:
Create a new subroutine CalculateDistance, which works out the distance between the cell currently occupied by M and the cell currently occupied by *.
Basically, I have to display the amount of moves it takes for M to reach *. I thought the most logical way of doing this would be to call MakeMonsterMove inside the new subroutine CalculateDistance as the exam paper says that is what we have to do. Then, using this algorithm:
MonsterMoves = 0
while loop
call MakeMonsterMove
MonsterMoves = MonsterMoves+1
print(MonsterMoves+1)
My logic is that each time the monster moves using the signalled subroutine, the counter will add one each time. However, whilst playing the game, the counter is always 1.Even when the M moves, it neither increases or decreases.
I'm using Python 3.
Any help would be appreciated :)

How to handle wxPython TextCtrls that influence each other's content

I am trying to build a GUI in wxPython. I have two TextCtrls. Let's say they are first_index_input and last_index_input, and they control model.f_i and model.l_i, respectively. There's a condition: For proper model execution, model.f_i must be <= model.l_i. Therefore the content of first_index_input should be <= last_index_input.
So what I want to do is fix it so that: 1) if the user enters a value into first_index_input that is greater than the value in last_index_input (established in a prior use case or something) then last_index_input and model.l_i will both be set equal to the new first_index_input. 2) If the user enters a last_index_input that is less than first_index_input, then last_index_input will be corrected again and set equal to first_index_input.
So what's so hard about that? It's a question of what event to key off of. Let's say that first_index_input has content "145" and I (correctly) want to give last_index_input an input of 10324. If this widget keys off of a wx.EVT_TEXT event, then it won't wait for me to type in "10324". As soon as it sees the "1" (i.e. first digit) it freaks out and says, "NO! That's less than first_index_input" and "corrects" my typing. On the other hand, I can get rid of this by keying off of a wx.EVT_TEXT_ENTER command, and everything works fine as long as I remember to hit return after entering my value and I never remember to hit return so I am sure my users won't either.
Is there another way to do this? Some other event that is available, perhaps? Thanks.
I would use EVT_TEXT together with a wx.Timer. The idea here is to monitor how long it's been since the user last typed something in that second control. So you'll have a start value of zero (self.start_value) and each time EVT_TEXT fires, you'll reset that value and restart the timer. When the EVT_TIMER event gets fired, it will increment the start value. You'll have to put an "if" statement in timer's event handler that checks if the start value is greater than X seconds. If it is, then do the check to see if the first input if less then the second and act accordingly. Make sure you stop the timer if it is as a running timer object can hang the app when you go to close it.
Here's a link on timers: http://www.blog.pythonlibrary.org/2009/08/25/wxpython-using-wx-timers/

Categories