How to speed up a for loop that moves labels up? - python

For my project I'm making a game with moving notes up. But the movement becomes inconsistent depending on notes amount. Here is the code and I want to speed up function "Update".
from multiprocessing import Process
import time
from tkinter import *
def wait(timee):
for i in range(int(timee*10000000)):
time.perf_counter()
def updateNotes(songdata):
global hp
speed=songdata['Data']['Speed']
tick=0
notearriving=0.9
toadd=1/100
toaddtick=1/10/speed
timetowait=1/100/speed
steps=notearriving/toadd
delay=steps*toaddtick
root.update()
tick=delay
# for i,v in enumerate(songdata['Notes']):
# changed=int(songdata['Notes'][i]['Time'])*toaddtick
# if type(songdata['Notes'][i]['Time'])==str:
# songdata['Notes'][i]['Time']=str(changed)
# else:
# songdata['Notes'][i]['Time']=changed
Get_Songs(songdata['Data']["Name"])
while True:
if hp <=0:
root.destroy()
SpawnNotes(tick-delay,songdata)
tick+=toaddtick
def Update(half):
global hp
middleIndex = math.ceil(len(notes) / 2)
if half == 1:
newlist=notes[0:middleIndex]
elif half == 2:
newlist=notes[-middleIndex:]
else:
newlist=notes
for i,v in enumerate(newlist):
note = v['note']
currentpos=v['currentypos']#-70
change=currentpos-toadd
note.place(relx=v['xpos'],rely=change)
notes[i]['currentypos']=change
if change<1-notearriving and v['owner']=='Enemy':
notes.remove(v)
note.destroy()
break
if configData['WindowSize'][1]*change+note.winfo_height()<0:
if v['owner']=='Player':
hp-=songdata['Data']['NoteDamage']
note.destroy()
notes.remove(v)
#---code with multiprocessing------
if len(notes)>=2:
a=Process(target=lambda: Update(1))
a.start()
a.join()
f=Process(target=lambda: Update(2))
f.start()
f.join()
else:
f=Process(target=lambda: Update(3))
f.start()
#---------------------------------------
# Update(3) code without multiprocessing
root.update()
wait(timetowait)
I tried Multiprocessing, but it gives me an error "EOFError: Ran out of input". Also I tried to do it with Pool, but it made even worse.

Related

How to print countdown timer and accept user input at the same time (python)?

