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
Binary file added .DS_Store
Binary file not shown.
2 changes: 2 additions & 0 deletions Knight's Travails Pseudocode.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Warmup 2: Knight's Travails Pseudocode

15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,18 @@
Marco? Polo!

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

DAVID WIESENBERG

Warmup 1: BFS and DFS Concepts

Before getting started, it's critical that you understand the concepts behind (and the differences between) depth-first search and breadth-first search. Start by answering the following questions in your README file:

What data structure is used to implement DFS? graph/tree
What data structure is typically used to implement BFS? graph
Which one can be done recursively? (the clue should be the data structure) DFS
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
What is the difference between a tree and a graph?
Tree: special type of graph; children have only one parent, only one edge between any two nodes; no loops (cycles)
Graph: no child/parent relationships; edges can go to any other node; can have more than one edge between any two nodes; can have loops (cycles), etc.

25 changes: 25 additions & 0 deletions knight.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Knight's Travails

# Knight - print moves

require_relative 'knight_searcher'
require_relative 'move_tree'

module KnightsTravails

Move = Struct.new(:x, :y, :depth, :parent, :children)

# print move data tidily

class Move
# puts calls # to_s
def to_s
"position: #{x}, #{y}, depth: #{depth}"
end
end

end # class Move




91 changes: 91 additions & 0 deletions knight_searcher.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Knight's Travails

# Knight - search moves until reaching target position


module KnightsTravails

class KnightSearcher

attr_reader :move_tree

def initialize(move_tree)
@move_tree = move_tree
end

# breadth first search
def bfs_for(target_coords)

start = move_tree.start_node
start.depth = 0
queue = [ start ]

until queue.empty?
current = queue.pop

# if target found ... return path traced
if target_coords == [current.x, current.y]
return trace_path_to(current)

# else add all children not yet visited to queue
else
current.children.each do |move|
next if move.depth # depth set means it has been visited
queue.unshift(move)
move.depth = current.depth + 1
end
end
end
"Not found!" # if queue runs out of moves (tree too small or
# stopped at certain depth)

end

# depth first search
def dfs_for(target_coords)
stack = [move_tree.start_node]
depth = 0
current = nil

until stack.empty?
current = stack.pop
current.depth = depth
if target_coords == [current.x, current.y]
return trace_path_to(current)
end
depth += 1
current.children.each {|move| stack.push(move) unless move.depth}
end
"Not found!" # if stack runs out of moves (tree too small or
# stopped at certain depth)
end

private

# return coordinate path from start node until current move
# by traversing the tree
def trace_path_to(move)
path = []
node = move

until node.nil?
path.unshift[node.x, node.y]
node = node.parent
end

path

end


end # class KnightSearcher

end # module KnightsTravails








81 changes: 81 additions & 0 deletions move_tree.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Knight's Travails

# Knight - build and inspect tree


module KnightsTravails

class MoveTree
attr_reader :start_node, :max_depth, :node_count

# cf tree set up test
def initialize (start_coords, max_depth)
x, y = start_coords[0], start_coords[1]

@start_node = Move.new(x, y, nil, nil, [])
@max_depth = max_depth
@node_count = 1 # initial node

build_tree
puts inspect
end

def inspect
"Move Tree starts at [#{start_node.x}, #{start_node.y}]; maximum depth: #{max_depth}; number of nodes: #{node_count}."
end

private

# build tree of moves recursively until maximum depth reached
def build_tree(current_node = self.start_node, depth = 0)

if depth < self.max_depth
append_next_moves(current_node)

# build new tree from children
current_node.children.each do |child|
build_tree(child, depth + 1)
end
end

end

# append all possible next moves to current move
# update number of nodes
def append_next_moves(current_move)
return unless current_move.children.empty?

next_moves = possible_moves(current_move)
@node_count += next_moves.size
next_moves.each do |move|
new_move = Move.new(move[0], move[1], nil, current_move, [])
current_move.children << new_move
end
end

# return array of legal moves from a particular position, in the form of coordinate pairs
def possible_moves(move)
x, y = move.x, move.y

[ [x+2, y-1], [x+2, y+1],
[x-2, y-1], [x-2, y+1],
[x+1, y+2], [x-1, y+2],
[x+1, y-2], [x-1, y-2] ].select {|move| legal?(move)}
end

# is move legal?
def legal?(move)
move[0].between?(0, 7) && move[1].between?(0,7)
end

end # class MoveTree

end # module KnightsTravails








1 change: 1 addition & 0 deletions solution_knights_travails
Submodule solution_knights_travails added at 8b139f
18 changes: 18 additions & 0 deletions tests.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Knight's Travails

# Tests

require_relative 'knight'

include KnightsTravails

move_tree = MoveTree.new([3,3],6)
knight_searcher = KnightSearcher.new(move_tree)
puts
puts knight_searcher.bfs_for([1,2])
puts
puts knight_searcher.bfs_for([7,7])
puts
puts knight_searcher.bfs_for([4,3])
puts