How to get python to preform a function every (x) seconds? - python

I am learning python, and am trying to make (how original) a disease model, where green balls bounce around and if a red ball touches them, they get infected with the red color.
I am trying to make it so every x seconds, each infected red ball has a probability to die and turn black, but I can't figure out how to do that. I have tried to use pygame's clocks but couldn't figure it out.
here's the die function
def die(particle_list):
for i in particle_list:
if (i.colour == red) and random.choice([1,1,1,1,1,1,1,1,1,1,1,1,1,1,0])==0:
i.colour = black

If the task of checking the red balls for killing them is suppose to happen without bothering the rest of the process, then I'd suggest that you use a separate thread to check it and perform operation.
Check out the threading module in standard library for examples.
Simplest example would be:
import threading, time
def checkballs_and_turn_black(balls_data):
while True:
time.sleep(10) # sleep for 10 secs
for ball in balls_data:
if check_probability(ball):
ball.set_black()
t = threading.Thread(target=checkballs_and_turn_black, args=(actual_balls_data,))
t.start()

Use the time.sleep method. It will block program execution for the given number of seconds.
I would also like to point out that is better to use random numbers for probablilities like this. In you example your particle has a 1 in 15 chance to die, so you would want to generate a random number from 0 to 1, and i the number is bellow 0.066666667 (1 / 15) the particle will die.
This example will do what you want:
import random
def die(particle_list, death_rate):
for particle in particle_list:
if random.random() <= death_rate:
particle.color = black

I have now solved the issue. I didn't yet firgure out how multithreading works, but I will look into tutorials for that as that seems easier than what I came up with. I did this:
d = 0
def day_counter():
global day_count, timelist
time = int(pg.time.get_ticks()/1000)
if time not in timelist:
timelist.append(time)
d = True
if timelist[-1]%(seconds_in_a_day) == 0 and d:
day_count += 1
d = False
e = True
so that the constant e becomes True every in-game day (which ticks every (seconds_in_a_day) seconds) Then, I used the constant e to regulate how often the other time based functions happen, like this:
def die(particle_list):
global sick_count,dead_count,e
for i in particle_list:
if i.colour == red and e:
if r.random() < death_rate:
i.colour = black
sick_count -= 1
dead_count += 1
e = False
Answer added on behalf of OP.

Related

How could I make a dash in a 2D pygame python program?

If the pygame program is just a basic entity you can move normally with arrow keys, how could i make it so that if space is pressed, based on the arrow key that was being held at the moment of pressing, a player dashes slightly to the specified direction? My idea is that when the space is pressed, program checks if other keys are being held down and based on that it rapidly increases the x and/or y coordinate and then stops at specific time, but I don't know how to make it stop as all of this is happening inside a main game loop. Any insight is highly appreciated.
You can use time.perf_counter.
So for using that function you will need to import module time
import time
And now you can store the value of time.perf_counter in a variable when space is pressed.
import time
jumping = False
start_time = 0
while True:
if ("space is pressed"): # Replace condition with what you want
jumping = True
start_time = time.perf_counter()
# Add your code here
if jumping:
# change of x, y and other jumping mechanism code here
if jumping and time.perf_counter() - start_time > 1: # Replace 1 with the amount you want this if condition to trigger, also add value in seconds
jumping = False
I'm not sure what your code is like, but this is how I'd go about it:
def dash(self):
keys = pygame.keys.get_pressed()
if keys[pygame.K_SPACE] and not self.dashing and self.jumping:
# ^^ Can be any key
if self.facing_right:
self.x += 20
if self.facing_left:
self.x -= 20
self.dashing = True
Make sure that when you hit the ground it does self.dashing = False else you will be able to dash forever.
Just put this function in the player class if you are doing it OOP.
Else if you are not using classes, put it anywhere in the file and take out all self..

How can I make a delay in python without the camera video get affected and slowed?

