We are using JES in my intro programming class and I have run into roadblock for my lab. The program is supposed to allow a user to select a picture and then a moth(bug) will start at the center of the picture and make random movements and change pixels to white if they are not already to simulate eating. I am stuck on the movement part. the current program below will load and eat 1 pixel at the very center but make no other movements. Could someone give me a hint as to what I am doing wrong with my random movement calls?
from random import *
def main():
#lets the user pic a file for the bug to eat
file= pickAFile()
pic= makePicture(file)
show(pic)
#gets the height and width of the picture selected
picHeight= getHeight(pic)
picWidth= getWidth(pic)
printNow("The height is: " + str(picHeight))
printNow("The width is: " + str(picWidth))
#sets the bug to the center of the picture
x= picHeight/2
y= picWidth/2
bug= getPixelAt(pic,x,y)
printNow(x)
printNow(y)
color= getColor(bug)
r= getRed(bug)
g= getGreen(bug)
b= getBlue(bug)
pixelsEaten= 0
hungerLevel= 0
while hungerLevel < 400 :
if r == 255 and g == 255 and b == 255:
hungerLevel + 1
randx= randrange(-1,2)
randy= randrange(-1,2)
x= x + randx
y= y + randy
repaint(pic)
else:
setColor(bug, white)
pixelsEaten += 1
randx= randrange(-1,2)
randy= randrange(-1,2)
x= x + randx
y= y + randy
repaint(pic)
Looks like you're never updating the position of the bug within the loop. You change x and y, but this doesn't have any effect on bug.
Try:
while hungerLevel < 400 :
bug= getPixelAt(pic,x,y)
#rest of code goes here
Incidentally, if you have identical code in an if block and an else block, you can streamline things by moving the duplicates outside of the blocks entirely. Ex:
while hungerLevel < 400 :
bug= getPixelAt(pic,x,y)
if r == 255 and g == 255 and b == 255:
hungerLevel + 1
else:
setColor(bug, white)
pixelsEaten += 1
randx= randrange(-1,2)
randy= randrange(-1,2)
x= x + randx
y= y + randy
repaint(pic)
Related
I am new to programming and I decided to code the game minesweeper as a way to exercise.
To do this, I started by creating a code that makes a grid of 10 x 10 cells that disappear when clicked. However the squares when clicked sometimes make other squares disappear in an unpredictable way.
Here is a gif showing what happens :
square_disappearing
Clicking the same square could make multiple squares disappear or not and I have no idea what triggers it, which makes me think the problem might not come from my code ? By the way here it is :
import pygame
import sys
listeSuppr = [] # list of squares that shouldn't be drawn
pygame.init()
WIDTH = 800
HEIGHT = 800
GREY = (50, 50, 50)
BLACK = (0, 0, 0)
def add_to_list(a, liste_locale): # looks at the position of the mouse and says what square it corresponds to
a = pygame.mouse.get_pos() # then adds it to the list of squares that shouldn't be drawn (listeSuppr)
print(a)
for x in range(HEIGHT // hauteur):
if hauteur * x < int(list(a)[1]) < hauteur * (x + 1):
break
print(x)
for y in range(WIDTH // longueur):
if longueur*y < int(list(a)[0]) < longueur*(y+1):
break
print(y)
if not [longueur*y, hauteur*x] in listeSuppr:
liste_locale.append([longueur*y, hauteur*x])
print(liste_locale)
longueur = WIDTH//10
hauteur = HEIGHT//10
screen = pygame.display.set_mode((WIDTH, HEIGHT))
game_over = False
while not game_over:
for x in range(HEIGHT//hauteur): # looks if the program should draw the squares or not
for y in range(WIDTH//longueur):
if not [longueur*y, hauteur*x] in listeSuppr:
pygame.draw.rect(screen, GREY, (longueur*y, hauteur*x, int(longueur*0.90), int(hauteur*0.90)))
else:
pygame.draw.rect(screen, BLACK, (longueur * y, hauteur * x, int(longueur * 0.90), int(hauteur * 0.90)))
for event in pygame.event.get():
if event.type == pygame.QUIT: # detects if the game has to close
sys.exit()
elif pygame.mouse.get_pressed() == (1, 0, 0): # detects when right-click has been pressed to delete the square
print(pygame.mouse.get_pos())
add_to_list(0, listeSuppr)
listeSuppr.sort()
print(listeSuppr)
elif pygame.mouse.get_pressed() == (0, 0, 1): # detects when left-click has been pressed to reset the grid
listeSuppr.clear()
pygame.display.update()
Sorry if the code looks like garbage lol. Also sorry for the half french half english names for the vars and fuctions...
If someone knows if there is something wrong with the code or the way I codded the grid, or if it isn't my fault but you know a way to fix the problem, please do tell me !
The issue always happens, when the first loop in add_to_list runs to the end and doesn't find a valid coordinate. This always happens when you click at a pixel, whose x coordinate is dividable by hauteur respectively y coordinate is divisible by longueur. In this case the condition hauteur * x < int(list(a)[1]) < hauteur * (x + 1) and/or longueur*y < int(list(a)[0]) < longueur*(y+1) is never fulfilled.
You have to evaluate <= rather than < for either the 1st or 2nd condition, to cover the full range of pixels:
if hauteur * x < int(list(a)[1]) < hauteur * (x + 1):
if hauteur * x <= int(list(a)[1]) < hauteur * (x + 1):
if longueur*y < int(list(a)[0]) < longueur*(y+1):
if longueur*y <= int(list(a)[0]) < longueur*(y+1):
Anyway, the code can be simplified by using the // (floor division) operator to compute the cell indices:
def add_to_list(a, liste_locale):
a = pygame.mouse.get_pos()
print(a)
x = a[1] // hauteur
print(x)
y = a[0] // longueur
print(y)
if not [longueur*y, hauteur*x] in listeSuppr:
liste_locale.append([longueur*y, hauteur*x])
print(liste_locale)
I want to click on a specific color on the screen with pyautogui, but for that I need its position, and I can't find any useful information about the topic. I'm trying to make a Piano Tiles autoclicker and for that I've thought about identifying the tiles' color and clicking it.
You can find color position with pyautogui:
import pyautogui
color = (255, 255, 255)
s = pyautogui.screenshot()
for x in range(s.width):
for y in range(s.height):
if s.getpixel((x, y)) == color:
pyautogui.click(x, y) # do something here
Consider making a screenshot of smaller area to identify pixels faster.
pyautogui.screenshot(region=(0,0, 300, 400))
The argument is a four-integer tuple of the left, top, width, and height of the region to capture. You can even grab only one pixel of each tile to make it work better. I don't think making a screenshot of the whole screen would be a great idea, especially when tiles goes fast.
How I would do it:
use pyautogui.position() to get coords of one pixel of each region where tiles appears (assuming color of tile is solid and is not changing during the game)
use getpixel() to obtain the RGB values of tile pixel
check in loop if pixels with coordinates from step 1 have the same RGB values you obtained in step 2.
Call pyautogui.click() if yes
Here is another version that counts how many pixels are in the region:
import pyautogui
def checkForRGBValues(start=(0,0), end=(50,50), R=255, G=255, B=255): #start/end/r/g/b value, I put some standard values for testing
x = int(end[0]-start[0] + 1) #calculates x value between start and end
y = int(end[1]-start[1] + 1) #calculates y value between start and end
how_many_pixels_found = 0 #nothing found yet
for x in range(start[0], end[0] + 1, 1): #loops through x value
for y in range(start[1], end[1] + 1, 1): #loops through y value
if pyautogui.pixel(x, y)[0] == R and pyautogui.pixel(x, y)[1] == G and pyautogui.pixel(x, y)[2] == B: #checks if the wanted RGB value is in the region
how_many_pixels_found = how_many_pixels_found + 1 #adds one to the result
y = y + 1
x = x + 1
return how_many_pixels_found #returns the total value of pixels with the wanted color in the region.
x = checkForRGBValues((150,200), (200,250), R=60, G=63, B=65)
print(x)
This is my first post! :) I had the same problem, but I found a solution. My code is probably not following any programming standard, but it is working hahaha! I started programming in Python 2 months ago (some experience 20 years ago (QBasic/C/Java), but never anything professional). Please tell me if is working for you and if there is anything that I can improve. I hope I can help somebody with this post, since this site has been helping me so much in the last 2 months!
def checkForRGBValues(start=(0,0), end=(50,50), R=255, G=255, B=255):
x = int(end[0]-start[0] + 1)
y = int(end[1]-start[1] + 1)
# print(x)
# print(y)
for x in range(start[0], end[0] + 1, 1):
for y in range(start[1], end[1] + 1, 1):
print(str(x) + "/" + str(y))
if pyautogui.pixel(x, y)[0] == R and pyautogui.pixel(x, y)[1] == G and pyautogui.pixel(x, y)[2] == B:
print("Color found")
with open("color_found.txt", "a") as file_found:
file_found.write(str(x) + "/" + str(y))
file_found.write("\n")
else:
with open("color_not_found.txt", "a") as file:
file.write(str(x) + "/" + str(y))
file.write("\n")
y = y + 1
x = x + 1
checkForRGBValues((150,200), (200,250), R=255, G=0, B=0) #if nothing (0,0), (50,50)
I am trying to code a game that has a red circle in which the user is supposed to click up to 7 times in the window. If the user clicks outside the circle, the circle will change its position to where the user clicked. And the game should end when the user has clicked 3 times inside the circle (does not have to be in a row) or when the user has clicked 7 times in total.
I have coded and done quite most of it I think, its just I cant seem to make it work as I want to.
from graphics import *
def draw_circle(win, c=None):
x = random.randint(0,500)
y = random.randint(0,500)
if var is None:
centa = Point(x,y)
var = Circle(centa,50)
var.setFill(color_rgb(200,0,0))
var.draw(win)
else:
p1 = c.p1
x_dif = (p1.x - x) * -1
y_dif = (p1.y - y) * -1
var.move(x_dif, y_dif)
return (var, x, y)
def main():
win= GraphWin("game",800,800)
score = 0
var,x,y = draw_circle(win)
while score <= 7:
mouseClick2=win.getMouse()
if mouseClick2.y >= y-50 and mouseClick2.y <= y +50 and
mouseClick2.x >= x-50 and mouseClick2.x <= x+50:
score=score + random.randint(0,5)
var,x,y = draw_circle(win, c)
print ("Success!")
print (("the score is, {0}").format(score))
thanks for the help in advance!
I see a couple problems.
your if mouseClick2.y >= y-50... conditional is spread out on two lines, but you don't have a line continuation character.
You never call main().
You don't import random.
You call draw_circle in the while loop with an argument of c, but there is no variable by that name in the global scope. You probably meant to pass in var.
c in draw_circle ostensibly refers to the circle object you want to manipulate, but half the time you manipulate var instead of c.
you assign a value to cvar in the loop, but never use it.
Your else block in draw_circle calculates the movement delta by subtracting the cursor coordinates from c.p1. But c.p1 is the upper-left corner of the circle, not the center of the circle. So your hit detection is off by fifty pixels.
import random
from graphics import *
def draw_circle(win, c=None):
x = random.randint(0,500)
y = random.randint(0,500)
if c is None:
centa = Point(x,y)
c = Circle(centa,50)
c.setFill(color_rgb(200,0,0))
c.draw(win)
else:
center_x = c.p1.x + 50
center_y = c.p1.y + 50
x_dif = (center_x - x) * -1
y_dif = (center_y - y) * -1
c.move(x_dif, y_dif)
return (c, x, y)
def main():
win= GraphWin("game",800,800)
score = 0
var,x,y = draw_circle(win)
while score <= 7:
mouseClick2=win.getMouse()
if mouseClick2.y >= y-50 and mouseClick2.y <= y +50 and \
mouseClick2.x >= x-50 and mouseClick2.x <= x+50:
score=score + random.randint(0,5)
var,x,y = draw_circle(win, var)
print ("Success!")
print (("the score is, {0}").format(score))
main()
Additional possible improvements:
Your hit detection checks whether the cursor is in a 50x50 rectangle centered on the circle. You could instead check whether the cursor is inside the circle if you measured the distance between the cursor and the center, and checked whether it was less than the radius.
var and c could stand to have more descriptive names.
mouseClick2 doesn't make much sense as a name, considering there's no mouseClick1.
The movement delta arithmetic could be simplified: (a-b) * -1 is the same as (b-a).
If you only use a variable's value once, you can sometimes avoid creating the variable at all if you nest expressions.
it might be nice to define constants, such as for the circle's radius, instead of having magic numbers in your code.
You can save five characters by using += to increment the score.
import math
import random
from graphics import *
RADIUS = 50
def draw_circle(win, circle=None):
x = random.randint(0,500)
y = random.randint(0,500)
if circle is None:
circle = Circle(Point(x,y),RADIUS)
circle.setFill(color_rgb(200,0,0))
circle.draw(win)
else:
circle.move(
x - circle.p1.x - RADIUS,
y - circle.p1.y - RADIUS
)
return (circle, x, y)
def main():
win= GraphWin("game",800,800)
score = 0
circle,x,y = draw_circle(win)
while score <= 7:
cursor = win.getMouse()
if math.hypot(cursor.x - x, cursor.y - y) <= RADIUS:
score += random.randint(0,5)
circle,x,y = draw_circle(win, circle)
print ("Success!")
print (("the score is, {0}").format(score))
main()
I'm not really a python guy, but I see that your hitbox is wrong. If there are any other issues then comment it/them to me.
Solving hitbox to be circle:
What you have already written is good to have thing but you should check if click was in circle not square. Pythagoras triangle is solution for this.
Check:
if (math.sqrt(delta_x **2 + delta_y **2) <= circle_radius)
where delta_x and delta_y is center coordinate minus mouse position
I am trying to write a mandelbrot set to an image in python, and am having a problem with one of my functions.
The issue is: While I expect something like this. I am getting a plain white image. Here is my code:
Quick Summary of code:
Check if value is in set, if it is, mark it as true in an array of booleans. Then, draw the image based on the array of booleans, coloring the true, and leaving the false ones.
import math
import numpy as np
import scipy.misc as smp
from PIL import PILLOW_VERSION
from PIL import Image
def iterate(x, y, iterationNum):
z = 0
coord = complex(x, y)
for a in xrange(iterationNum):
#Don't use fabs. It can be negative.
z = z * z + coord
#This is a comparison between complex and int. It probably won't work.
#You want |Z| which is: z.real ** 2 + z.imag ** 2 > 4
if math.fabs(z) > 2:
return False
return True
def pixel(image,x,y,r,g,b):
"""Place pixel at pos=(x,y) on image, with color=(r,g,b)"""
image.put("#%02x%02x%02x" % (r,g,b), (y, x))
#here's some example coloring code that may help:
def draw(grid):
#Create a white image with the size of the grid as the number of pixels
img = Image.new('RGB', (len(grid), len(grid)), "white")
pixels = img.load()
for row in xrange(len(grid)):
for col in xrange(len(grid[row])):
if grid[row][col] == True:
#If that point is True (it's in the set), color it blue
pixels[row, col] = (0, 0, 255)
return img
def mandelbrot():
#you should probably use a square, it's easier to deal with
#The mandelbrot set fits completely within (-2, 2) and (2, -2)
#(-200, 200), (200, -200) is way too big!
TopLeftX = -2; BottomRightX = 2
TopLeftY = 2; BottomRightY = -2
#increment should be calculated based on the size of the bounds and the number of pixels
#For example, if you're between -2 and 2 on the X-Plane, and your image is 400 pixels wide
#Then your increment = (2 - (-2)) / 400 = 4 / 400 = .01 so that each pixel is 1/400th of the
#Total width of the bounding area
increment = 0.01
maxIt = 100
w = BottomRightX - TopLeftX
h = TopLeftY - BottomRightY
#This should be based on the size of the image, one spot in the area for one pixel
npArr = np.zeros((w / increment, h / increment), dtype=bool)
#Use the increment variable from above. It won't work with xrange because that doesn't
#Support decimals. You probably want to use a while loop or something
x = -2
y = 2
while TopLeftX <= x <= BottomRightX:
while TopLeftY <= y <= BottomRightY:
#I recommend using True or False in here (in the set or not)
#And then do your color calculations as I explained above
#Saves a lot of memory
if iterate(x, y, maxIt):
npArr[x, y] = True
y += increment
#once you've calculated the Trues and Falses, you'd call the draw() function
#using the npArr as the parameter. I haven't tested the code, so there may
#be a few bugs, but it should be helpful!
x += increment
return npArr
img = draw(mandelbrot())
img.save("mandelbrot.png")
I suspect the problem is with the "iterate" function in my code, because none of the values i put in iterate are returning true.
EDIT
I have another issue as well, The second for loop I have here isnt even running.
Your handling of the y coordinate is faulty. You begin the outer loop with
y = 2
and have the loop condition as
while TopLeftY <= y <= BottomRightY:
After substituting their values, this is
while 2 <= y <= -2:
which is a nonsense. This is followed by
y += increment
but y is already at the top end of the range. Moreover, you fail to reset y for each inner loop.
To summarise, the loop should be
x = TopLeftX # use the value you already defined!
while TopLeftX <= x <= BottomRightX:
y = TopLeftY # moved to inside x loop
while TopLeftY >= y >= BottomRightY: # change the loop condition
# ... the Mandelbrot iteration
y -= increment # reverse direction
x += increment
I am no Python expert, so there may be other problems too.
I am trying to implement a program, that will increase the width of an image by one pixel. I then want to take the new maximum x ordinate and put this with a random y ordinate (that is within the range of the image) to create a new pixel.
for x in range (0,getWidth(pic)):
for y in range (0,getHeight(pic)):
X=getWidth(pic)
newX = (X+1)
colr=(255,0,0)
newPixel = getPixel (pic, newX, y)//line 25
setColor(newPixel, colr)
Y=getHeight(pic)
newY= (Y+1)
newPixel = getPixel( pic,x, newY)
setColor(newPixel, colr)
I get this error:
getPixel(picture,x,y): x (= 226) is less than 0 or bigger than the width (= 224)
The error was:
Inappropriate argument value (of correct type).
An error occurred attempting to pass an argument to a function.
Please check line 25 of D:\bla bla
I understand it is out of the range. What am I doing wrong?
Here is generalized approach to increase the size of an image keeping its current content:
Feel free to adapt.
# Increase a picture given an offset, a color and the anciant
# content must be centered or not.
# Offsets must be positive.
def increaseAndCopy(pic, offsetX, offsetY, bg_color=black, center=True):
# Offsets must be positive
if (offsetX < 0.0) or (offsetY < 0.0):
printNow("Error: Offsets must be positive !")
return None
new_w = pic.getWidth() + int(2*offsetX)
new_h = pic.getHeight() + int(2*offsetY)
startX = 0
startY = 0
if (center) and (offsetX > 1.0):
startX = int(offsetX)
if (center) and (offsetY > 1.0):
startY = int(offsetY)
new_pic = makeEmptyPicture(new_w, new_h)
# Fill with background color
setAllPixelsToAColor(new_pic, bg_color)
# Process copy
for x in xrange(pic.getWidth()):
for y in xrange(pic.getHeight()):
px = getPixel(pic, x, y)
new_px = getPixel(new_pic, x + startX, y + startY)
setColor(new_px, getColor(px))
return new_pic
file = pickAFile()
picture = makePicture(file)
# Pass an offset of 0.5 to increase by 1 pixel
#new_picture = increaseAndCopy(picture, 0.5, 0, blue)
new_picture = increaseAndCopy(picture, 10, 20, gray, True)
if (new_picture):
writePictureTo(new_picture, "/home/biggerPic.png")
show(new_picture)
Output (Painting by Jean-Michel Basquiat):
...........................................................
How can you get something that an object does not have?
newPixel = getPixel (pic, newX, y)//line 25
The original image remains sized at getWidth(pic) but you are asking for a pixel at getWidth(pic) + 1 which does not exist.
You can enlarge the image by copying it to a new picture similar to this answer.
...
newPic=makeEmptyPicture(newX,newY)
xstart=0
ystart=0
for y in range(ystart,newY):
for x in range(xstart, newX):
if x == newX or y == newY:
colour=(255,0,0)
else:
oldPixel=getPixel(oldPic,x,y)
colour=getColor(oldPixel)
newPixel=getPixel(newPic,x,y)
setColor(newPixel,colour)
explore(newPic)