Im trying to make a stepping function in python for rhino,
The function is supposed to make a step in a random direction, without going backwards.
How do i prevent a step back?
import rhinoscriptsyntax as rs
import random as r
r.seed(seed)
class Walker:
def __init__(self):
self.x = 0
self.y = 0
def point(self):
shape = rs.AddPoint(self.x, self.y, 0)
return shape
def step(self):
choice = r.randint(0,3)
choice = r.randint(1,3)
if (choice == 0):
self.x = self.x + r.choice(uList)
elif (choice == 1):
self.x = self.x - r.choice(uList)
elif (choice == 2):
self.y = self.y + r.choice(uList)
else:
self.y = self.y - r.choice(uList)
uList = [8,11,14]
w = Walker()
pList = []
for t in range(time):
w.step()
pList.append(w.point())
for t-1 in range(time):
a = pList
This line:
choice = r.randint(0,3)
chooses one of 4 directions randomly. But if you don't want to go backwards, then you only want forward, left and right. So change the parameters to randint() so that it only chooses from 3 possible numbers, avoiding the one that corresponds to the direction you are calling backwards, whichever that is.
Related
Hello i am trying to learn some basics by making some mistakes.
I am making a basic python based snake game, using as little of non built in modules as i can.
at the moment the main one is tkinter.
Some of my logic is changing a member of a list, when i do not expect it do so and i can't see why.
The change is happening at line 60 (21) where index 1 is changed to equal index 0
when only index 0 should change only when "middle" occurs on line 71 (31)
the error is within this function
self.player[1] changes when i did not expect
def move(self):
print("old snake pos {}".format(self.player))
for i in range(len(self.player)-1, -1, -1):
# runs through loop backwards as the positions of the next piece needs to be known
print(i)
if i == len(self.player)-1:
print("last piece")
if self.eat():
print("eat = True")
self.player.append(self.player[-1])
print("{} changed from {} to {}".format(i, self.player[i], self.player[i-1]))
self.player[i] = self.player[i-1]
else:
if i == 0:
print("Head")
print(self.vel)
print(self.player[0])
print(self.player[1])
self.player[0][0] = self.player[0][0] + self.vel[0]
print("why has it changed????????")
print(self.player[0])
print(self.player[1])
self.player[0][1] = self.player[0][1] + self.vel[1]
print(self.player[1])
print(self.player)
continue
print("middle piece")
print("{} changed from {} to {}".format(i, self.player[i], self.player[i - 1]))
self.player[i] = self.player[i - 1]
print(self.player[i])
print(self.player[i])
print(self.player)
print("new snake pos {}".format(self.player))
i have tried different checks, but it doesnt seem to be doing any line that i dont expect at the right time.
and the full code is this:
# programme for learning more about creating graphical displays in Python
# will start with some investigation and use of tkinter resource
# then move to creating a snake style game
import tkinter as tk
import random as r
import time
class SnakeApp(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.pack()
self.setup()
self.gameloop()
def mat2str(self, matrix):
string = ""
for y in matrix:
for x in y:
string += x
string += "\n"
return string
# random an int co-ordinate
def newpos(self):
return [r.randint(0, self.wx), r.randint(0, self.wy)]
# check if the fruit has been eaten
def eat(self):
if any([s == self.fruit for s in self.player]):
print("fruit col detected {}".format(self.fruit))
# new position
self.fruit = self.newpos()
# increase the game speed by 2.5%
self.dt = self.dt * 0.975
# need to add a segment to the player
return True
# move the game 1 turn and compute all the logic before the next frame is drawn
def move(self):
print("old snake pos {}".format(self.player))
for i in range(len(self.player)-1, -1, -1):
# runs through loop backwards as the positions of the next piece needs to be known
print(i)
if i == len(self.player)-1:
print("last piece")
if self.eat():
print("eat = True")
self.player.append(self.player[-1])
print("{} changed from {} to {}".format(i, self.player[i], self.player[i-1]))
self.player[i] = self.player[i-1]
else:
if i == 0:
print("Head")
print(self.vel)
print(self.player[0])
print(self.player[1])
self.player[0][0] = self.player[0][0] + self.vel[0]
print("why has it changed????????")
print(self.player[0])
print(self.player[1])
self.player[0][1] = self.player[0][1] + self.vel[1]
print(self.player[1])
print(self.player)
continue
print("middle piece")
print("{} changed from {} to {}".format(i, self.player[i], self.player[i - 1]))
self.player[i] = self.player[i - 1]
print(self.player[i])
print(self.player[i])
print(self.player)
print("new snake pos {}".format(self.player))
def up(self, event):
print("up")
if self.vel != [0, 1]:
self.vel = [0, -1]
def down(self, event):
print("down")
if self.vel != [0, -1]:
self.vel = [0, 1]
def left(self, event):
print("left")
if self.vel != [1, 0]:
self.vel = [-1, 0]
def right(self, event):
print("right")
if self.vel != [-1, 0]:
self.vel = [1, 0]
def drawempty(self, wx, wy):
frame = []
for y in range(wy):
xlayer = []
for x in range(wx):
xlayer.append("-")
frame.append(xlayer)
return frame
def redraw(self, player, object):
# self.drawempty(self.wx, self.wy)
# replaced redraw each frame with a static empty frame build
print(self.gameframe)
self.gameframe = self.drawempty(self.wx, self.wy)
print(self.gameframe)
# set the string in the co-ord of the object to A
# check for collision needs to occur before this - all game logic before
# set the string in the co-ords of all players to *
print(object)
self.gameframe[object[1]][object[0]] = "A"
for b in player:
self.gameframe[b[1]][b[0]] = "*"
def setup(self):
# set game size
self.wx = 20
self.wy = 20
self.master.geometry("300x300")
self.vel = [-1, 0]
self.dt = 1
# create text matrices of spaces of size wx * wy
#self.gameframe = tk.Variable()
self.gameframe = []
#self.emptyframe = tk.Variable()
self.emptyframe = self.drawempty(self.wx, self.wy)
self.gameframe = self.emptyframe
# create a player and fruit object in the space
self.player = [[round(self.wx / 2), round(self.wy / 2)],[round(self.wx / 2) + 1, round(self.wy / 2)],[round(self.wx / 2) + 2, round(self.wy / 2)]]
self.fruit = self.newpos()
self.redraw(self.player, self.fruit)
self.game = tk.Text(self, height=self.wy, width=self.wx)
self.game.pack()
self.game.insert(tk.END, self.mat2str(self.gameframe))
self.master.bind("<Up>", self.up)
self.master.bind("<Down>", self.down)
self.master.bind("<Left>", self.left)
self.master.bind("<Right>", self.right)
def gameloop(self):
while True:
self.redraw(self.player, self.fruit)
self.game.delete('1.0', tk.END)
self.game.insert(tk.END, self.mat2str(self.gameframe))
self.move()
self.master.update()
time.sleep(self.dt)
Snake = tk.Tk()
app = SnakeApp(master=Snake)
The problem can be found at your move function as this point (Line 122)
self.player[i] = self.player[i - 1] # i == 1, self.player[1] = self.player[0]
At the point when i is 1 this code block is reached and it sets self.player[1] to self.player[0]
The problem is that self.player[0] after that is equal by reference to self.player[1], which means that when one changes, the other does as well (which you said was your problem).
What you need to do to prevent that from happening is to create a copy of self.player[i-1] and set that equal to self.player[i]. This can be achieved through multiple ways.
In your case because you have a list of lists the following should be fine
self.player[i] = [item for item in self.player[i-1]] # Create a new list
if you want use a built-in functions for this you can use deepcopy
from copy import deepcopy
# ...
self.player[i] = deepcopy(self.player[i-1])
Note that this behavior can also be found on lines 25,43, 104 and 122. So you'll have to change all of them to create a copy as shown above.
The code that should be modified is:
self.player[i] = self.player[i - 1]
When you change element 1 to be element 0, you are not making a copy but making them pointing to the same element, which is 0. So when you change element 0, element 1 change as well.
Example why this leads to what you see in code:
player = [[1,2], [3,4]]
i = 1
player[i] = player[i - 1]
player[0][0] = 100
print(player)
[[100, 2], [100, 2]]
One quick solution to create a copy:
self.player[i] = [x for x in self.player[i - 1]]
I am fairly new to coding so this might be fairly simple. I have been stuck on this error in my code for a while. I copied the code that I think will be important. The problem occurs when I call the highlightSide function as this checks squares[i][j].contains(x, y). I figure that since it says that the 'NoneType' object, then this would mean that there is a problem in the creation of the squares in the 2d array, but I don't know for sure. If this is the problem, how should I go about fixing this because I tried a variety of possible solutions, but they all resulted in the error being conveyed in a different way?
def highlightSide(x, y):
rows = len(squares)
cols = len(squares[0])
for i in range(rows):
for j in range(cols):
if squares[i][j].contains(x, y):
side = squares[i][j].highlightSide(x,y)
break
else:
continue
break
def newGame():
#random chance of who starts the new game
playersTurn = random.randint(0, 1) > 0
#set up the squares
squares = np.empty((GAME_SIZE, GAME_SIZE), dtype=object)
for i in range(GAME_SIZE):
for j in range(GAME_SIZE):
squares[i][j] = (createSquare(w, dotX(j), dotY(i), BOX))
#Create square from rectangle
class createSquare:
def __init__(self, canvas,x,y,length):
self.canvas = canvas
self.length = length
self.length = height
self.bot = y + length
self.left = x
self.right = x + length
self.top = y
self.highlight = None
self.NumSelected = 0
self.owner = None
#look into to make sure it work
#to see if in the range of the square
def contains(self, x, y):
if y>self.bot and x < self.right and y <= self.top and y >= self.left:
return True
else:
return False
def highlightSide(self, x, y):
#calcualte the distance to each side
dBot = self.bot - y
dLeft = x - self.left
dRight = self.right - x
dTop = y - self.top
#find which of them is the closest
dClosest = min(dBot, dLeft, dRight, dTop)
#make sure the color changes to highlighted color for closest if doesn't already have line
if dClosest == dBot and not self.sideBot.selected:
self.highlight = constants.BOT
elif dClosest == dLeft and not self.sideLeft.selected:
self.highlight = constants.LEFT
elif dClosest == dRight and not self.sideRight.selected:
self.highlight = constants.RIGHT
elif dClosest == dTop and not self.sideTop.selected:
self.highlight = constants.Top
#return the highlight
return self.highlight
So I've been working on this game (I'm a big noob at python and I've only worked on this for like 3 days) and I've been trying to move the Location (Add or Subtract one from Location's x and y values) but the fuction doesn't work. I know because I put a print in the function and the print didn't work at all. What is wrong? (I have created a folder for this project and there is a folder called Decisions containing 2 files.)
Locations.py:
class Location:
def __init__(self, x, y):
self.x = x
self.y = y
def move_forward(self):
self.y = self.y + 1
return self.y
def move_back(self):
self.y = self.y - 1
return self.y
def move_left(self):
self.x = self.x - 1
return self.x
def move_right(self):
self.x = self.x + 1
return self.x
main.py (Main Function):
import Decisions
import Characters
import Locations
def main():
Player = Characters.Character([], 100)
Loc = Locations.Location(0, 0)
answer = Decisions.choice_yes_no.choice_yes_no("You woke up, discovering
that somehow you were in the middle of a dark dungeon. A sword lies to the
left of you, pick it up? (Yes/No) ")
if answer == True:
print("You picked up the sword.")
Player.add_item("Sword")
elif answer == False:
print("You chose not to pick up the sword.")
answer_2 = Decisions.choice_direction.choice_direction("You stood up,
patting the dust off your clothes, you looked around. The room was dark and
you view was limited to a few meters. Where do you go?
\n(Left/Right/Forward/Back) ")
if answer == "forward":
Loc.y = Loc.y + 1
elif answer == "back":
Loc.move_back()
elif answer == "left":
Loc.move_left()
elif answer == "right":
Loc.move_right()
print(Loc.x)
print(Loc.y)
main() #REMOVE BEFORE USING#
The function add_item works just fine, what is wrong? There aren't any errors, it's just when I print the x and y values at the end they stay 0.
Sorry if I don't do this correctly, I am new here. I am trying to make it so that raw_input loops through saving the value of self.x every time so that it asks "r or l"? Whenever you click enter, then raise or lower self.x but I'm not sure how to. If someone could check my work, that would mean a lot. Thank you.
q = raw_input("r or l: ")
class game:
def __init__(self):
self.x = 0
def raise_n(self):
self.x += 1
return self.x
def lower_n(self):
self.x -= 1
return self.x
def main():
g = game()
while q == "r":
print g.raise_n()
break
while q == "l":
print g.lower_n()
break
main()
I also tried this, but it didn't save the value of self.x even if I tried to call main() again.
q = raw_input("r or l: ")
class game:
def __init__(self):
self.x = 0
def raise_n(self):
self.x += 1
return self.x
def lower_n(self):
self.x -= 1
return self.x
def main():
g = game()
while q == "r":
print g.raise_n()
break
while q == "l":
print g.lower_n()
break
main()
Any help would be very useful, thank you!
Your second approach was closer to a valid solution. There are several approaches, and below I show you one, without introducing too many changes. Basically:
The main() function is executed in an endless loop. Change the True condition if you want to change the stop condition.
The question is asked and evaluated every time it enters the main() function. Afterwards, it checks if it has to run the raise_n() or lower_n() methods.
The code:
class game():
def __init__(self):
self.x = 0
def raise_n(self):
self.x += 1
return self.x
def lower_n(self):
self.x -= 1
return self.x
def main():
q = raw_input("r or l: ")
if q == "r":
print g.raise_n()
if q == "l":
print g.lower_n()
g = game()
while True:
main()
EDIT: In order to put as condition for the while loop to iterate a determinated number of times, a constant can be succesively increased and check if it has reached the desired limit:
#... Copy previous code here
g = game()
iterations_limit = 10 #Substitute 10 by any positive integer
while k > iterations_limit:
k += 1 #Increase variable k
main()
So I am programming a checkers game, and the problem I am having is with creating several pieces in a loop. I have the class creation part of the code, which I won't post here, and the rest, which I'm posting, but I don't know how to change the variable the loop is about to use. If you can lend me a hand and clear this out, I would be thankful.
Sorry for posting my code as image, I'm new to this website ( and programming) and couldn't format so that the website would accept my post. I really hope it's ok for you guys to help me!
Thanks for the help!
Further clarification: I need to use a different "piece" creation everytime the loop runs. That means the first loop has to create piece1, then piece2, then piece3... and so forward
EDIT: Posting whole code. I know format is wrong, can't help it. So, hope somebody can fix it.
class Piece:
def __init__(self, kind, yposition, xposition):
self.color = kind
self.ypos = xposition
self.xpos = yposition
def getColor(self):
return self.getColor
def adjustY(self, change):
self.ypos = self.ypos + change
def adjustX(self, change):
self.xpos = self.xpos + change
def getY(self):
return self.ypos
def getX(self):
return self.xpos
def mover(self, direction):
self.direc = direction
if self.direc == "right" and self.color == "white":
for n in alist:
if n.getY == (self.getY - 1) and n.getX == (self.getX + 1):
pass
# NOT YET IMPLEMENTED
else:
self.adjustY(-1)
self.adjustX(+1)
elif self.direc == "left" and self.color == "white":
for n in alist:
if n.getY == (self.getY - 1) and n.getX == (self.getX - 1):
pass
# NOT YET IMPLEMENTED
else:
self.adjustY(-1)
self.adjustX(-1)
elif self.direc == "right" and self.color == "black":
for n in alist:
if n.getY == (self.getY + 1) and n.getX == (self.getX + 1):
pass
# NOT YET IMPLEMENTED
else:
self.adjustY(+1)
self.adjustX(+1)
else:
for n in alist:
if n.getY == (self.getY + 1) and n.getX == (self.getX - 1):
pass
# NOT YET IMPLEMENTED
else:
self.adjustY(+1)
self.adjustX(-1)
piece1 = 0
piece2 = 0
piece3 = 0
piece4 = 0
piece5 = 0
piece6 = 0
piece7 = 0
piece8 = 0
piece9 = 0
piece10 = 0
piece11 = 0
piece12 = 0
alistb1 = [piece1,piece2,piece3,piece4,piece5,piece6,piece7,piece8,piece9,piece10,piece11,piece12]
k = 2
for i in range(0,11):
if i >= 0 and i <5:
j = 8
m = 0
elif i >= 5 and i < 9:
j = 7
m = 1
else:
j = 6
m = 0
alistb1[i] = Piece("white",j,(m + 1 + i * k))
print(alistb1[i].getY())
# print(piece7.getY()) test reasons
PS: def mover is not ready yet.
You do not need to assign a variable for each piece. You are already using a list for your pieces. Instead of writing piece1, you can just write pieces[0]. (You do need to note that lists start with index 0.)
range has an exclusive right bound. This means that it is not included, your range ends with one less than that value. You want to use range(0,12).
In python, you can add to lists dynamically. You do not need to allocate enough spaces to fit your pieces. You can use the .append() method of lists.
One way to write your code now is this:
pieces = []
for i in range(0, 12): # 0-11
if i < 5:
pieces.append(Piece("white", 8, 1 + i*2))
elif i < 9:
pieces.append(Piece("white", 7, 2 + i*2))
else:
pieces.append(Piece("white", 6, 1 + i*2))
I took the liberty of simplifying your conditional statements (i will always be >= 0 and if i < 5 is false, then the inverse, i >= 5, is true, so you don't need to restate it in your elif) and getting rid of j, k, and m which are unnecessary variables and can be replaced with literals to save memory.
One more thing: your implementation of getColor will return the function object itself. I think you wanted to do:
def getColor():
return self.color
Use a dictionary and a for loop:
pieces = {}
# I'm assuming you want 12 pieces since your list has 12 pieces
for i in range(1,13): # range starts at m so, range(m,n) iterates from m up to n-1
# I would suggest using more descriptive variable names if you can, row or column for example
if i >= 0 and i <5:
j = 8
m = 0
elif i >= 5 and i < 9:
j = 7
m = 1
else:
j = 6
m = 0
pieces['piece{}'.format(i)] = Piece("white",j,(m + 1 + i * k))
This should do what you want unless I am misunderstanding you. Also this isn't C++ you don't need those get methods you can simply Piece.color to get the color attribute of a piece.
Use the dictionary to access the pieces, pieces['piece1'].whatever(). However for brevity's sake you don't need to pieces['piece{}.format(i)] you can just pieces[i] and the piece would be accessed pieces[1].whatever().
More info on dictionaries http://docs.python.org/3.3/tutorial/datastructures.html#dictionaries
What I have and it works with no errors:
class Piece:
def __init__(self, kind, yposition, xposition):
self.color = kind
self.ypos = xposition
self.xpos = yposition
def getColor(self):
return self.getColor
def adjustY(self, change):
self.ypos = self.ypos + change
def adjustX(self, change):
self.xpos = self.xpos + change
def getY(self):
return self.ypos
def getX(self):
return self.xpos
def mover(self, direction):
self.direc = direction
if self.direc == "right" and self.color == "white":
for n in alist:
if n.getY == (self.getY - 1) and n.getX == (self.getX + 1):
pass
# NOT YET IMPLEMENTED
else:
self.adjustY(-1)
self.adjustX(+1)
elif self.direc == "left" and self.color == "white":
for n in alist:
if n.getY == (self.getY - 1) and n.getX == (self.getX - 1):
pass
# NOT YET IMPLEMENTED
else:
self.adjustY(-1)
self.adjustX(-1)
elif self.direc == "right" and self.color == "black":
for n in alist:
if n.getY == (self.getY + 1) and n.getX == (self.getX + 1):
pass
# NOT YET IMPLEMENTED
else:
self.adjustY(+1)
self.adjustX(+1)
else:
for n in alist:
if n.getY == (self.getY + 1) and n.getX == (self.getX - 1):
pass
# NOT YET IMPLEMENTED
else:
self.adjustY(+1)
self.adjustX(-1)
k=2
pieces = {}
# I'm assuming you want 12 pieces since your list has 12 pieces
for i in range(1,13): # range starts at m so, range(m,n) iterates from m up to n-1
# I would suggest using more descriptive variable names if you can, row or column for example
if i >= 0 and i <5:
j = 8
m = 0
elif i >= 5 and i < 9:
j = 7
m = 1
else:
j = 6
m = 0
pieces['piece{}'.format(i)] = Piece("white",j,(m + 1 + i * k))
Output:
>>> pieces['piece1'].color
'white'
>>> pieces['piece3'].color
'white'
>>> pieces['piece3'].xpos
8
>>> for key in pieces:
print(key, pieces[key])
piece8 <__main__.Piece object at 0x000000000329A4E0>
piece9 <__main__.Piece object at 0x000000000329A550>
piece6 <__main__.Piece object at 0x000000000329A400>
piece7 <__main__.Piece object at 0x000000000329A470>
piece4 <__main__.Piece object at 0x000000000329A320>
piece5 <__main__.Piece object at 0x000000000329A390>
piece2 <__main__.Piece object at 0x0000000003287DA0>
piece3 <__main__.Piece object at 0x000000000329A2B0>
piece1 <__main__.Piece object at 0x00000000031D9CF8>
piece10 <__main__.Piece object at 0x000000000329A5C0>
piece11 <__main__.Piece object at 0x000000000329A630>
piece12 <__main__.Piece object at 0x000000000329A6A0>
>>> pieces['piece3'].mover('right')
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
pieces['piece3'].mover('right')
File "C:/Users/Hannah/Documents/thing.py", line 25, in mover
for n in alist:
NameError: global name 'alist' is not defined
>>> pieces['piece3'].xpos
8
>>> pieces['piece3'].adjustX(1)
>>> pieces['piece3'].xpos
9
Keep in mind dictionaries are unordered so the order they print in is arbitrary.
The traceback on mover is expected since I don't have alist in my version of the code. You will need to modify mover() to work with the dictionary. Some helpful ways to work with dicts:
>>> for n in pieces.values(): # iterates over the values in a dict
n.color
'white'
'white'
'white'
'white'
'white'
'white'
'white'
'white'
'white'
'white'
'white'
'white'
>>> for n in pieces.keys(): # iterates over the keys
print(n)
piece8
piece9
piece6
piece7
piece4
piece5
piece2
piece3
piece1
piece10
piece11
piece12