Skip to content

Commit f969b41

Browse files
committed
undirected
1 parent 013335a commit f969b41

File tree

2 files changed

+365
-0
lines changed

2 files changed

+365
-0
lines changed

undirected_graph/undirected_graph.rb

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#lib/undirected_graph.rb
2+
3+
class UndirectedGraph
4+
5+
def initialize()
6+
end
7+
8+
#accessor methods:
9+
10+
def vertices
11+
end
12+
13+
def neighbors(vertex)
14+
end
15+
16+
#if there is no edge throws and ArgumentError
17+
def weight(vertex1, vertex2)
18+
end
19+
20+
def degree(vertex)
21+
end
22+
23+
def has_vertex?(vertex)
24+
end
25+
26+
def has_edge?(vertex1, vertex2)
27+
end
28+
29+
def size
30+
end
31+
32+
#mutator methods:
33+
34+
#adds a vertex to the graph
35+
#if a vertex is already in the graph, does nothing
36+
#returns true iff a vertex was added (false if the vertex was already in the graph)
37+
def add_vertex!(vertex)
38+
end
39+
40+
#adds an edge with the given weight between two vertices, starting at vertex1 and pointing to the vertex2
41+
#if there is already an edge with said weight, it updates the weight
42+
#if either one (or both) of the vertices are not in the graph, it throws an ArgumentError
43+
#also, if you're trying to make a self_loop, throws an error
44+
def add_edge!(vertex1, vertex2, weight)
45+
end
46+
47+
#removes a vertex and and edges associated with it
48+
#if there is no such vertex in the graph, throws an ArgumentError
49+
#returns a hash of the removed vertex's out_neighborhood
50+
def remove_vertex!(vertex)
51+
end
52+
53+
#removes an edge between two vertices (vertex1 <-> vertex2)
54+
#returns the weight of the removed edge
55+
#if there was no such edge (or either one of the vertices were not in the vertex, throws an ArgumentError)
56+
def remove_edge!(vertex1, vertex2)
57+
end
58+
end
Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
require "undirected_graph"
2+
3+
describe UndirectedGraph do
4+
5+
#First, accessor methods on an empty graph (to set a good base)
6+
describe "empty graph" do
7+
blank = UndirectedGraph.new()
8+
9+
describe ".vertices" do
10+
context "given an empty graph" do
11+
it "returns an empty hash" do
12+
expect(blank.vertices().length()).to eql(0)
13+
end
14+
end
15+
end
16+
17+
describe ".size" do
18+
context "given empty graph" do
19+
it "size should be 0" do
20+
expect(blank.size()).to eql(0)
21+
end
22+
end
23+
end
24+
end
25+
26+
#mutator methods first:
27+
describe ".add_vertex!" do
28+
context "given an empty graph" do
29+
it "adds exactly one vertex" do
30+
g = UndirectedGraph.new()
31+
32+
expect(g.add_vertex!("Water")).to eql(true)
33+
expect(g.size).to eql(1)
34+
expect(g.has_vertex?("Water")).to eql(true)
35+
end
36+
end
37+
38+
context "graph with different element in it" do
39+
it "adds the element" do
40+
g = UndirectedGraph.new()
41+
g.add_vertex!("Water")
42+
43+
expect(g.add_vertex!("Fire")).to eql(true)
44+
expect(g.size).to eql(2)
45+
expect(g.has_vertex?("Fire")).to eql(true)
46+
expect(g.has_vertex?("Water")).to eql(true)
47+
end
48+
end
49+
50+
context "given a graph with the same element in it" do
51+
it "doesn't add the element" do
52+
g = UndirectedGraph.new()
53+
g.add_vertex!("Water")
54+
55+
expect(g.add_vertex!("Water")).to eql(false)
56+
expect(g.size).to eql(1)
57+
end
58+
end
59+
end
60+
61+
describe ".add_edge!" do
62+
context "given vertices not in the graph" do
63+
it "throw an error" do
64+
expect{UndirectedGraph.new().add_edge!("Grass", "Electric", 3)}.to raise_error(ArgumentError)
65+
end
66+
end
67+
68+
context "given vertices without an edge between them" do
69+
it "creates an edge pointing both ways" do
70+
g = UndirectedGraph.new()
71+
g.add_vertex!("Dragon")
72+
g.add_vertex!("Fairy")
73+
74+
expect(g.add_edge!("Dragon", "Fairy", 2)).to eql(true)
75+
expect(g.has_edge?("Dragon", "Fairy")).to eql(true)
76+
expect(g.has_edge?("Fairy", "Dragon")).to eql(true)
77+
expect(g.weight("Dragon", "Fairy")).to eql(2)
78+
expect(g.weight("Fairy", "Dragon")).to eql(2)
79+
end
80+
end
81+
82+
context "given vertices with an edge already between them" do
83+
it "updates the edge weight" do
84+
g = UndirectedGraph.new()
85+
g.add_vertex!("Dragon")
86+
g.add_vertex!("Fairy")
87+
g.add_edge!("Dragon", "Fairy", 0)
88+
89+
expect(g.add_edge!("Dragon", "Fairy", 2)).to eql(false)
90+
expect(g.has_edge?("Dragon", "Fairy")).to eql(true)
91+
expect(g.has_edge?("Fairy", "Dragon")).to eql(true)
92+
93+
expect(g.weight("Dragon", "Fairy")).to eql(2)
94+
expect(g.weight("Fairy", "Dragon")).to eql(2)
95+
end
96+
end
97+
98+
context "given vertices with an edge made one way" do
99+
it "updates the edge, even when arguments reversed" do
100+
g = UndirectedGraph.new()
101+
g.add_vertex!("Dragon")
102+
g.add_vertex!("Fairy")
103+
g.add_edge!("Dragon", "Fairy", 0)
104+
105+
expect(g.add_edge!("Fairy", "Dragon", 2)).to eql(false)
106+
expect(g.has_edge?("Dragon", "Fairy")).to eql(true)
107+
expect(g.has_edge?("Fairy", "Dragon")).to eql(true)
108+
109+
expect(g.weight("Dragon", "Fairy")).to eql(2)
110+
expect(g.weight("Fairy", "Dragon")).to eql(2)
111+
end
112+
end
113+
114+
context "given a graph trying to make a self-loop" do
115+
it "throws an error" do
116+
g = UndirectedGraph.new()
117+
g.add_vertex!("Dragon")
118+
119+
expect{g.add_edge!("Dragon", "Dragon", 2)}.to raise_error(ArgumentError)
120+
end
121+
end
122+
end
123+
124+
describe ".remove_edge!" do
125+
context "given vertices not in the graph" do
126+
it "throw an error" do
127+
expect{UndirectedGraph.new().remove_edge!("Grass", "Electric")}.to raise_error(ArgumentError)
128+
end
129+
end
130+
131+
context "given an edge not in graph" do
132+
it "throw an error" do
133+
g = UndirectedGraph.new()
134+
g.add_vertex!("Grass")
135+
g.add_vertex!("Electric")
136+
137+
expect{UndirectedGraph.new().remove_edge!("Grass", "Electric", 3)}.to raise_error(ArgumentError)
138+
end
139+
end
140+
141+
context "given an edge in the graph" do
142+
it "removes the edge between both vertices" do
143+
g = UndirectedGraph.new()
144+
g.add_vertex!("Fighting")
145+
g.add_vertex!("Steel")
146+
g.add_edge!("Fighting", "Steel", 2)
147+
148+
expect(g.remove_edge!("Fighting", "Steel")).to eql(2)
149+
expect(g.has_edge?("Fighting", "Steel")).to eql(false)
150+
end
151+
end
152+
153+
context "reverse arguments" do
154+
it "still removes the edge" do
155+
g = UndirectedGraph.new()
156+
g = UndirectedGraph.new()
157+
g.add_vertex!("Fighting")
158+
g.add_vertex!("Steel")
159+
g.add_edge!("Steel", "Fighting", 1)
160+
161+
expect(g.remove_edge!("Fighting", "Steel")).to eql(1)
162+
expect(g.has_edge?("Fighting", "Steel")).to eql(false)
163+
expect(g.has_edge?("Steel", "Fighting")).to eql(false)
164+
end
165+
end
166+
end
167+
168+
describe ".remove_vertex!" do
169+
context "given a graph with no vertices" do
170+
it "throws an error" do
171+
expect{UndirectedGraph.new().remove_vertex!("Dark")}.to raise_error(ArgumentError)
172+
end
173+
end
174+
175+
context "given a graph with that isolated vertex" do
176+
it "removes that vertex" do
177+
g = UndirectedGraph.new()
178+
g.add_vertex!("Fire")
179+
180+
expect(g.remove_vertex!("Fire")).to eql({})
181+
expect(g.has_vertex?("Fire")).to eql(false)
182+
end
183+
end
184+
185+
context "given a graph with an out vertex" do
186+
it "removes that vertex and its connections" do
187+
g = UndirectedGraph.new()
188+
g.add_vertex!("Fire")
189+
g.add_vertex!("Grass")
190+
g.add_edge!("Fire", "Grass", 2)
191+
192+
expect(g.remove_vertex!("Fire")).to eql({"Grass" => 2})
193+
expect(g.has_vertex?("Fire")).to eql(false)
194+
expect(g.degree("Grass")).to eql(0)
195+
end
196+
end
197+
198+
context "given a graph with an in vertex" do
199+
it "removes that vertex and its connections" do
200+
g = UndirectedGraph.new()
201+
g.add_vertex!("Fire")
202+
g.add_vertex!("Water")
203+
g.add_edge!("Water", "Fire", 2)
204+
205+
expect(g.remove_vertex!("Fire")).to eql({"Water" => 2})
206+
expect(g.has_vertex?("Fire")).to eql(false)
207+
expect(g.degree("Water")).to eql(0)
208+
end
209+
end
210+
end
211+
212+
describe ".degree" do
213+
context "vertex not in graph" do
214+
it "throws an error" do
215+
expect{UndirectedGraph.new().degree("Dark")}.to raise_error(ArgumentError)
216+
end
217+
end
218+
219+
context "point to some vertexes" do
220+
it "has proper degree" do
221+
g = UndirectedGraph.new()
222+
g.add_vertex!("Psychic")
223+
g.add_vertex!("Normal")
224+
g.add_vertex!("Ghost")
225+
g.add_edge!("Ghost", "Psychic", 2)
226+
g.add_edge!("Ghost", "Normal", 0)
227+
228+
expect(g.degree("Ghost")).to eql(2)
229+
end
230+
end
231+
232+
context "add, remove, add, vertices" do
233+
it "has degree of 1" do
234+
g = UndirectedGraph.new()
235+
g.add_vertex!("Bug")
236+
g.add_vertex!("Grass")
237+
g.add_edge!("Bug", "Grass", 2)
238+
g.remove_edge!("Bug", "Grass")
239+
g.add_vertex!("Fire")
240+
g.add_edge!("Bug", "Fire", 0.5)
241+
242+
expect(g.degree("Bug")).to eql(1)
243+
end
244+
end
245+
246+
context "reverse arguments" do
247+
it "has proper degree" do
248+
g = UndirectedGraph.new()
249+
g.add_vertex!("Psychic")
250+
g.add_vertex!("Normal")
251+
g.add_vertex!("Ghost")
252+
g.add_edge!("Psychic", "Ghost", 1)
253+
g.add_edge!("Ghost", "Normal", 0)
254+
255+
expect(g.degree("Ghost")).to eql(2)
256+
end
257+
end
258+
end
259+
260+
describe ".neighbors" do
261+
context "vertex not in graph" do
262+
it "throws error" do
263+
expect{UndirectedGraph.new().neighbors("Dark")}.to raise_error(ArgumentError)
264+
end
265+
end
266+
267+
context "no neighbors" do
268+
it "returns empty array" do
269+
g = UndirectedGraph.new
270+
g.add_vertex!("Steel")
271+
expect(g.neighbors("Steel")).to eql([])
272+
end
273+
end
274+
275+
context "two out neighbors" do
276+
it "returns an array of both neighbors" do
277+
g = UndirectedGraph.new
278+
g.add_vertex!("Steel")
279+
g.add_vertex!("Rock")
280+
g.add_vertex!("Ice")
281+
g.add_edge!("Steel", "Ice", 2)
282+
g.add_edge!("Steel", "Rock", 2)
283+
284+
n = g.neighbors("Steel")
285+
expect(n.include?("Ice")).to eql(true)
286+
expect(n.include?("Rock")).to eql(true)
287+
expect(n.length).to eql(2)
288+
end
289+
end
290+
291+
context "two in neighbors" do
292+
it "returns array of both" do
293+
g = UndirectedGraph.new()
294+
g.add_vertex!("Psychic")
295+
g.add_vertex!("Normal")
296+
g.add_vertex!("Ghost")
297+
g.add_edge!("Psychic", "Ghost", 1)
298+
g.add_edge!("Normal", "Ghost", 0)
299+
300+
n = g.neighbors("Ghost")
301+
expect(n.include?("Normal")).to eql(true)
302+
expect(n.include?("Psychic")).to eql(true)
303+
expect(n.length).to eql(2)
304+
end
305+
end
306+
end
307+
end

0 commit comments

Comments
 (0)