Hope you are doing fine.
So my problem or question is actually more complicated than the title but I will try to keep it simple.
I have this code that runs on cam ( using OpenCV ) and will detect if a person wearing a mask or not, as far as detection go it performs very well ( I got the code from YouTube : https://www.youtube.com/watch?v=Ax6P93r32KU&t=73s ).
In short I want the program to see if the person(with confidence > 95%) is wearing a mask or not, if he is wearing the mask a pop-up message will appear thanking him then the program will close.
In theory I've done all that, The problem is that when the person wears a mask the pop-up message will immediately appear before even the cam catch up !
or if the person isn't wearing a mask then starts to wear one the pop-up message will immediately appear also while he is wearing.
Ideally I would like to check if he is wearing the mask for 2 or 3 continues seconds then the pop-up will appear.
I tried using delay but it slows the camera so much and don't see what is happening, I tried append the confidence of wearing a mask into a list then take the average of the list but still didn't work.
So ideally :
confidence of person wearing mask = M
If M > 95% for 3 seconds:
print(message(thank you))
exit()
Hope you have an idea how to solve this, and I'm sorry if my explanation isn't obvious. I can show it with a live stream (discord) for anyone who is interested and didn't understand my problem.
I was able to solve the issue by making an empty list and set t1 = time.time() ( before the while True loop )
mask_list=[]
t1 = time.time()
and inside the loop I would take the reading for 4 seconds
mask_list.append(mask)
if time.time() - t1 > 4: # when 4 seconds passes
mask_avg = sum(mask_list) / len(mask_list)
if mask_avg*100 > 90: # when the average of wearing a mask is > 90%
# code for wearing a mask then exit()
else :
# code for NOT wearing a mask then exit()
I'm not sure if I'm allowed but I will post the code on GitHub if anyone wants to see the full code : https://github.com/Dalsallum/Login-System-With-Mask-Detection
So if i understand properly, something like this should work. Let me know what happends or if you dont understand something. This code uses multiple threads as to not stop the video portion of code.
import time
import threading
wearingMaskBool = False
def checkPerson3Seconds():
global wearingMaskBool
#lets check the person 6 times we will use multiple threads so the camera and the 3 second check code can run simpltaniously
for i in range(6)
if (M > 95%):
#adding one if mask is worn
wearingMask += 1
else:
#subtracting one if mask isnt worn
wearingMask -= 1
#wait half a second
time.sleep(0.5)
#checking if wearingMask == 6
if wearingMask == 6:
#execute code for person that is wearing mask
#example
# we can define the "wearingMaskBool" as a global and use it in out main script
wearingMaskBool = True
else:
#execute code for person that isnt wearing mask
#example
# we can define the "wearingMaskBool" as a global and use it in out main script
wearingMaskBool = False
#start thread aka staring the checkPerson3Seconds script
threading.Thread(target=checkPerson3Seconds(), daemon=True).start()
#after the script is ran if they are wearing a mask with a certainty of 95 percent of 3 seconds the the wearingMaskBool will be equal to true
#if it fell below 95% it will be equal to false

Get Python turtle window to display graphics and remain open

In this code I can't see why it isn't printing a hexagon 24 times. I tell it to make a 6 sided shape with 60 degrees between lines ( a hexagon) and tell it do turn 15 degrees each time. This ends up being a even 24 for the picture I'm trying to draw.
import turtle
Hex_Count = 0
x = turtle.Turtle()
x.speed(.25)
def Hexagon():
for i in range(24):
for i in range(6):
x.forward(100)
x.left(60)
Hex_Count = Hex_Count + 1
x.left(15)
print(Hex_Count)
Hexagon
But, for some reason, when I run this code the turtle screen pops up for about a half second then closes. How do I get it to perform in the way I want it to?
You have several errors that I corrected for you; I added the explanation in the comments:
import turtle
hexagons_count = 0
my_turtle = turtle.Turtle() # x is not a good name for a Turtle object
# my_turtle.speed(.25) # see #cdlane comment reported in a note under.
def draw_hexagon(): # use explicit names respecting python conventions (no camel case)
global hexagons_count # need global to modify the variable in the function scope
for idx in range(24): # use different dummy variable names in your loops
for jdx in range(6): # use different dummy variable names in your loops
my_turtle.forward(100)
my_turtle.left(60)
hexagons_count += 1
my_turtle.left(15)
print(hexagons_count)
draw_hexagon() # need parenthesis to call the function
turtle.exitonclick() # this to exit cleanly
Note: I know you simply copied it from the OP but my_turtle.speed(.25)
doesn't make sense as the argument should be an int from 0 to 10 or a
string like 'slow', 'fastest', etc. I especially don't understand why
beginners with turtle code that isn't working call turtle.speed() at
all -- it seems to me a function to be tweaked after everything is
working. #cdlane
You have some reference issue, you just need to put the variable hex_count where it needs to be so you don't have error accessing it.
import turtle
x = turtle.Turtle()
x.speed(.25)
def Hexagon():
Hex_Count = 0
for i in range(24):
for i in range(6):
x.forward(100)
x.left(60)
Hex_Count += 1
x.left(15)
print(Hex_Count)
Hexagon()
prints 24
You have several problems with your program. One is that it will when after running through the program, closing the window it created. You can add turtle.exitonclick() to the end of your script which tells python to wait for a click in the graphics window, after which it will exit.
The second problem is that you don't call the Hexagon function because you're missing the parentheses. Even if a function takes no arguments, you still need to call it like:
Hexagon()
The final problem is that you need to define Hex_Count before you try to increment it. Hex_Count + 1 will thrown an error if Hex_Count wasn't already assigned to. You can fix this by putting
Hex_Count = 0
before your for loop in Hexagon.
An approach different in a lot of the details but primarily in its use of circle() to more rapidly draw the hexagons:
from turtle import Turtle, Screen # force object-oriented turtle
hex_count = 0 # global to count all hexagons drawn by all routines
def hexagons(turtle):
global hex_count # needed as this function *changes* hex_count
for _ in range(24): # don't need explicit iteration variable
turtle.circle(100, steps=6) # use circle() to draw hexagons
turtle.left(15) # 24 hexagons offset by 15 degrees = 360
hex_count += 1 # increment global hexagon count
print(hex_count)
screen = Screen()
yertle = Turtle(visible=False) # keep turtle out of the drawing
yertle.speed('fastest') # ask turtle to draw as fast as it can
hexagons(yertle)
screen.exitonclick() # allow dismiss of window by clicking on it

How to make one cannon instead of multiple?

I am currently in the process of making a new cannon game. How can I make it so that there is just one cannon, on the bottom left hand of the screen?
from graphics import *
from math import sqrt
from math import trunc
def PinR(p,r):
if p.getX()>=r.getP1().getX() and p.getX()<=r.getP2().getX()and p.getY()>=r.getP1().getY() and p.getY()<=r.getP2().getY():
return True;
else:
return False;
def distance(p1,p2):
dx=p1.getX()-p2.getX();
dy=p1.getY()-p2.getY();
dist=sqrt(dx*dx+dy*dy);
return dist;
#parameter
FieldWidth=700;
FieldHeight=700;
GroundDepth=75;
BallSize=10;
OriginalSpeed=4;
FieldBackground="brown";
FieldBorder="brown";
tickLength=800000;
buttonSize=8;
# number of cannons and balls
numBalls=4;
# initial cannon power
explosionStrength=30;
# intial gravitational constant
g=1;
# clock tick delay
delay=0.05;
#Create field
Field=GraphWin("B",FieldWidth,FieldHeight);
Field.setBackground(FieldBackground);
#set of balls
spacing=FieldWidth/(numBalls);
ball=[];
for b in range (0,numBalls):
newball=Circle(Point(spacing*b+spacing//2,FieldHeight-GroundDepth),BallSize);
newball.setFill("black");
newball.draw(Field);
ball.append(newball);
#cannon
cannon=[]
for c in range (0,numBalls):
newCannon=Rectangle(Point(spacing*c+spacing//2-BallSize,FieldHeight-GroundDepth-BallSize*5),
Point(spacing*c+spacing//2+BallSize,FieldHeight-GroundDepth+BallSize));
newCannon.setFill("black");
newCannon.draw(Field);
cannon.append(newCannon);
#set of button groups (fire, powerup, powerdown)
fire=[];
for f in range (0,numBalls):
newbutton=Rectangle(Point(spacing*f+spacing//2-buttonSize//2,FieldHeight-GroundDepth-BallSize),
Point(spacing*f+spacing//2+buttonSize//2,FieldHeight-GroundDepth-BallSize+buttonSize));
newbutton.setFill("red");
newbutton.draw(Field);
fire.append(newbutton);
#wall
#target(red,white,red,white)
balldistance=20;
ball1=Circle(Point(FieldWidth//2-20,FieldHeight//2+20),BallSize);
ball1.setFill("red");
ball1.draw(Field);
The reason you get 4 cannons is that you're doing this:
for c in range (0,numBalls):
… where numBalls is 4, and you create a new cannon each time through the loop.
Presumably with only 1 cannon you also only want one cannon ball and one shot, so just set numBalls = 1 instead of numBalls = 4.
However, it might make more sense to simplify the program while you're at it. Replace the lists of 4 cannons with a single cannon, get rid of the loop, do the same for the 4 balls, etc. Then you can also simplify the layout rules—no need for a spacing variable to configure how far apart the cannons are if there's only 1 of them. And so on. This might make it easier for you to understand how the program works—and figuring out how to simplify it might similarly be beneficial on its own.
And if you want to change its position, that's being set in this line:
newCannon=Rectangle(Point(spacing*c+spacing//2-BallSize,FieldHeight-GroundDepth-BallSize*5),
Point(spacing*c+spacing//2+BallSize,FieldHeight-GroundDepth+BallSize));
So, you can tweak the various constants (which all seem to have pretty reasonable names) to get the result you want—or, of course, just hardcode the position you want instead of calculating it.

Python IF statement to see how long an input has been active

I am using a raspberry pi, a pi face and a python script to monitor several home sensors. I want to add the sensing wire from the smoke detectors to that list but I need a bit of help with the if statement.
I'm unsure how to tell the if statement to check how long the input has detected the signal. Under 4 seconds disregard (low battery chirp), over 4 seconds (smoke detected) alert me..
Basically I need help writing the if statement below.
if piface.digital_read(0)==0 >= 4 seconds:
# do x
else:
# do y
Do I need a loop and can it be as easy as what I have above? (Coded correctly of course!)
Something like this (untested pseudo-code):
counter = 0
while True: #your main loop
smoke = digital_read() #assume 0 = no alarm, 1 = alarm
if smoke:
counter += 1
else:
counter = 0
if counter >= 4: #there was smoke for the last 4 seconds
call_the_fire_brigade()
time.sleep(1) #wait one second
I guess you probably need some loop.
Well I think a good solution to this would be spawn a separate thread for each detector and then use a blocking for the number with a loop.. like
count = 0
while count < 4:
if piface.digital_read(0) == 0:
count += 1
else: count = 0
sleep(4000)
# ... rest of code ...

Categories