aboutsummaryrefslogtreecommitdiff
path: root/src/scramble.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/scramble.rs')
-rw-r--r--src/scramble.rs133
1 files changed, 133 insertions, 0 deletions
diff --git a/src/scramble.rs b/src/scramble.rs
new file mode 100644
index 0000000..abee6a6
--- /dev/null
+++ b/src/scramble.rs
@@ -0,0 +1,133 @@
+use std::fmt;
+use std::str;
+
+use rand::{
+ distributions::{Distribution, Standard},
+ Rng
+};
+
+pub struct Scramble(Vec<Move>);
+
+impl Scramble {
+ pub fn new_rand(n: usize) -> Scramble {
+ let mut sequence: Vec<Move> = Vec::with_capacity(n);
+
+ while sequence.len() != n {
+ let direction = rand::random::<Direction>();
+ let modifier = rand::random::<Modifier>();
+
+ if let Some(l) = sequence.last() {
+ if l.direction == direction {
+ continue;
+ }
+ }
+ sequence.push(Move { direction, modifier });
+ }
+ Scramble(sequence)
+ }
+}
+
+impl fmt::Display for Scramble {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self.0.iter().map(|m| m.to_string()).collect::<Vec<String>>().join(" "))
+ }
+}
+
+impl str::FromStr for Scramble {
+ type Err = &'static str;
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ let strs = s.split(" ");
+ let mut scramble = Scramble(Vec::new());
+ for s in strs {
+ scramble.0.push(s.parse()?);
+ }
+ Ok(scramble)
+ }
+}
+
+impl str::FromStr for Move {
+ type Err = &'static str;
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ use Direction::*;
+ use Modifier::*;
+
+ let mut cs = s.chars();
+ let direction = match cs.next() {
+ Some('F') => Front,
+ Some('B') => Back,
+ Some('D') => Down,
+ Some('U') => Up,
+ Some('R') => Right,
+ Some('L') => Left,
+ Some(_) => return Err("Move direction isn't valid"),
+ None => return Err("Move format is empty"),
+ };
+ let modifier = match cs.next() {
+ Some('\'') => Prime,
+ Some('2') => Twice,
+ Some(_) => return Err("Move modifier isn't valid"),
+ None => No,
+ };
+ if let Some(_) = cs.next() {
+ return Err("Unexpected character in move");
+ }
+ Ok(Move{ direction, modifier })
+ }
+}
+
+#[derive(PartialEq)]
+enum Direction { Front, Back, Down, Up, Right, Left, }
+
+enum Modifier { No, Twice, Prime, }
+
+struct Move {
+ direction: Direction,
+ modifier: Modifier,
+}
+
+// https://stackoverflow.com/questions/48490049
+impl Distribution<Direction> for Standard {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Direction {
+ use Direction::*;
+ match rng.gen_range(0, 6) {
+ 0 => Front,
+ 1 => Back,
+ 2 => Down,
+ 3 => Up,
+ 4 => Right,
+ _ => Left,
+ }
+ }
+}
+
+impl Distribution<Modifier> for Standard {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Modifier {
+ use Modifier::*;
+ match rng.gen_range(0, 3) {
+ 0 => No,
+ 1 => Twice,
+ _ => Prime,
+ }
+ }
+}
+
+impl fmt::Display for Move {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use Direction::*;
+ use Modifier::*;
+ let letter = match self.direction {
+ Front => "F",
+ Back => "B",
+ Down => "D",
+ Up => "U",
+ Right => "R",
+ Left => "L",
+ };
+ let modifier = match self.modifier {
+ No => "",
+ Twice => "2",
+ Prime => "'",
+ };
+ write!(f, "{}{}", letter, modifier)
+ }
+}