Clarificaition
This is a repost of my previous question as I am extremely desperate to receive an answer to my problem. I am quite new and if this is against any of the rules, please inform me as I would remove this post if so.
I want to create a quiz-like program where the user would be able to see the countdown timer ticking down every second while they can input their answer at any time. According to my previous post regarding this question, I've tried using threading in my code. Here is a sample of my code.
from threading import Thread
import time
import sys
def func1():
t = 10
for t in range (t,1,-1):
sys.stdout.write('\r' + str(t))
sys.stdout.flush()
time.sleep(1)
if __name__ == '__main__':
Thread(target = func1).start()
answer = input("\tEnter: ")
It does function, but the problem is that the user input is forced to return back (\r) while the timer doesn't properly remove the '0' of the 10 which is not what I desire. Here is the output:
It would be a tremendous help if you could suggest a solution to this problem. Thank you in advance.
After some messing around, I came up with this.
If you would like me to edit this to make it work without the windows, let me know.
import time
import tkinter
from tkinter import messagebox
from tkinter import *
from tkinter import ttk
from threading import Thread
def clear():
print('\033[H\033[J', end='')
run = True
def timer():
tim = int(input("Type how long the countdown should last in seconds: "))
clear()
count = 0
while count < tim and run == True:
clear()
b1 = (tim-count)
c = (str(b1),"second(s) left")
win = Tk()
win = Tk()
win.attributes('-fullscreen', True)
if run == False:
win.destroy()
Label(win, text= c,
font=('Helvetica 20 bold')).pack(pady=20)
win.after(1000,lambda:win.destroy())
win.mainloop()
time.sleep(1)
count += 1
def take_input():
inpu = input()
#Your code
def time_input():
global run
while run == True:
t1 = Thread(target=timer)
t2 = Thread(target=take_input)
t1.start()
t2.start()
t2.join()
thread_running = False
run = False
time_input()
Hope this helps, and you're welcome. 乇卩丨匚卄乂尺
(To stop the window from being fullscreen, change the (window).attributes('-fullscreen', True) to (window).geometry(500x500) or whatever you wish.

How do i do some stuff and count time in parallel in python?

I want my code to take some integers for some time (e.g. 10 seconds) and to count and print time every second. So it prints time permanently and i enter some numbers whenever i want. Maybe i should use async functions?
def accepting_bets():
global list_of_bets
list_of_bets = []
list_of_bets.append(int(input()))
def main():
i = 10
while True:
print(f"{i} seconds remaining...")
time.sleep(1)
i -= 1
accepting_bets()
if i == 0:
break
print(list_of_bets)
You can move the timing code to a different thread.
I would recommend researching about multi-threading in Python if you aren't aware about it.
import threading
import time
def countTime():
i = 10
while True:
print(f"{i} seconds remaining...")
time.sleep(1)
i -= 1
if i == 0:
break
print(list_of_bets)
thread1 = threading.Thread(target=countTime)
thread1.start()
# while you want to get the input
global list_of_bets
list_of_bets = []
list_of_bets.append(int(input()))
The countTime function will keep on running on another thread, and will not be paused by the input statement

Seconds Counter and score keeper in with python tkinter

im a beginner in python and i have a big trouble for this code. im making a small match making game and this game made me hate python.
simply, user should match the photos together and try to do it as fast as possible for getting less time.
however, the timer is never working or giving me recursion limit error.
i want a simple second counter and a way to count the score.
so far, this is what i have and the timer is happening only once. so the label just becoming 1
import mycanvas as mc
import tkinter as tk
import random as r
import time
clickedimages=[]
score = 0
seconds=0
def main():
root=tk.Tk()
root.geometry("550x800")
root.resizable(0,0)
coverimg=tk.PhotoImage(file="pics\\qs.png")
name=""
images=[]
coppyimages=[]
allcanvas=[]
lbl=tk.Label(root,text="0",font=('robot',20))
lbl2=tk.Label(root,text=str(score),font=('robot',20))
lbl.place(x=100,y=750)
lbl2.place(x=400,y=750)
#making images
for x in range(1,11):
name="pics\\p"+str(x)+".png"
images.append(tk.PhotoImage(file=name))
coppyimages.append(tk.PhotoImage(file=name))
coppyimages.append(tk.PhotoImage(file=name))
#5x4
#positioning
tx=50
ty=150
counter=1
for x in range(0,5):
for y in range (0,4):
choice=r.randint(0,len(coppyimages)-1)
allcanvas.append(mc.myconvas(root,counter,coppyimages.pop(choice),tx,ty,coverimg))
tx+=120
counter+=1
tx=50
ty+=120
root.after(1000,timer(lbl))
root.mainloop()
def timer(lbl):
global seconds
seconds+=1
lbl.configure(text=str(seconds))
def clicked(event):
if(len(clickedimages)==0):
event.widget.showorhide()
clickedimages.append(event.widget)
elif((len(clickedimages)>0) and (event.widget != clickedimages[0])):
event.widget.showorhide()
clickedimages.append(event.widget)
matchchecker()
def matchchecker():
global clickedimages,score
time.sleep(0.5)
if(clickedimages[0].nameofimage==clickedimages[1].nameofimage):
print("Its a match")
clickedimages[0].place_forget()
clickedimages[1].place_forget()
score+=1
else:
print("wrong :(")
clickedimages[0].showorhide()
clickedimages[1].showorhide()
clickedimages.clear()
gamechecker()
def gamechecker():
global score
if(score==10):
print("Game over")
if __name__ == '__main__':
main()
the class is :
import tkinter as tk
import main
class myconvas(tk.Canvas):
number=0
myimage=None
nameofimage=""
coverimg=None
show=True
def __init__(self, root,n,img,px,py,dfault):
super().__init__()
self["width"] = 100
self["height"] = 100
self.number=n
self.myimage=img
self.maketheimage(dfault,px,py)
self.nameofimage = img.cget('file')
# self.setimagename()
self.coverimg=dfault;
self.bind("<Button-1>",main.clicked)
# root.after(500,self.showorhide())
def maketheimage(self,img,px,py):
self.create_image(50,50,image=img,anchor='center')
self.place(x=px,y=py)
def setimagename(self):
self.nameofimage=self.myimage.cget('file')
def showorhide(self):
if(self.show):
self.create_image(50,50,image=self.myimage,anchor='center')
self.show=False
else:
self.create_image(50,50,image=self.coverimg,anchor='center')
self.show=True
thank you in advance

Ending a thread that contains an infinite loop

I'm trying to use python to turn on some RGB lights after motion is detected. My code is below but I can't get the thread to end and switch off the LEDS. All that happening is I get stuck after keyboard interrupt.
Essentially when I run the code it works to detect movement and switch the lights on but then when I try to end the program with a keyboard interupt exception either the program hangs and doesn't stop or it stops but the LEDs don't switch off and stay lit. I've looked at various pages about how to stop a thread running but none of it has helped. Below are the articles I've looked at. I think my issue is that the thread running the lighting pattern loop isn't stopping so when I try to turn each LED off its turned back on immediately but I'm not sure.
I can't get the thread to stop any way I've tried. Any help would be much appreciated.
How to stop a looping thread in Python?
https://www.oreilly.com/library/view/python-cookbook/0596001673/ch06s03.html
https://www.geeksforgeeks.org/python-different-ways-to-kill-a-thread/
Threading an Infinite Loop
Stopping a python thread running an Infinite Loop
Threading infinite loop in python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Jan 1 10:10:25 2020
#author: thomas
"""
import RPi.GPIO as GPIO
import time
import subprocess
import argparse
from neopixel import *
import datetime as dt
from threading import Thread
from threading import enumerate
from threading import Event as EV
import sys
global stop
GPIO.setmode(GPIO.BCM)
# LED strip configuration:
LED_COUNT = 288 # Number of LED pixels.
LED_PIN = 18 # GPIO pin connected to the pixels (must support PWM!).
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
LED_CHANNEL = 0
LED_STRIP = ws.SK6812_STRIP_RGBW
#LED_STRIP = ws.SK6812W_STRIP
# Define functions which animate LEDs in various ways.
def wheel(pos):
"""Generate rainbow colors across 0-255 positions."""
if pos < 85:
return Color(pos * 3, 255 - pos * 3, 0)
elif pos < 170:
pos -= 85
return Color(255 - pos * 3, 0, pos * 3)
else:
pos -= 170
return Color(0, pos * 3, 255 - pos * 3)
def colorWipe(strip, color, wait_ms=20):
"""Wipe color across display a pixel at a time."""
for i in range(strip.numPixels()):
strip.setPixelColor(i, color)
strip.show()
time.sleep(wait_ms/1000.0)
def rainbowCycle(strip, wait_ms=20, iterations=5):
"""Draw rainbow that uniformly distributes itself across all pixels."""
while not stop:
for j in range(256*iterations):
for i in range(strip.numPixels()):
strip.setPixelColor(i, wheel(((i * 256 // strip.numPixels()) + j) & 255))
strip.show()
time.sleep(wait_ms/1000.0)
class RainbowLights(Thread):
def __init__(self, name="RainbowLights"):
self._stopevent = EV()
self.sleeppreiod = 1.0
Thread.__init__(self, name=name)
def run(self):
while not self._stopevent.isSet():
rainbowCycle(strip)
self._stopevent.wait(self._sleepperiod)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-c', '--clear', action='store_true', help='clear the display on exit')
args = parser.parse_args()
# Create NeoPixel object with appropriate configuration.
strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_STRIP)
# Intialize the library (must be called once before other functions).
strip.begin()
print ('Press Ctrl-C to quit.')
if not args.clear:
print('Use "-c" argument to clear LEDs on exit')
GPIO.setup(22, GPIO.IN) #PIR
rta = "none"
time1 = "none"
stop = False
RainbowLights = RainbowLights()
try:
time.sleep(2) # to stabilize sensor
while True:
trigger = GPIO.input(22)
if trigger == 1:
print("Motion Detected...")
if rta == "running":
print("Lights Already On")
else:
RainbowLights.start()
rta = "running"
time1 = dt.datetime.now()
time.sleep(5) #to avoid multiple detection
elif trigger == 0:
print("No Motion...")
print("Lights turned on at " + str(time1))
time.sleep(0.1) #loop delay, should be less than detection delay
except KeyboardInterrupt:
RainbowLights._stopevent.set()
stop = True
time.sleep(5)
if args.clear:
colorWipe(strip, Color(0,0,0), 10)
GPIO.cleanup()
Reduced to a minimal example so it can run without hardware. Comments added for fixes. The main problem was stop was only checked after 256*iterations*wait_ms/1000.0 or 25.6 seconds, so stopping appeared unresponsive. A few other bugs as well. Global stop is sufficient to end the thread so the Event wasn't needed.
import time
import argparse
from threading import Thread
import sys
global stop
def rainbowCycle(strip, wait_ms=20, iterations=5):
"""Draw rainbow that uniformly distributes itself across all pixels."""
while not stop:
for j in range(256*iterations):
if stop: break # add stop check here for responsiveness.
print(f'rainbowCycle')
time.sleep(wait_ms/1000.0)
print('stopping...')
class RainbowLights(Thread):
def __init__(self, name="RainbowLights"):
print('__init__')
Thread.__init__(self, name=name)
def run(self):
print('run')
rainbowCycle(strip)
print('stopped')
if __name__ == '__main__':
strip = None
print('Press Ctrl-C to quit.')
rta = "none"
stop = False
rainbow_lights = RainbowLights() # renamed variable so it doesn't replace the class.
try:
time.sleep(2) # to stabilize sensor
while True:
trigger = 1 # pretend some motion
if trigger == 1:
print("Motion Detected...")
if rta == "running":
print("Lights Already On")
else:
rainbow_lights.start()
rta = "running"
time.sleep(5) #to avoid multiple detection
elif trigger == 0:
print("No Motion...")
time.sleep(0.1) #loop delay, should be less than detection delay
except KeyboardInterrupt:
print('KeyboardInterrupt')
print('stop')
stop = True
Press Ctrl-C to quit.
__init__
Motion Detected...
run
rainbowCycle
rainbowCycle
rainbowCycle
rainbowCycle
rainbowCycle
rainbowCycle
rainbowCycle
rainbowCycle
rainbowCycle
rainbowCycle
rainbowCycle
rainbowCycle
KeyboardInterrupt
stop
stopping...
stopped

I am testing out threading.Time in this little game I made, but it keeps overlapping

import time
from threading import Timer
from random import randint
print("Every wrong answer is a 3s delay; you have 30s")
end = False
def lose():
print(end)
print("Time up!")
time.sleep(1)
print("Score is",pts,", with",wrong,"wrong answers.")
time.sleep(1)
input("enter to quit")
quit()
timer = Timer(10,lose)
timer.start()
pts = 0
wrong = 0
while end == False:
a = randint(5,50)
b = randint(5,50)
print(a,"+",b)
ans = input()
if ans.isnumeric():
ans = int(ans)
if ans == a+b:
print("correct")
pts = pts+1
else:
print("wrong,",a+b)
wrong = wrong+1
print("delay")
time.sleep(3)
print("delay end")
print("")
When the timer finishes, the loop overlaps the 'lose' function, and it messes up on the line like this:
Time up!
45 + 10
55
Score iscorrect
3
, with29 0+ wrong answers.37
enter to quitwrong,p
66
delay
How do I fix this issue?
Sorry if this question has already been answered, but I want to know.
Ideally, you should probably avoid using threads altogether, as mentioned in the comments.
However, if you are going to use threads, consider using a mutex to ensure that multiple threads are not trying to write to stdout at the same time.
For example:
# setup at the beginning:
from threading import Thread, Lock
mutex = Lock()
# surrounding each print statement:
mutex.acquire()
try:
print('text')
finally:
mutex.release()

Categories