def bf_paths(graph: Dict[int, Dict[str, int]], starting_room: int) -> Dict[int, List[str]]: qq = Queue() visited = set() qq.enqueue([starting_room]) paths = {(starting_room, starting_room): [starting_room]} while qq.size > 0: path: List[int] = qq.dequeue() room = path[-1] if room not in visited: visited.add(room) for move, nextroom in graph[room].items(): path_copy = path.copy() path_copy.append(nextroom) qq.enqueue(path_copy) paths[(starting_room, nextroom)] = paths[(starting_room, room)] + [move] paths = {key: val[1:] for key, val in paths.items()} return paths
def test_length(self): queue = Queue() self.assertEqual(0, len(queue)) self.assertIs(queue.first, queue.last) queue.enqueue(4) self.assertIs(queue.first, queue.last) self.assertEqual(1, len(queue))
def test_primitives(): queue = Queue() with pytest.raises(NotImplementedError): queue.head with pytest.raises(NotImplementedError): queue.tail with pytest.raises(NotImplementedError): queue.enqueue('a') with pytest.raises(NotImplementedError): queue.dequeue()
def test_dequeue(self): """retrait d'un item à la fin de la file""" queue = Queue() for i in range(5): queue.enqueue(i) self.assertEqual(5, len(queue)) for i in range(5): self.assertEqual(i, queue.dequeue())
def bfs(self, start: Vertex, process_vertex_early: Callable[[Vertex], Any] = None, process_vertex_late: Callable[[Vertex], Any] = None, process_edge: Callable[[Vertex, Edgenode], Any] = None, discovered_vertices: NodeList = None, processed_vertices: NodeList = None, is_edge_processable: Callable[[Vertex, Edgenode], bool] = None): """Breadth-First Search returns the graph of processed vertices - one single connected component""" process_vertex_early = process_vertex_early if process_vertex_early else lambda v: None process_vertex_late = process_vertex_late if process_vertex_late else lambda v: None process_edge = process_edge if process_edge else lambda v, e: None is_edge_processable = is_edge_processable if is_edge_processable else lambda v, e: True vertices = [v for v in self.adjacency_lists] self.parent_edges = NodeList(vertices=vertices) # reinit parents discovered = NodeList( vertices=vertices ) if discovered_vertices is None else discovered_vertices # added to stack processed = NodeList( vertices=vertices ) if processed_vertices is None else processed_vertices # processed and out of stack discovered[start] = True queue = Queue(implementation='doubly_linked_list') queue.enqueue(start) while True: try: vertex = queue.dequeue() except QueueEmptyError: break processed[vertex] = True process_vertex_early(vertex) adjacency_list = self.adjacency_lists[vertex] for edgenode in adjacency_list.edgenodes: if is_edge_processable(vertex, edgenode): next_vertex = edgenode.tail if not processed[next_vertex] or self.directed: process_edge(vertex, edgenode) if not discovered[next_vertex]: discovered[next_vertex] = True self.parent_edges[next_vertex] = edgenode.to_edge( head=vertex) queue.enqueue(next_vertex) process_vertex_late(vertex) processed_vertices = [v for v in processed if processed[v]] processed_edges = [] for processed_vertex in processed_vertices: adjacency_list = self.adjacency_lists[processed_vertex] for edgenode in adjacency_list.edgenodes: processed_edges.append(edgenode.to_edge(head=processed_vertex)) return Graph(vertices=processed_vertices, edges=processed_edges, directed=self.directed)
def hotpotate(namelist, num): queue = Queue() for name in namelist: queue.enqueue(name) while queue.size() > 1: for i in range(num): queue.enqueue(queue.dequeue()) queue.dequeue() return queue.dequeue()
def mergesort(items: Sequence[KeyedItem], order=None) -> None: """O(n*log n)""" comp = lambda x, y: x > y if order == 'max' else x < y stack = Stack(implementation='linked_list') class StackItem: def __init__(self, low, high, status=0): self.low = low self.high = high self.status = status stack_item = StackItem(0, len(items) - 1) while True: low = stack_item.low high = stack_item.high if low != high: median = (low + high) // 2 if not stack_item.status: # sort left stack_item.status = 1 stack.push(stack_item) stack.push(StackItem(low, median)) elif stack_item.status == 1: # sort right stack_item.status = 2 stack.push(stack_item) stack.push(StackItem(median + 1, high)) else: # merge left_queue = Queue(implementation='doubly_linked_list') for i in range(low, median+1): left_queue.enqueue(items[i]) right_queue = Queue(implementation='doubly_linked_list') for i in range(median+1, high+1): right_queue.enqueue(items[i]) for i in range(low, high + 1): if not left_queue.head: items[i] = right_queue.dequeue() elif not right_queue.head: items[i] = left_queue.dequeue() else: if comp(left_queue.head.key, right_queue.head.key): items[i] = left_queue.dequeue() else: items[i] = right_queue.dequeue() try: stack_item = stack.pop() except StackEmptyError: break
def bfs(g, start: Vertex): start.setDistance(0) start.setPred(None) vertQueue = Queue() vertQueue.enqueue(start) while (vertQueue.size() > 0): currentVert = vertQueue.dequeue() for nbr in currentVert.getConnections(): if (nbr.getColor() == 'white'): nbr.setColor('gray') nbr.setDistance(currentVert.getDistance() + 1) nbr.setPred(currentVert) vertQueue.enqueue(nbr) currentVert.setColor('black')
def test_linked_list_implementation(): queue = Queue(implementation='doubly_linked_list') a, b, c, d = list('abcd') assert queue.head is None assert queue.tail is None queue.enqueue(a) assert queue.head is a assert queue.tail is a assert queue.dequeue() is a assert queue.head is None assert queue.tail is None queue.enqueue(b) queue.enqueue(c) assert queue.head is b assert queue.tail is c assert queue.dequeue() is b assert queue.head is c assert queue.tail is c queue.enqueue(d) assert queue.head is c assert queue.tail is d assert queue.dequeue() is c assert queue.head is d assert queue.tail is d assert queue.dequeue() is d assert queue.head is None assert queue.tail is None
def BFSPuzzle(startNode): temp = copy.deepcopy(startNode) myQueue = Queue() myQueue.enqueue(temp) #temp = copy.deepcopy(myQueue.dequeue()) puzzleStateList = [] puzzleStateList.append(temp.numbers) while myQueue.size() > 0: temp = myQueue.dequeue() temp1 = copy.deepcopy(temp) # upMovement Temp Node temp2 = copy.deepcopy(temp) # downMovement Temp Node temp3 = copy.deepcopy(temp) #leftMovement Temp Node temp4 = copy.deepcopy(temp) # rightMovement Temp Node if temp.numbers == [1, 2, 5, 6, 3, 4, 7, 8, 0]: # targetNode temp.toString() print("Arbol Genealogico") temp.familyTree() #BackTrace family tree route from target to root print(len(puzzleStateList)) input() else: # looks for all possible movements and adds to the queue the ones that are not in the list yet if temp1.moveUp() != 0 and temp1.numbers not in puzzleStateList: temp1.setParent(temp) puzzleStateList.append(temp1.numbers) myQueue.enqueue(temp1) if temp2.moveDown() != 0 and temp2.numbers not in puzzleStateList: temp2.setParent(temp) puzzleStateList.append(temp2.numbers) myQueue.enqueue(temp2) if temp3.moveLeft() != 0 and temp3.numbers not in puzzleStateList: temp3.setParent(temp) puzzleStateList.append(temp3.numbers) myQueue.enqueue(temp3) if temp4.moveRight() != 0 and temp4.numbers not in puzzleStateList: temp4.setParent(temp) puzzleStateList.append(temp4.numbers) myQueue.enqueue(temp4)
def test_enqueue(self): """ajout d'un item au début de la file""" queue = Queue() self.assertEqual(0, len(queue)) queue.enqueue(5) self.assertIs(queue.first, queue.last) self.assertEqual(1, len(queue)) queue.enqueue(7) self.assertEqual(2, len(queue)) self.assertIsNot(queue.first, queue.last) self.assertIs(queue.first.next(), queue.last) # il reste 1 élément self.assertEqual(5, queue.dequeue()) self.assertIs(queue.first, queue.last) # il reste aucun élément self.assertEqual(7, queue.dequeue()) self.assertIsNone(queue.first) self.assertIsNone(queue.last)
def simulation(num_seconds, pages_perminute): lab_printer = Printer(pages_perminute) print_queue = Queue() waiting_times = [] for current_second in range(num_seconds): if new_print_task(): print(current_second) task = Task(current_second) print_queue.enqueue(task) if (not lab_printer.busy()) and (not print_queue.isEmpty()): next_task = print_queue.dequeue() print('cs', current_second) print('ts', next_task.time_stamp) waiting_times.append(next_task.wait_time(current_second)) lab_printer.start_next(next_task) lab_printer.tick() print(waiting_times) average_wait = sum(waiting_times) / len(waiting_times) print("Average wait %6.2f secs %3d tasks remaining." % (average_wait, print_queue.size()))
def test_remove(self): queue = Queue() queue.enqueue(1) self.assertEqual(1, len(queue))
class DiceResolver: def __init__(self): # BEDMAS ==> d()!^/%*+- # PEMDAS ==> d()!^*/%+- # Precedence weighting reflects rule; higher means priority # Close bracket ')' not included; it is a special case (collapses stack to '(') self.precedence = { "(": 0, "+": 3, "-": 3, "/": 5, "*": 5, "%": 5, "C": 5, "c": 5, "^": 7, "!": 8, "d": 9 } # 's' is a stack used for rearranging infix arguments self.s = Stack() # 'q' is a queue used to store the postfix arguments self.q = Queue() self.error = False # Converts a valid infix expression (mathematical expression) # to postfix using Reverse Polish Notation (RPN). Infix exp- # ression must be valid; this function can not check validi- # ty. Note that by design, this only supports integer expr- # ession (no floating point support). FP support can be add- # ed if while building numbers, the '.' character is accepted. # Example: Expression="1 + 2 * 3" --> 7, NOT 9 # RPN="1 2 3 * +" --> 7 # Note that the order of operations is preserved in the RPN. def infixToRPN(self, expression): # Since a number may be multiple characters, we start with an empty string, # and while each character is numeric, we append the number until a non- # numeric value is encountered. num = "" # Tokenize expression character by character for c in expression: token = str(c) # Case: we had accumulated a number but this character is not a # numeric value; so save accumulated number, and reset accumulator. if (num != "" and not token.isnumeric()): self.q.enqueue(num) num = "" # We aren't a number; so handle the token # '(' start brackets are simply markers of what point to return to when # a ')' close bracket is encountered. if (token == "("): self.s.push(token) # Special case; we look for this first -> it means we have to pop all # previous values off stack into the RPN queue until we find the '(' elif (token == ")"): # pop up until the bracket while (self.s.peek() != "("): self.q.enqueue(self.s.pop()) # pop the bracket / throw it away (it was just a marker, we're done with it) self.s.pop() # Casee: operator handling # we are done handling brackets, check for a valid operator elif (token in self.precedence): while self.s.size() != 0 and (self.precedence[token] <= self.precedence[self.s.peek()]): self.q.enqueue(self.s.pop()) self.s.push(token) # Case: character is numeric. # Append to accumulator and continue parsing elif (token.isnumeric()): num += token # Did token end on a number? If so store accumulated number in RPN queue if (num != ""): self.q.enqueue(num) # Now pop items from stack to the queue to cleanup while (self.s.size() != 0): self.q.enqueue(self.s.pop()) # At this point, we have a valid RPN in the 'q' queue # (if the infix expression was valid) # Let's return a string version: q_cp = self.q.copy() rpn = "" for c in q_cp: rpn += c + " " return (rpn) # Routine to calculate a factorial def factorial(self, value): if (value < 0): return (0) elif (value == 0 or value == 1): return (1) elif (value == 2): return (2) product = value for x in range(2, value): product = product * x return (product) # Routine to calculate "choose" (combinatorics) # Formula: # nCr (n Choose r) = n! / r!(n-r)! def choose(self, n, r): numerator = self.factorial(n) denominator = self.factorial(r) * self.factorial(n - r) # Sanity if (denominator == 0): return (0) # Compute # NOTE: Should always be an integer result, but cast # it anyways to be safe return (int(numerator / denominator)) # Given left value, right value, and an operator, calculate. def calculate(self, left, right, op): if (op == "+"): return (left + right) elif (op == "-"): return (left - right) elif (op == "*"): return (left * right) elif (op == "/"): return (int(left / right)) elif (op == "^"): return (left**right) elif (op == "%"): return (left % right) elif (op == "!"): return (self.factorial(left)) elif (op == "c" or op == "C"): return (self.choose(left, right)) # dice roll; handled with 'random' # NOTE: expressions without 'd' are deterministic; # expressions with 'd' are non-deterministic (variable # outcomes). elif (op == "d"): sum = 0 # Left value is number of rolls; right value is die # IE 3d6 = 3 rolls of a 6 sided die, summed. for i in range(left): sum += random.randint(1, right) return (sum) # whoops shouldn't have happened try to be graceful return (0) # Nifty little stack and queue algorithm for evaluating # the RPN. Expects a valid RPN expression. def evaluateRPN(self): workstack = Stack() # As we pull tokens from the queue, we validate them and if neither a number # nor an operator, we abort with an error. for t in self.q.copy(): if (t in self.precedence): # As we work backwards, right value is first; validate right = workstack.pop() if (not str(right).isnumeric() and not right in self.precedence): self.error = True break # Now get left value, validate # Special case: ! only takes one argument. Make them identical if (t == "!"): left = right else: left = workstack.pop() if (not str(left).isnumeric() and not left in self.precedence): self.error = True break # Both valid, so calculate workstack.push(self.calculate(left, right, t)) else: workstack.push(int(t)) # answer is now on the stack if (not self.error): return (workstack.pop()) else: return (0) # One function to handle it all. How Pythonic. def resolve(self, expression, repeat=False): if not repeat: self.error = False self.q.clear() self.s.clear() self.infixToRPN(expression) return (self.evaluateRPN()) else: # Repeat=True # This allows repeat dice rolls / calculations, without rebuilding # the RPN queue each time. return (self.evaluateRPN()) # Heuristic to calculate expression distribution, ment to be # used with dice rolls (ie, 2d6). This is done by repeating rolls # to a cap of n trials, then assessing the results. # Returns a histogram report with trial results, mean and mode. def getHistogram(self, expression, trials): # Validate min/max boundaries if (trials < 0): trials = 1 elif (trials > 1000000): trials = 1000000 # Initialize sb = "" rolls = dict() sum = 0 pct = 1.0 max = dict() result = dict() # Build for i in range(trials): if i == 0: roll = self.resolve(expression) else: # We already built the RPN, don't waste cycles # reuilding it on every iteration, set repeat=True. roll = self.resolve(expression, repeat=True) # Track the recurrences of roll values if (roll in rolls.keys()): rolls[roll] += 1 else: rolls[roll] = 1 # Nifty way to build a key sorted report keys = list(rolls.keys()) keys.sort() # Report sb = f"DISTRIBUTION HISTORGRAM ({trials:,} trials):\n" max[0] = max[1] = 0 for key in keys: result[key] = rolls[key] sum += key * rolls[key] pct = float(rolls[key]) / float(trials, ) * 100.0 if (pct > max[0]): max[0] = pct max[1] = key sb += f"[{key:3}] ==> {rolls[key]:,} ({pct:.2f}%)\n" # Stash pct for later rolls[key] = pct mean = float(sum) / float(trials) + 0.5 sb += f"Mean: {mean:.2f}\n" mode = max[1] sb += f"Mode: {mode}\n\n" # Scaling calculation uses a lambda function scale = lambda x, y: int(float(x / 100) * float(y) + 0.5) # Build histogram pictogragh pic = "PICTORIAL HISTOGRAM:\n" for key in keys: pic += f"[{key:3}] " for i in range(scale(rolls[key], 160)): pic += "*" pic += "\n" # Send back the report return (sb + pic)