Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,22 @@
Marco? Polo!

[A data structures and algorithms Ruby challenge from the Viking Code School](http://www.vikingcodeschool.com)

Yi-Xuan Lau

---

1. **What data structure is used to implement DFS?**
Graph

2. **What data structure is typically used to implement BFS?**
Tree

3. **Which one can be done recursively? (the clue should be the data structure)**
DFS

4. **Which one would you use to print a list of all the nodes in a tree or graph, starting with depth 1, then depth 2, then depth 3 etc.?**
BFS

5. **What is the difference between a tree and a graph?**
A tree is a specific kind of graph that has a root node, a hierarchy, and no cycles.
122 changes: 122 additions & 0 deletions Warmup_1_BFS_and_DFS_concepts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# BFS and DFS Concepts

## Pseudocode the following:

### Searching a simple tree of nodes where each Node has an array of child nodes(`some_node.children`) using DFS:

1. Put root node in `stack`
2. Do the following until stack is empty:
1. Set `current` as `stack.pop`
2. Return `current.value` if `current.value` is what we're looking for
3. Push `current`'s child nodes onto end of `stack`
4. Indicate the target was not found / return a value to that effect

### Searching the same tree using BFS:
1. Put root node in `queue`
2. Set `current` as `queue[0]`
3. Do the following until the `queue` is empty:
1. Return `current` if `current.value` is what we're after
2. Add `current`'s child nodes to end of `queue`
3. Remove `current` from `queue`
4. Set `current` as `queue[0]`
5. Indicate that target was not found / return a value to that effect

### Searching a graph using DFS: (stack)

#### Edge List:
Description: Array where each row consists of the `from` and `to` vertex columns

1. Create a master list of the graph's `vertices[]`
2. Until `vertices[]` is empty: (this is in case there are isolated nodes)
1. Return first item in `vertices[]` if it's our target
2. Add first item in `vertices[]` to `stack[]`
3. Until `stack[]` is empty: (this is the mechanism for traversing a vertex's edges)
1. Set `current` as `stack.pop`'s `from` value
2. Return `current.value` if it's our target
3. Mark `current` as visited (either set `current.visited` as `true` or add to a `visited` list)
3. Get `current`'s adjacent vertices (i.e. the vertices in the corresponding `to` column) by iterating through `edge_list`:
a. Push adjacent vertices to top of `stack`
*if* they have **not** been visited
5. Remove `current` from `vertices[]` master list
4. Indicate that target was not found / return a value to that effect


#### Adjacency List:
[node, node, node, node]

1. Put first item of `array` in `stack[]`
2. Until we've hit the end of the `array`:
1. Return if `array[i]` is the vertex we want
2. Until `stack[]` is empty:
1. Set `current` as `stack.pop`
2. Return if `current.value` is our target
2. Mark `current` as visited
3. Traverse the linked list to get `current`'s adjacent vertices
4. Add `current`'s adjacent vertices to top of stack *if* they have **not** been visited
3. Indicate that the target was not found / return a value to that effect


#### Adjacency Matrix
Description: A 2D array where each item in the array signifies an edge, and each row / column's index corresponds to a node's id)

DFS on an adjacency matrix is kind of like a treasure hunt. You go through each column in a row and if there's something there, it means that you need to go check out the node whose id corresponds to the current column's index number.

1. Add first vertex to `stack[]`
2. Go through each `row` in the matrix:
1. Return if `matrix[i]` is the vertex we want
2. Until `stack[]` is empty:
1. Set `current` as `stack.pop`
2. Return if `current.value` is our target
3. Mark `current` as visited
4. Go through the `columns` to get `current`'s adjacent vertices
5. Add vertices to `stack` *if* they have **not** been visited
6. Indicate that target was not found / return a value to that effect


### Searching the same graph using BFS. (Queue)

#### Edge List:
The edge list is just a two-column array of `from` nodes and `to ` nodes. To do a BFS, we need (1) a list of all vertices, (2) a queue and (3) a list of visited edges

1. Create a master list of the graph's `vertices[]`
2. Until `vertices[]` is empty: (this is in case there are isolated nodes)
1. Return first item in `vertices[]` if it's our target
2. Add first item in `vertices[]` to `queue[]`
3. Until `queue[]` is empty:
1. Set `current` as `stack.dequeue`'s `from` value
2. Return `current.value` if it's our target
3. Mark `current` as visited (either set `current.visited` as `true` or add to a `visited` list)
3. Get `current`'s adjacent vertices (i.e. the vertices in the corresponding `to` column) by iterating through `edge_list`:
a. Push adjacent vertices to back of `queue`
*if* they have **not** been visited
5. Remove `current` from `vertices[]` master list
4. Indicate that target was not found / return a value to that effect

#### Adjacency List:
Description: A 1D array where each item is a linked list / node)

