Skip to content

Instantly share code, notes, and snippets.

@zearen
Created February 14, 2020 02:22
Show Gist options
  • Save zearen/396d253ffd7456a8ea466088633433e1 to your computer and use it in GitHub Desktop.
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
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