Skip to content

Instantly share code, notes, and snippets.

@46bit
Created December 29, 2014 02:42
Show Gist options
  • Save 46bit/09ef5da4df4af157fd31 to your computer and use it in GitHub Desktop.
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.
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