Created
December 29, 2014 02:42
-
-
Save 46bit/09ef5da4df4af157fd31 to your computer and use it in GitHub Desktop.
Bizarre difference in Vec<Node<NodeInfo>> lengths in subsequent areas of code. Need to reduce out a testcase for debugging/getting help.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::HashMap; | |
use std::num::Int; | |
use std::num::Float; | |
use std::io; | |
use std::uint; | |
use std::io::File; | |
#[deriving(Show)] | |
pub struct Graph<D,E> { | |
pub nodes: Vec<Node<D>>, | |
pub edges: Vec<Edge<E>> | |
} | |
impl<D,E> Graph<D,E> { | |
pub fn new() -> Graph<D,E> { | |
Graph{nodes: Vec::new(), edges: Vec::new()} | |
} | |
pub fn insert_node(&mut self, node: Node<D>) -> NodeIndex { | |
let mut node : Node<D> = Node::new(node.data); | |
let idx = NodeIndex(self.nodes.len()); | |
node.index = idx; | |
self.nodes.push(node); | |
return idx; | |
} | |
pub fn add_edge(&mut self, start: NodeIndex, end: NodeIndex, data: E) -> EdgeIndex { | |
// How do we get nodes mutable? | |
match self.nodes.get_mut(start.val()) { | |
None => return INVALID_EDGE_INDEX, | |
Some(_) => () | |
}; | |
match self.nodes.get_mut(end.val()) { | |
None => return INVALID_EDGE_INDEX, | |
Some(_) => () | |
}; | |
// @TODO: Does Rust make getting the edge index then pushing threadsafe? | |
let edge_idx = EdgeIndex(self.edges.len()); | |
self.edges.push(Edge{index: edge_idx, start: start, end: end, data: data}); | |
self.nodes.get_mut(start.val()).unwrap().edges.push(edge_idx); | |
self.nodes.get_mut(end.val()).unwrap().edges.push(edge_idx); | |
return edge_idx; | |
} | |
pub fn node<'a>(&'a self, index: NodeIndex) -> Option<&'a Node<D>> { | |
io::stderr().write(b"node.1 "); | |
io::stderr().write(index.to_string().into_bytes().as_slice()); | |
io::stderr().write(b"\n"); | |
let node = self.nodes.get(index.val()); | |
io::stderr().write(b"node.2 "); | |
match node { | |
None => io::stderr().write(b"None "), | |
Some(_) => io::stderr().write(b"Some ") | |
}; | |
io::stderr().write((*self).nodes.len().to_string().into_bytes().as_slice()); | |
io::stderr().write(b"\n"); | |
node | |
} | |
pub fn node_data<'a>(&'a self, index: NodeIndex) -> Option<&'a D> { | |
match self.node(index) { | |
Some(node) => return Some(&node.data), | |
None => return None | |
} | |
} | |
pub fn edge<'a>(&'a self, index: EdgeIndex) -> Option<&'a Edge<E>> { | |
return self.edges.get(index.val()); | |
} | |
pub fn edge_data<'a>(&'a self, index: EdgeIndex) -> Option<&'a E> { | |
match self.edge(index) { | |
Some(edge) => return Some(&edge.data), | |
None => return None | |
} | |
} | |
} | |
#[deriving(Show)] | |
pub struct Node<D> { | |
pub index: NodeIndex, | |
pub edges: Vec<EdgeIndex>, | |
pub data: D | |
} | |
impl<D> Node<D> { | |
pub fn new(data: D) -> Node<D> { | |
Node{index: INVALID_NODE_INDEX, edges: Vec::new(), data: data} | |
} | |
} | |
#[deriving(Clone, PartialEq, Show)] | |
pub struct NodeIndex(pub uint); | |
pub static INVALID_NODE_INDEX: NodeIndex = NodeIndex(uint::MAX); | |
impl NodeIndex { | |
pub fn val(&self) -> uint { | |
let NodeIndex(v) = *self; | |
return v; | |
} | |
} | |
#[deriving(Show)] | |
pub struct Edge<E> { | |
pub index: EdgeIndex, | |
pub start: NodeIndex, | |
pub end: NodeIndex, | |
pub data: E | |
} | |
#[deriving(Clone, PartialEq, Show)] | |
pub struct EdgeIndex(pub uint); | |
pub static INVALID_EDGE_INDEX: EdgeIndex = EdgeIndex(uint::MAX); | |
impl EdgeIndex { | |
pub fn val(&self) -> uint { | |
let EdgeIndex(v) = *self; | |
return v; | |
} | |
} | |
#[deriving(Show)] | |
pub struct Maze<'a> { | |
pub dimensions: MazeCoord, | |
pub neighboring: MazeNeighbor, | |
pub graph: Graph<MazeNodeInfo,MazeEdgeInfo>, | |
pub costs: HashMap<char,f64> | |
} | |
impl <'a>Maze<'a> { | |
pub fn new_from_chars(dimensions: MazeCoord, chars: &str, neighboring: MazeNeighbor, costs: HashMap<char, f64>) -> Maze { | |
let mut m = Maze{dimensions: dimensions, neighboring: neighboring, graph: Graph::new(), costs: costs}; | |
m.graph = m.char_graph(chars); | |
m | |
} | |
pub fn coord_valid(&self, coord: MazeCoord) -> bool { | |
!(coord.x < 0 || coord.y < 0 || coord.x >= self.dimensions.x || coord.y >= self.dimensions.y) | |
} | |
pub fn coord_node(&self, coord: MazeCoord) -> Option<&Node<MazeNodeInfo>> { | |
io::stderr().write(b"coord_node.1 "); | |
io::stderr().write(coord.to_string().into_bytes().as_slice()); | |
io::stderr().write(b"\n"); | |
if coord.x < 0 || coord.y < 0 || coord.x >= self.dimensions.x || coord.y >= self.dimensions.y { | |
return None; | |
} | |
let node_index = (coord.x + coord.y * self.dimensions.x) as uint; | |
io::stderr().write(b"coord_node.2 "); | |
io::stderr().write(node_index.to_string().into_bytes().as_slice()); | |
io::stderr().write(b"\n"); | |
let node = self.graph.node(NodeIndex(node_index)); | |
io::stderr().write(b"coord_node.3 "); | |
io::stderr().write(node.to_string().into_bytes().as_slice()); | |
io::stderr().write(b"\n"); | |
let node2 = self.graph.node(NodeIndex(5)); | |
io::stderr().write(b"coord_node.4 "); | |
io::stderr().write(node2.to_string().into_bytes().as_slice()); | |
io::stderr().write(b"\n"); | |
node | |
} | |
fn char_graph(&mut self, chars: &str) -> Graph<MazeNodeInfo,MazeEdgeInfo> { | |
let mut graph = Graph::new(); | |
let mut x = 0i; | |
let mut y = 0i; | |
for symbol in chars.chars() { | |
if symbol == '\n' { | |
x = 0; | |
y += 1; | |
continue; | |
} | |
let n = graph.insert_node(Node::new(MazeNodeInfo::new(x, y, symbol))); | |
io::stderr().write(b"~~~ char_graph.1 "); | |
io::stderr().write(n.to_string().into_bytes().as_slice()); | |
io::stderr().write(b"\n"); | |
x += 1; | |
} | |
for node in graph.nodes.iter() { | |
io::stderr().write(b"~~~ char_graph.2 "); | |
io::stderr().write(node.to_string().into_bytes().as_slice()); | |
io::stderr().write(b"\n"); | |
io::stderr().write(b"~~~ char_graph.3 "); | |
match NodeIndex(5 + 7) { | |
NodeIndex(Z) => match graph.nodes.get(Z) { | |
None => io::stderr().write(b"None"), | |
Some(X) => io::stderr().write((*X).index.to_string().into_bytes().as_slice()) | |
} | |
}; | |
io::stderr().write(b"\n"); | |
match self.neighboring { | |
MazeNeighbor::NESW => self.char_graph_node_edges_nesw(node), | |
MazeNeighbor::Square => self.char_graph_node_edges_square(node) | |
} | |
io::stderr().write(b"~~~ char_graph.4 "); | |
match node.index { | |
NodeIndex(Z) => match graph.nodes.get(Z) { | |
None => io::stderr().write(b"None"), | |
Some(X) => io::stderr().write((*X).index.to_string().into_bytes().as_slice()) | |
} | |
}; | |
io::stderr().write(b"\n"); | |
} | |
return graph | |
} | |
fn char_graph_node_edges_nesw(&mut self, start_node: &Node<MazeNodeInfo>) { | |
for offset in [[0, -1], [1, 0], [0, 1], [-1, 0]].iter() { | |
io::stderr().write(b"char_graph_node_edges_nesw "); | |
io::stderr().write(offset.to_string().into_bytes().as_slice()); | |
io::stderr().write(b"\n"); | |
self.add_edge_by_offset(start_node, MazeCoord{x: offset[0], y: offset[1]}); | |
} | |
} | |
fn char_graph_node_edges_square(&mut self, start_node: &Node<MazeNodeInfo>) { | |
for offset in [[0, -1], [1, 0], [0, 1], [-1, 0]].iter() { | |
self.add_edge_by_offset(start_node, MazeCoord{x: offset[0], y: offset[1]}); | |
} | |
for offset in [[-1, -1], [1, -1], [1, 1], [-1, 1]].iter() { | |
self.add_edge_by_offset(start_node, MazeCoord{x: offset[0], y: offset[1]}); | |
} | |
} | |
fn add_edge_by_offset(&mut self, start_node: &Node<MazeNodeInfo>, offset: MazeCoord) { | |
let end_coord = MazeCoord{x: start_node.data.x + offset.x, y: start_node.data.y + offset.y}; | |
let end_node = match self.coord_node(end_coord) { | |
None => return, | |
Some(en) => en.clone() | |
}; | |
let distance2 = offset.x.pow(2) + offset.y.pow(2); | |
let distance = (distance2 as f64).sqrt(); | |
let unit_cost : f64 = match self.costs.get(&end_node.data.symbol) { | |
None => -1.0, | |
Some(uc) => *uc as f64 | |
}; | |
// Don't add edge if it'll cost negatively. | |
if unit_cost < 0.0f64 { | |
return; | |
} | |
let edge_info = MazeEdgeInfo::new(distance, unit_cost); | |
io::stderr().write(b"add_edge_by_offset "); | |
io::stderr().write(edge_info.to_string().into_bytes().as_slice()); | |
io::stderr().write(b"\n"); | |
self.graph.add_edge(start_node.index, end_node.index, edge_info); | |
} | |
} | |
#[deriving(Show,PartialEq)] | |
pub enum MazeNeighbor {NESW, Square} | |
#[deriving(Show,PartialEq)] | |
pub struct MazeCoord { | |
pub x: int, | |
pub y: int | |
} | |
#[deriving(Show)] | |
pub struct MazeNodeInfo { | |
pub x: int, | |
pub y: int, | |
pub symbol: char | |
} | |
impl MazeNodeInfo { | |
pub fn new(x : int, y: int, symbol: char) -> MazeNodeInfo { | |
MazeNodeInfo{x: x, y: y, symbol: symbol} | |
} | |
} | |
#[deriving(Show)] | |
pub struct MazeEdgeInfo { | |
pub distance: f64, | |
pub unit_cost: f64, | |
pub cost: f64 | |
} | |
impl MazeEdgeInfo { | |
pub fn new(distance : f64, unit_cost: f64) -> MazeEdgeInfo { | |
MazeEdgeInfo{distance: distance, unit_cost: unit_cost, cost: distance * unit_cost} | |
} | |
} | |
fn main() { | |
let mut graph : Graph<&str,&str> = Graph::new(); | |
let maze_dimensions = MazeCoord{x: 4, y: 4}; | |
let maze_coords = "# ##\n# ##\n# #\n## #\n"; | |
let mut maze_costs : HashMap<char,f64> = HashMap::new(); | |
maze_costs.insert('#', -1.0); | |
maze_costs.insert(' ', 1.0); | |
let mut maze = Maze::new_from_chars(maze_dimensions, maze_coords, MazeNeighbor::NESW, maze_costs); | |
println!("{}", maze); | |
//let mut file = File::create(&Path::new("message.txt")); | |
//file.write(maze.to_string().into_bytes().as_slice()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment