I am trying to develop a python program to check if there is a loop in the graph when a new line is added.
I am storing different lines in a list ordered by shortest length first, and the lines are a class:
class Line():
def __init__(self,node1,node2,length):
self.node1 = node1
self.node2 = node2
self.length = int(length)
self.drawn = False
And the nodes are stored in a list:
nodes = ["A","B","C","D","E","F"]
When my program has run it stores the route as a list:
route = [class(Line),class(Line)...]
What i want it to do is to check that when a new line is added that it does not form a cycle. I plan to use a method inside of a bigger class:
something like:
def check_loop(new_line,graphs):
add new line to graph
if there is a loop in graphs:
return False
else:
return True
(sorry this is one of my first posts so the format is rubbish)
To identify if a cycle is created in a tree is pretty simple, all you need to do is pick a node and then breadth first search the entire tree from that node. If any node has been visited before by the time you reach it, then you know that there is a cycle because there was an alternative path that reached that node beside the one that you have taken.
Related
i would like to create a tree of objects called State.
Each State has a list of 4 robots and each states have differents robots coordinates.
The goal is to create a graph which will be solved by a Breadth First Search Algorithm.
(The original game is RicochetRobot maybe you guys know it).
class State:
def __init__(self,parent,childs,robots,cpt,):
self.parent = parent
self.childs = childs
self.robots = robots
self.cpt = cpt
I created a function create_child to do this
def create_child(self,depth):
#UP
#Depth is the tree height
if depth==0:
print("STOP")
return
else :
for i in range(4):
#Copying the robots of the current object
temp = copy.deepcopy(self.robots)
#Getting robot to move index
temp_robot = temp[i]
#removing this robot from the list
temp.pop(i)
#Moving up the robot and inserting it in the list
#Moving up is a simple function which increment the y of the robot
temp.insert(i,moving_up(temp_robot,create_board(init_robot())))
#Adding a new child into childs list
self.childs.append(State(self,self.childs,temp,self.cpt+1))
#Decrementing the depth
depth-=1
#Recursivity
for child in self.childs:
child.create_child(depth)
My problem is that when depth = 0 , it print STOP,but it doesnt return None, and the function keep going.
Anynone knows from where it come froms?
Also, if you can give advice on how to make my tree in an easier way it would be nice.
Alright so i think i found a solution , here it is :
depth = 1
parent = Initial_State
for j in range(depth):
for i in range(len(parent.childs)-1):
parent.childs[i].create_child()
parent = parent.childs[i]
It seems to be working. I dont use recursion anymore, i do it in a more iterative way and outside the function and it seems good.
Thank you
I'm trying to walk through a Decision Tree one node at a time.
Each node can have 2-3 paths
On the nodes with 3 paths, one of the paths is always an end point, and one is sometimes and end point
We can't move backwards, but can start over
Our available functions are
getCurrentNode() #returns string of current node's path from start (ex. 'A-B-A-A-B')
getCurrentNodePaths() #returns number of possible paths from this node
startOver() #puts us back at node 0
takePath(int pathNumber) #traverse the decision tree down a desired path
I've written this pseudo code that should walk through each node recursively, but only for the 'left' most path
# Start
def walk(pathNumber):
takePath(pathNumber)
next_nodes_paths = getCurrentNodePaths()
if next_nodes_paths.length > 0:
walk(0)
startOver()
walk(0)
How can I get this to keep track of where it's been, start over, and take a new path
This creates a model of the decision tree. You can navigate to a certain Node with the select_path method. path is a string like '03231002'. You can walk over the whole tree and apply a function at each point, by using the apply_function method. There is an example for walking the whole tree.
def select_path(path):
startOver()
for pathNumber in path:
takePath(int(pathNumber))
class Node:
def __init__(self,path):
self.path = path
self.select()
self.num_children = getCurrentNodePaths().length
self.children = [Node(path+str(i)) for i in range(self.num_children)]
def select(self):
select_path(self.path)
def apply_function(self, func, recursive=False):
self.select()
func()
if recursive:
for child in self.children:
apply_function(self, func, recursive=True)
root = Node('')
#walk whole tree and apply function function:
#def function:
# pass
#root.apply_function(function, recursive=True)
Since we cannot move backwards, your approach of (recursive) depth-first search is probably difficult to handle: You can never know if a node is an end node without actually moving there, and once you have arrived, you can only make a new walk to the previous node all the way from the start.
I suggest using a breadth-first search instead (partly adopted from this example):
def walk(currentNode):
queue = []
visited = []
queue.append(currentNode)
visited.append(currentNode)
while queue:
s = queue.pop(0)
# go to node from start by following the path
startOver()
for p in s:
takePath(int(p))
for i in range(getCurrentNodePaths()):
nextNode = getCurrentNode() + str(i)
queue.append(nextNode)
visited.append(nextNode)
# Use this if you want a list of paths to end points only
# if getCurrentNodePaths() > 0:
# visited.remove(s)
print(visited)
startOver()
walk(getCurrentNode())
This will give you a list of paths to all nodes in your tree in visited.
A few notes:
A node in the queue and visited lists is assumed to be represented by its path from the start node as a string (e.g. 0, 101, 012012).
Thus, a node can be reached by just following its sequence of numbers.
Moreover, the successor nodes can be constructed by
appending the numbers within range(getCurrentNodePaths()).
I am a bit new to python and I am trying to get a list containing all root parent existing in a scene of type joint.
for example, my scene outliner is something like that:
group1>>group2>>joint1>>joint2>>joint3
group3>>joint4>>joint5
joint16>>joint17>>joint18
I want a script that travels through the outliner and returns a list, in my example:
[joint1, joint4, joint16]
Any tips would be really appreciated. thank you so much.
Im not sure if it is any of use has Haggi Krey solution works fine but
You can use also the flag : -long from cmds.ls
# list all the joints from the scene
mjoints = cmds.ls(type='joint', l=True)
# list of the top joints from chain
output = []
# list to optimise the loop counter
exclusion = []
# lets iterate joints
for jnt in mjoints:
# convert all hierarchy into a list
pars = jnt.split('|')[1:]
# lets see if our hierarchy is in the exclusion list
# we put [1:] because maya root is represented by ''
if not set(pars) & set(exclusion):
# we parse the hierarchy until we reach the top joint
# then we add it to the output
# we add everything else to the exclusion list to avoid
for p in pars:
if cmds.nodeType(p) == 'joint':
output.append(p)
exclusion+=pars
break
print(output)
I just put this because there is not one way to go. I hope the construction of this code could help your python skills. It is exactly the same, just the way to find the parent nodes is different !
I've used DrWeeny's idea before where you traverse the hierarchy by the object's long name. The difference in this answer is that the script won't crash if there's objects with duplicate names in the scene. What I mean by that is let's say you have a situation where you have 2 hierachies:
group1>>joint1>>joint2>>group2>>joint3
and
group3>>joint1>>joint2>>group2>>joint3
Maya easily allows this, like when duplicating a top node, so we need to prevent the script from crashing in this case. When there's multiple objects with duplicate names Maya will crash if you try to access the object's short name (it doesn't know what one you're referring to!), so instead we must always use its long name:
import maya.cmds as cmds
jnts = cmds.ls(type="joint", l=True) # Collect all joints in the scene by their long names.
output = set() # Use a set to avoid adding the same joint.
for jnt in jnts:
pars = jnt.split("|") # Split long name so we can traverse its hierarchy.
root_jnt = None
while pars:
obj = "|".join(pars)
del pars[-1] # Remove last word to "traverse" up hierarchy on next loop.
# If this is a joint, mark it as the new root joint.
if obj and cmds.nodeType(obj) == "joint":
root_jnt = obj
# If a root joint was found, append it to our final list.
if root_jnt is not None:
output.add(root_jnt)
print(list(output))
Using this script on the hierarchies above would return
[u'|group1|joint1', u'|group3|joint1']
I'd suggest to list all joints and for every joint you can check if it's parent is not a joint. In your definition, these joints should be your root joints.
I use this method to get a joint hierarchy. I have given up on trying to figure out a sexier way to do this.
myItems = cmds.ls(selection = True, type='joint')
theParentJnt = cmds.listRelatives(myItems, parent = True)
jntRel = cmds.listRelatives(myItems, allDescendents = True)
allJnt = jntRel + myItems
#Green Cell
Your method worked once, and never worked again. Restarted maya 2020 more then 5 times and only displays to the top node joint, never again does it return the all the joints in one list.
Yes, this is related to homework and no I'm not looking for you to code it for me just a point in the right direction.
I'm trying to implement a linked list to represent the list of the current possible words in the list after the user has guessed a letter.
Currently I am doing the following to read in the lenght of the word the player wants to guess upon and then appending all possible words to the linked list.
However, I fail to see how I could continually update the linked list to compute the biggest word family and print the current word progress
(Ex. the dashed word with all of the current letters the user has guessed in there).
Mainly having problems because I fail to fully understand how linked lists work and how to implement them in my programs.
How I'm making the initial linked list of all possible words.
def make_ll(self):
linked_list = ll.LinkedList()
print(linked_list)
for word in self.init_list:
if len(word) == int(self.word_length):
linked_list.append(str(word))
self.linked_list = linked_list
def init_family(self, guess):
self.dictionary = {}
cursor = self.linked_list.head
while cursor != None:
word = cursor.data
cursor = cursor.next
word = self.make_families(word, guess)
def make_families(self, word, guess):
count = 0
new_word = ""
for c in word:
if guess == c:
count += 1
else:
new_word = word.replace(c, "-")
if count == 0:
self.linked_list.delete(word)
key = new_word
if key not in self.dictionary:
self.dictionary[key] = []
self.dictionary[key].append(word)
max = max(self.dictionary.values(), key = len)
new_linked_list = ll.linked_list
for word in max:
new_linked_list.append(word)
self.linked_list = new_linked_list
return word
Skeletor,
This can be done using a Linked List, but it is not the optimal solution.
You can think of a Linked List as a bunch of train cars. Each car does two things:
1) It holds something (in programming, this is the data - in your case it is a word).
2) It connects to other cars (in programming this is usually something called a pointer).
Both of these things are a part of the train car. In Linked Lists, this is called the node.
Node1 Node2 Node3
----- ----- -----
|Data1| -> |Data2| -> |Data3|
----- ----- -----
There are a few operations you can perform on train cars:
1) You can add a new car anywhere if you adjust the connectors appropriately.
2) You can walk through cars, depending on the rules for traffic, and look at the data inside.
3) Being in a car let's you easily find the next: you just have to exit and board the next car.
Linked lists have these same rules:
1) They allow you to add a node anywhere you like, but you have to adjust the references to the node (the pointers.)
2) When you're looking at the node you can easily access the data.
3) You can access the next node easily by looking at that node's reference. If you have a doubly linked list, you can look at both the previous and next node.
Most confusion understanding linked lists is the linked part of the definition. Like I mentioned, this is usually a pointer. To understand how that works you'll have to understand pointers, however, you can still understand linked lists by walking through one yourself.
First, let's define our train car(or our node):
class TrainCar:
def __init__(self, data):
# this is the contents of our train car
self.data = data
# This is the reference to the next node, or the train car's connector.
# Accessing it gets you the next TrainCar, if one exists
self.next_car = None
Once you get this, it already starts to fall into place. Basically you have a bunch of nodes with each one referencing the next node! All that's left to do is to implement our operations:
# making a new linked list
class Train:
def __init__(self):
self.head_car = None
def add_car(self, data):
# make new car/node
new_car = TrainCar()
# add our data to the new car as desired
new_car.data = data
# This is where the magic happens! We're updating the reference inside
# the node we just made to point to the last car we were on.
# We are just adding a new car to the end of the train.
new_car.next_car = self.head_car
# Now we're setting the head car to be the one we just made!
self.head_car = new_car
Now, other operations - such as traversing the linked list and deleting nodes - are left to you.
So I want to sort a range of numbers so that the sum of every sequential number is a squared number (4,9,16,25,...) I was told I should use Depth first search but am unable to implenment it correctly, especialy the backtracking part. Is this the correct way to do this, what am I not seeing, doing wrong? Is DFS even the correct way to do this?
class Node: #Define node Object
def __init__(self, value):
self.value = value #Node "Name"
self.adjacentNodes=list() #Node Neighbours
#Set limit
limit=16
squares=list() #list for squared numbers in rang smaller than 2Xlimit
tree=list() #Tree containing nodes
path=list() #current path taken
def calculate(limit): #Population control legal squares
for i in range(1,(limit+1)):
i=i*i
if i<(limit+limit):
squares.append(i)
calculate(limit) #Populate squares list
for a in range(1,(limit+1)): #creating the nodes
newnode=Node(a)
for s in squares:
legalsum=s-a
if legalsum>0 and legalsum<limit and legalsum!=a: #zero and lower can't play,keeping non-exiting nodes out of node.adjacentNodes, don't connect to selve.
newnode.adjacentNodes.append(legalsum) #Add adjacentnode
tree.append(newnode) #add newborn to tree
for b in range(0,limit):
print tree[b].value,tree[b].adjacentNodes #Quick checkup
#Now the tree is build and can be used to search for paths.
'''
Take a node and check adjnodes
is it already visited? check path
yes-> are all nodes visited (loop over tree(currentnode).adjnodes) Maybe use len()
yes->pop last node from path and take other node -> fear for infinte loops, do I need a current node discard pile?
no -> visit next available adje node next in line from loop got from len(tree.adjn)
no-> take this as node and check adj nodes.
'''
def dfs (node):
path.append(node)
#load/check adjacent nodes
tree[node].adjacentNodes
for adjnode in tree[node-1].adjacentNodes:
if adjnode in path:
#skip to next adj node
continue
else:
print path #Quick checkup
dfs(adjnode)
dfs(8) # start with 8 since 1-16 should be {8,1,15,10,6,3,13,12,4,5,11,14,2,7,9,16}
I have no idea what you are talking about with the squares but here are some problems
def dfs (node):
#always assume the path starts with this node
path=[node]
if node == GoalState: return path #we win!!
#load/check adjacent nodes
#this line did nothing `tree[node].adjacentNodes`
for adjnode in tree[node-1].adjacentNodes:
# if adjnode in path: ****this will never be true, lets eliminate it
# #skip to next adj node
# continue
# else:
subpath = dfs(adjnode)
if subpath and subpath.endswith(GoalState):
return path + subpath #return solution
#if we get here there is no solution from this node to the goal state