Why does my code give wrong values for variables? - python

I know the question is not very precise, and that is because I have no idea what is going on either. I have narrowed down the problem to a couple of lines, but to me the execution seems rather weird.
def loadmaze(backup):
test = createmaze(10,10) #This creates a new 10x10 matrix
maze = placewalls(test, "x") #The X is a string with wall positions
if maze != test:
#when placewalls executed correctly, and returned a maze different from the original
showmaze(maze) #simply printing maze to console
else:
return backup #so nothing changes, looks as if function never happened
return maze,10,10
# this returns the new maze, with walls, and the dimensions of the new maze
def placewalls(amaze,positions):
#placing walls, definitely correct
return amaze-with-walls
Obviously I changed the variable names so it's clear what I'm doing.
The problem is, when I call the function loadmaze(maze), it never returns a maze with walls. Somehow the test and maze values are always identical. I do not understand how this can be as the maze with walls is assigned to maze after test, which at that point does not have walls.
According to the debug, test also contains the walls after the third line has been executed.
Please help, I'm terribly confused.

As #stephan said, the variables test and maze refer to the same objects in the memory. So I changed maze = placewalls(test,"x") with maze = placewalls(createmaze(10,10),"x"), thus creating a new object different from maze. This then results in test and maze being two different mazes.

Related

Object's location not recognized when solving maze

When I run my code, it opens up a random-generated maze for the user to solve by using the agent object, mover, to move around the maze. When my object reaches the end of the maze, in which it is at the top-left of the maze with the position (1,1), I want it to print "Done" in the terminal. The problem is that the program won't recognize the status of the object's position when it is at the end of the maze, resulting in the conditional statement (shown below) not working.
from pyamaze import maze,COLOR,agent,textLabel
m=maze(10, 10)
m.CreateMaze()
mover = agent(m, footprints=True, color = "red")
m.enableWASD(mover)
if(mover.position == (1,1)):
print("Done")
m.run()
However, when I place my object at the end of the maze then run the program, the conditional statement surprisingly works and it prints out the result. The problem is that I want my object to be controlled by the user when it starts off at the bottom of the maze and when the user reaches the end of the maze, I want the conditional statement to work and print out the result in the terminal.
mover.position = (1,1)
if(mover.position == (1,1)):
print("Done")
Can someone help me in solving this problem, so that my object's position can be recognized when the user reaches the end of the maze, making the conditional statement to work?

Python: implement a "software-wide" setting that does not change often without running an if statement in every loop

I want Python to kind of ignore a statement that is unlikely to be called in a function that is often called.
I do not have a formal education in programming, so please excuse my lackluster ability to desribe things. I will try to explain the concept by example.
Say I am writing a video game, first-person shooter, drawing 60 frames per second.
In the settings menu, the user can select whether or not to display the name of other players above their head. If they disable this, I store this value as showplayernames = False.
Then in my drawing function that outputs the graphics I have:
def draw():
#code that draws the graphics on screen
if showplayernames:
#code that draws the name of players on screen
I call this function 60 times a second, but there is absolutely no point for checking if showplayernames is True 60 times a second. It will not change that often, in fact I could make this a kind of "constant" during play by preventing it to change. If showplayernames is False, then the third and fourth lines of the code are completely redundant, but they are executed nevertheless. The computer isn't smart enough to know it can ignore it, and there is a performance difference: reading a value and then checking if it is false takes time.
I could write two copies of the game (or at least the draw() function), one with only the first two lines when the user selects not to show names in the settings, and another without the if statement, and then run the appropriate one.
def draw_with_names():
#code that draws the graphics on screen
#code that draws the name of players on screen
def draw_without_names():
#code that draws the graphics on screen
Although looping through either of these 60 times a second is more efficient than running draw() ,this is obviously not the way to go. There are dozens of settings like this.
So how do software and game designers implement these kind of "software-wide" settings efficiently?
I'm not a game developer, but here's one option. Create a list of function pointers and add or remove from the list based on settings. Example:
def draw_player_names():
# Code to overlay names
def draw_fps():
# Code to overlay fps
def draw():
# Main code to draw a frame of the game
# Hold all the functions to call
optional_funcs = []
if showplayernames: optional_funcs.append(draw_player_names)
if show_fps: optional_funcs.append(draw_fps)
# Main game loop
while True:
draw()
for f in optional_funcs: f()
This can be extended for any number of functions/options.
not an game designer, but here is my voice.
You could store settings inside json file next to you python, but then you need to cover reading, getting right values etc.
You could use Environment variables to store value but that would end up using still "if" in the code.
Game designers use triggers and events to get things done, and on the lowest level I would assume those things also use if's.
system-wide-settings will in the end be used with if's
You could use overwrites based on event/trigger and use "same" draw function in both times but that only complicates code, and we all know to "keep it simple".
Sorry if this is not the answer you were looking for.
As Matthias said, you shouldn't really bother about this kind of optimization. Look at these two very silly functions:
def lot_of_ifs(settings):
#do something
a=2**10
b=2**10
c=2**10
for setting in settings:
if setting:
#do something more
a=2**10
b=2**10
c=2**10
def no_ifs():
#do something
a=2**10
b=2**10
c=2**10
timeit("lot_of_ifs([0,0,0,0,0])", globals=globals())
0.2630380000000514
timeit("no_ifs()", globals=globals())
0.10232830000040849
The cost of creating a list, looping over it, and executing five ifs is about 0.16 seconds for one million iterations, or 160 nanoseconds per iteration, while at 60 fps you have 16.6 million nanoseconds to execute your code.

