Created
February 14, 2020 02:22
-
-
Save zearen/396d253ffd7456a8ea466088633433e1 to your computer and use it in GitHub Desktop.
A little script I wrote to generate a transition map for a single pawn playing PrimeClimb
This file contains hidden or 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
extern crate petgraph; | |
use petgraph::graph::{Graph, NodeIndex}; | |
use std::fmt; | |
use std::ops::Range; | |
use std::slice::Iter; | |
use std::io::Write; | |
#[derive(Eq, PartialEq, Clone, Copy, Debug)] | |
enum Op { Add, Sub, Mul, Div } | |
impl Op { | |
fn ops() -> Iter<'static, Op> { | |
static OP_ARRAY: [Op; 4] = [Op::Add, Op::Sub, Op::Mul, Op::Div]; | |
OP_ARRAY.iter() | |
} | |
} | |
#[derive(Eq, PartialEq, Clone, Debug)] | |
struct OpEdge { | |
operator: Op, | |
operand: i32, | |
} | |
impl OpEdge { | |
fn try_move(&self, range: &Range<i32>, pos: i32) -> Option<i32> { | |
let new_pos = match self.operator { | |
Op::Add => Some(pos + self.operand), | |
Op::Sub => Some(pos - self.operand), | |
Op::Mul => Some(pos * self.operand), | |
Op::Div => if pos % self.operand == 0 { | |
Some(pos / self.operand) | |
} else { | |
None | |
}, | |
}?; | |
if range.contains(&new_pos) { | |
Some(new_pos) | |
} else { | |
None | |
} | |
} | |
} | |
impl fmt::Display for OpEdge { | |
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
match self.operator { | |
Op::Add => write!(f, "+"), | |
Op::Sub => write!(f, "-"), | |
Op::Mul => write!(f, "×"), | |
Op::Div => write!(f, "/"), | |
}?; | |
write!(f, "{}", self.operand) | |
} | |
} | |
struct MovementGraph { | |
range: Range<i32>, | |
dice_sides: Vec<i32>, | |
graph: Graph<i32, OpEdge>, | |
nodes: Vec<NodeIndex>, | |
} | |
/// Given a range and a position inside that range, find the relative index within the range. I.e. | |
/// if we're given a range 3, 30, then position 5 would be index | |
fn index_in_range(range: &Range<i32>, pos: i32) -> usize { | |
debug_assert!(pos >= range.start); | |
(pos - range.start) as usize | |
} | |
impl MovementGraph { | |
fn new() -> Self { | |
MovementGraph::new_with(0..102, (1..=10).collect()) | |
} | |
fn new_with(range: Range<i32>, dice_sides: Vec<i32>) -> Self { | |
let mut graph = Graph::new(); | |
let mut nodes = Vec::with_capacity((range.end - range.start) as usize); | |
// Add the vertices so we have them up front. | |
for i in range.clone() { | |
nodes.push(graph.add_node(i)); | |
} | |
for pos in range.clone() { | |
let index = index_in_range(&range, pos); | |
for op in Op::ops() { | |
for roll in dice_sides.iter() { | |
let edge = OpEdge{operator: op.clone(), operand: roll.clone()}; | |
edge.try_move(&range, pos).and_then(|new_pos| | |
Some(graph.add_edge( | |
nodes[index], nodes[index_in_range(&range, new_pos)], | |
edge)) | |
); | |
} | |
} | |
} | |
graph.shrink_to_fit(); | |
MovementGraph{range, dice_sides, graph, nodes} | |
} | |
} | |
fn main() -> std::io::Result<()> { | |
let movement_graph = MovementGraph::new(); | |
let mut out_file = std::fs::File::create("movement.dot")?; | |
write!(out_file, "{}", petgraph::dot::Dot::new(&movement_graph.graph))?; | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment