Initial commit
This commit is contained in:
commit
4681dc4b66
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "Graph-Theory"
|
||||
version = "0.1.0"
|
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "Graph-Theory"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
BIN
assets/graph1.png
Normal file
BIN
assets/graph1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 170 KiB |
189
src/main.rs
Normal file
189
src/main.rs
Normal file
@ -0,0 +1,189 @@
|
||||
#![allow(non_snake_case, dead_code)]
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// simple_searches()?;
|
||||
breadth_first_search_grid_shortest_path()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn simple_searches() -> Result<(), String> {
|
||||
let adjacency_list_graph = vec![
|
||||
(0, vec![1, 9]),
|
||||
(1, vec![0, 8]),
|
||||
(2, vec![3]),
|
||||
(3, vec![2, 4, 5, 7]),
|
||||
(4, vec![3]),
|
||||
(5, vec![3, 6]),
|
||||
(6, vec![5, 7]),
|
||||
(7, vec![3, 6, 11, 10, 8]),
|
||||
(8, vec![1, 7]),
|
||||
(9, vec![0, 8]),
|
||||
(10, vec![7, 11]),
|
||||
(11, vec![7, 10]),
|
||||
(12, vec![]),
|
||||
];
|
||||
println!("---Depth first search---");
|
||||
depth_first_search(&adjacency_list_graph, 0)?;
|
||||
println!("\n\n---Breadth first search---");
|
||||
breadth_first_search_shortest_path(&adjacency_list_graph, 0, 11)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// See assets/graph1.png
|
||||
fn depth_first_search(graph: &Vec<(usize, Vec<usize>)>, start_node: usize) -> Result<(), String> {
|
||||
let mut nodes_to_visit: Vec<usize> = vec![start_node];
|
||||
let mut visited_nodes = vec![false; graph.len() - 1];
|
||||
let mut last_node = start_node;
|
||||
while !nodes_to_visit.is_empty() {
|
||||
let node = nodes_to_visit.pop().ok_or("Unable to get node!")?;
|
||||
if visited_nodes[node] {
|
||||
continue;
|
||||
}
|
||||
println!("Current Node: {node}");
|
||||
|
||||
visited_nodes[node] = true;
|
||||
let neighbors: Vec<&usize> = graph[node]
|
||||
.1
|
||||
.iter()
|
||||
.filter(|neighbor| last_node != **neighbor)
|
||||
.collect();
|
||||
nodes_to_visit.extend(neighbors);
|
||||
last_node = node;
|
||||
}
|
||||
println!("Visited Nodes: {visited_nodes:#?}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// See assets/graph1.png
|
||||
fn breadth_first_search_shortest_path(
|
||||
graph: &Vec<(usize, Vec<usize>)>,
|
||||
start_node: usize,
|
||||
end_node: usize,
|
||||
) -> Result<(), String> {
|
||||
let mut visited_nodes = HashSet::new();
|
||||
let mut queue = VecDeque::new();
|
||||
let mut dirty_path: Vec<Option<usize>> = vec![None; graph.len() - 1];
|
||||
queue.push_back(start_node);
|
||||
|
||||
while let Some(node) = queue.pop_front() {
|
||||
if visited_nodes.contains(&node) {
|
||||
continue;
|
||||
}
|
||||
println!("Current node: {node}");
|
||||
|
||||
visited_nodes.insert(node);
|
||||
|
||||
if node == end_node {
|
||||
break;
|
||||
}
|
||||
|
||||
for neighbor in &graph[node].1 {
|
||||
if neighbor != &node && !visited_nodes.contains(neighbor) {
|
||||
queue.push_back(*neighbor);
|
||||
dirty_path[*neighbor] = Some(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let dirty_path: Vec<_> = dirty_path.iter().flatten().cloned().collect();
|
||||
|
||||
let mut path = vec![];
|
||||
let mut curr_node = end_node;
|
||||
while curr_node != start_node {
|
||||
path.push(curr_node);
|
||||
curr_node = dirty_path[curr_node - 1];
|
||||
}
|
||||
path.push(start_node);
|
||||
path.reverse();
|
||||
println!("Visited Nodes: {visited_nodes:#?}");
|
||||
println!("Shortest path from '{start_node}' to '{end_node}': {path:#?}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn breadth_first_search_grid_shortest_path() -> Result<(), String> {
|
||||
// S is start
|
||||
// E is end
|
||||
// . are open spaces
|
||||
// # are blocked
|
||||
let dungeon_grid = vec![
|
||||
//0 1 2 3 4 5 6
|
||||
['S', '.', '.', '#', '.', '.', '.'], // 0
|
||||
['.', '#', '.', '.', '.', '#', '.'], // 1
|
||||
['.', '#', '.', '.', '.', '.', '.'], // 2
|
||||
['.', '.', '#', '#', '.', '.', '.'], // 3
|
||||
['#', '.', '#', 'E', '.', '#', '.'], // 4
|
||||
];
|
||||
|
||||
let mut start_position = (0, 0);
|
||||
let mut end_position = (0, 0);
|
||||
|
||||
// Find the start and end position.
|
||||
for (row, row_vals) in dungeon_grid.iter().enumerate() {
|
||||
for (column, char) in row_vals.iter().enumerate() {
|
||||
if *char == 'S' {
|
||||
start_position = (row as i32, column as i32);
|
||||
} else if *char == 'E' {
|
||||
end_position = (row as i32, column as i32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut visited_nodes = HashSet::new();
|
||||
let mut queue = VecDeque::new();
|
||||
queue.push_front(start_position);
|
||||
let grid_rows = dungeon_grid.len() as i32;
|
||||
let grid_columns = dungeon_grid[0].len() as i32;
|
||||
let mut reached_end = false;
|
||||
let mut dirty_path: HashMap<(i32, i32), (i32, i32)> = HashMap::new();
|
||||
while let Some((row, column)) = queue.pop_front() {
|
||||
println!("Current Position: ({row},{column})");
|
||||
for (vec_row, vec_column) in [(0, -1), (-1, 0), (0, 1), (1, 0)] {
|
||||
let new_row: i32 = row + vec_row;
|
||||
let new_column: i32 = column + vec_column;
|
||||
|
||||
// Ensure the new position is within the grid
|
||||
if (new_row < 0 || new_column < 0)
|
||||
|| (new_row >= grid_rows || new_column >= grid_columns)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ensure we haven't visited the node yet
|
||||
if !visited_nodes.contains(&(new_row, new_column)) {
|
||||
match dungeon_grid[new_row as usize][new_column as usize] {
|
||||
'.' => {
|
||||
queue.push_back((new_row, new_column));
|
||||
dirty_path.insert((new_row, new_column), (row, column));
|
||||
}
|
||||
'E' => {
|
||||
queue.drain(..);
|
||||
dirty_path.insert((new_row, new_column), (row, column));
|
||||
reached_end = true;
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
visited_nodes.insert((row, column));
|
||||
}
|
||||
|
||||
if !reached_end {
|
||||
println!("No solution found, cannot reach the end!");
|
||||
return Ok(())
|
||||
}
|
||||
// Get the shortest path
|
||||
let mut path: Vec<(i32, i32)> = Vec::new();
|
||||
let mut curr_node = end_position;
|
||||
while curr_node != start_position {
|
||||
path.push(curr_node);
|
||||
let dirt_path = dirty_path[&(curr_node.0, curr_node.1)];
|
||||
curr_node = dirt_path;
|
||||
}
|
||||
path.push(start_position);
|
||||
path.reverse();
|
||||
println!("Shortest path from '{start_position:?}' to '{end_position:?}': {path:?}");
|
||||
println!("Number of moves taken: {}", path.len());
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue
Block a user