Characters S, 5, and 3 in Python with Turtle Graphics?

Currently I am trying to use commands to tell a turtle to draw the characters "S," "3," and "5" using the turtle module - without using the command turtle.write. Currently my code looks like:
import turtle
def halfcircle(parts=360, line=1, direction=1):
for x in range(parts//2):
turtle.forward(line)
turtle.left(360/parts * direction)
turtle.tracer(False)
for x in range(2):
halfcircle(20, 360/30, 1)
halfcircle(20, 360/30, -1)
turtle.update()
But the loop is never ending. Additionally, I am unable to incorporate linear and nonlinear lines into one character in order to draw a 5 or 3. Any help would be much appreciated.
Before I could actually check this out, I had to add an extra line of turtle.exitonclick() to the script to prevent it from disappearing from my screen as soon as I ran it.
From what I'm seeing, it doesn't appear to actually be never ending. The turtle draws four half-circle shapes then stops. When you say never ending, do you mean that it's repeating more than you wanted/expected? Or are you calling this code somewhere else and it's really never stopping in some other part?
If you just mean that it's drawing too many half-circles (4, when you want 2 to make an S), that's because of the 2 in your for-loop for x in range(2): that for-loop has two half-circles in it, so when the loop runs twice (because of range(2)), you get 2 * 2 = 4 half-circles. [BTW, as a convention, we generally use a single underscore _ to indicate "throw-away" variables. You'll see that the var x does not actually get used in your for-loop, it's just necessary to state some var for the for-loop syntax. A lot of Python programmers just write for _ in range(2) as a way of saying, "Don't pay attention to this var, it's not going to get used."]
So if you change the for-loop from range(2) to being range(1), you get a single pair of half-circles and the program halts on this image:
Which, admittedly, is not a great S shape, but it's getting there. In general, drawing symbols is hard. I think a really good S is probably the hardest one. I think the easiest might be a 5? The best approach to figuring out how to code symbols is to draw it very large and very carefully on graph paper, then break it down into its component parts. Let's use 5 as an example, working from bottom to top:
A curved section, maybe half-circle, maybe more like 2/3's of a circle, maybe more of an ellipse, kinda hard to be certain.
A straight line going (mostly) up (or maybe just a hair to the right)
A straight line going directly right, a little longer than the previous line
Then, with that series of motions in mind, create code to draw each piece on its own. Once you've done that, just have the turtle draw the first piece, then immediately draw the next, then the next. You'll have to figure out how to reset the turtle's direction between pieces, but other than that, you'll have a 5! It's not so much that you want to have nonlinear and linear segments together, as a single symbol is created by drawing one segment after another, and you just write code that draws the specific segment one at a time.

Efficient collision detection

I am using python and pyglet in a 2d game but I have come across a problem in collision detection. My code to check for collision looks like this:
def distance(self,target):
return math.sqrt((self.x-target.x)**2 + (self.y-target.y)**2)
def check_collision(self):
for i in list_of_mobs:
if self.distance(i) < (self.width/2 + i.width/2):
return True
It checks the distance from each sprite with "target" being another sprite. The thing I am unsure of is "should I be checking for collisions between all the sprites?" I have over 200 mobs (even more I hope in the finished product) and it becomes unplayable when the collisions are checked. Is there someway to only check sprites within a certain distance without losing speed?
EDIT:
I had a read around google and found out that a lot of the speed was spent doing the same collisions. i.e. sprite1 was checked with sprite2 and sprite2 was checked with sprite1. So I made a few changes to the check collision function and it runs quicker now but still less than 20 fps
def check_collision(self):
global mobs_to_collide
if mobs_to_collide == []:
mobs_to_collide = list_of_mobs[:]
if self in mobs_to_collide:
mobs_to_collide.remove(self)
for i in mobs_to_collide:
if self.distance(i) < (self.width/2 + i.width/2):
return True
(it may contain some inefficient code/useless stuff. I was playing around with it a bit)
EDIT2:
I decided to use rabbyt as the sprite library. The collisions are fast and easy. I replaced the code above ^^ with:
rabbyt.collisions.collide(mobs_to_collide)
This returns a list of lists (I'm not sure if that's the correct term) with the objects that collided. I'm still working on how to translate that into an "if collided:" type statement but I am making progress. If anyone is in a similar situation, I would reccomend using rabbyt.
A simple way to improve the speed on this, could be to remove the square root operation.
def distancesq(self,target):
return (self.x-target.x)**2 + (self.y-target.y)**2
def check_collision(self):
for i in list_of_mobs:
# Square this distance to compensate
if self.distancesq(i) < (self.width/2 + i.width/2)**2:
return True
Probably it is already too late, but I had exactly the same problem. I managed to solve it by calculating collisions only for visible objects, like that:
for object_ in objects:
if not object_.visible: # pyglet.sprite.Sprite() provides this flag
continue
# rest of your collision detection

How to make a shot impact in a rectangle only output one event?

In pygame, I am trying to make my points increase by 1000 every time a shot impacts my zombie, who's positions are zhot[XX] and zhot[YY]. I attempted to accomplish this by creating a rectangle around my zombie, and using the collidepoint function, however as my shot passes through the rectangle, every change in it's position counts as 1000 points, so shooting one zombie will give me something like 30000 points. How can I fix this?
for shot in shots:
zomrect2=Rect(zhot[XX],zhot[YY],49,38)
if zomrect2.collidepoint(shot[X],shot[Y]):
points+=1000
Once you've awarded points, you need to break out of the for loop.
for shot in shots:
zomrect2=Rect(zhot[XX],zhot[YY],49,38)
if zomrect2.collidepoint(shot[X],shot[Y]):
points+=1000
break #no more points will be awarded, there's no point wasting computation checking the rest.
I guess the loop you posted runs inside your main loop and is invoked every iteration of the main loop.
You should remove the shot from the shots list once it hit your zombie, so it won't be checked again for collision in the next iteration of the main loop.
zomrect2=Rect(zhot[XX],zhot[YY],49,38)
# make a copy of the list so we can savely remove items
# from it while iterating over the list
for shot in shots[:]:
if zomrect2.collidepoint(shot[X],shot[Y]):
points += 1000
shots.remove(shot)
# and also do whatever you have to do to
# erase the shot objects from your game
You need to track the fact that the points have been awarded already. It's not really clear how/when the method or function awarding points is being called, but something like this perhaps:
points_awarded = False
for shot in shots:
zomrect2=Rect(zhot[XX],zhot[YY],49,38)
if zomrect2.collidepoint(shot[X],shot[Y]) and not points_awarded:
points_awarded = True
points+=1000

Categories