1. For each `vertex` in the `array`
1. Return `vertex` if `current_vertex`'s value is what we're after
2. Otherwise, traverse the linked list
1. Return `current_vertex` if it's our target
2. Indicate that target was not found / return a value to that effect

#### Adjacency Matrix:

1. Add first vertex to `queue[]`
2. Go through each `row` in the matrix:
1. Return if `matrix[i]` is the vertex we want
2. Until `queue[]` is empty:
1. Set `current` as `queue.shift`
2. Return if `current.value` is our target
3. Mark `current` as visited
4. Go through the `columns` to get `current`'s adjacent vertices
5. Add vertices to `queue` *if* they have **not** been visited
6. Indicate that target was not found / return a value to that effect







70 changes: 70 additions & 0 deletions lib/knight_searcher.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
require_relative 'move_tree'
require_relative 'move'

class KnightSearcher
def initialize(tree)
@root = tree.root
end

def bfs_for(coord)
target = bfs_find_target(coord)
moves = get_moves(target)
print_moves(moves)
end

def dfs_for(coord)
target = dfs_find_target(coord)
moves = get_moves(target)
print_moves(moves)
end

def print_moves(moves)
puts "#{moves.size} Move(s)" unless moves.empty?
moves.each { |move| print "#{move}\n" }
end

def get_moves(target)
moves = []
while target
moves.unshift([target.x, target.y])
target = target.parent
end
moves
end

def dfs_find_target(coord)
x = coord[0]
y = coord[1]
stack = [@root]
target = ''
until stack.empty?
current = stack.pop
if x == current.x && y == current.y
return current
end
current.children.each { |child| stack << child }
end
puts "Move not found"
end

def bfs_find_target(coord)
x = coord[0]
y = coord[1]
queue = [@root]
target = ''
until queue.empty?
current = queue.shift
if x == current.x && y == current.y
return current
end
current.children.each { |child| queue << child }
end
puts "Move not found"
end


end

s = KnightSearcher.new( MoveTree.new([0, 0], 20))
s.bfs_for([6, 0])
s.dfs_for([6, 0])
1 change: 1 addition & 0 deletions lib/move.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Move = Struct.new(:x, :y, :depth, :children, :parent)
45 changes: 45 additions & 0 deletions lib/move_tree.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
require_relative 'move'
class MoveTree
attr_reader :root
def initialize(coords, depth)
@root = Move.new(coords[0], coords[1], 0, [])
@depth = depth
@queue = [@root]
@counter = 1
add_children
end

def add_children
until @queue.empty?
current = @queue.shift
return if current.depth == @depth
moves = get_moves(current.x, current.y)
moves.each do |coords|
move = Move.new(coords[0], coords[1], current.depth + 1, [], current)
current.children << move
@queue << move
@counter += 1
end
end
end

def get_moves(x, y)
# returns coordinates that knight can move to from x, y
coords = [[2, -1], [2, 1], [-2, -1], [-2, 1], [1, -2], [1, 2], [-1, 2], [-1, -2]]
moves = []
coords.each do |a, b|
moves << [x + a, y + b] if valid_move?(x + a, y + b)
end
moves
end

def valid_move?(x, y)
x.between?(0, 7) && y.between?(0, 7)
end

def inspect
puts "Your tree has #{@counter} Move nodes and a maximum depth of #{@depth}"
end


end