Best shuffle: Difference between revisions
Content added Content deleted
m (→{{header|Sidef}}: minor code simplifications) |
|||
Line 2,795: | Line 2,795: | ||
up pu 0 |
up pu 0 |
||
a a 1</pre> |
a a 1</pre> |
||
== {{header|Rust}} == |
|||
<lang rust>extern crate permutohedron; |
|||
extern crate rand; |
|||
use std::cmp::{min, Ordering}; |
|||
use std::env; |
|||
use rand::{thread_rng, Rng}; |
|||
use std::str; |
|||
const WORDS: &'static [&'static str] = &["abracadabra", "seesaw", "elk", "grrrrrr", "up", "a"]; |
|||
#[derive(Eq)] |
|||
struct Solution { |
|||
original: String, |
|||
shuffled: String, |
|||
score: usize, |
|||
} |
|||
// Ordering trait implementations are only needed for the permutations method |
|||
impl PartialOrd for Solution { |
|||
fn partial_cmp(&self, other: &Solution) -> Option<Ordering> { |
|||
match (self.score, other.score) { |
|||
(s, o) if s < o => Some(Ordering::Less), |
|||
(s, o) if s > o => Some(Ordering::Greater), |
|||
(s, o) if s == o => Some(Ordering::Equal), |
|||
_ => None, |
|||
} |
|||
} |
|||
} |
|||
impl PartialEq for Solution { |
|||
fn eq(&self, other: &Solution) -> bool { |
|||
match (self.score, other.score) { |
|||
(s, o) if s == o => true, |
|||
_ => false, |
|||
} |
|||
} |
|||
} |
|||
impl Ord for Solution { |
|||
fn cmp(&self, other: &Solution) -> Ordering { |
|||
match (self.score, other.score) { |
|||
(s, o) if s < o => Ordering::Less, |
|||
(s, o) if s > o => Ordering::Greater, |
|||
_ => Ordering::Equal, |
|||
} |
|||
} |
|||
} |
|||
fn _help() { |
|||
println!("Usage: best_shuffle <word1> <word2> ..."); |
|||
} |
|||
fn main() { |
|||
let args: Vec<String> = env::args().collect(); |
|||
let mut words: Vec<String> = vec![]; |
|||
match args.len() { |
|||
1 => { |
|||
for w in WORDS.iter() { |
|||
words.push(String::from(*w)); |
|||
} |
|||
} |
|||
_ => { |
|||
for w in args.split_at(1).1 { |
|||
words.push(w.clone()); |
|||
} |
|||
} |
|||
} |
|||
let solutions = words.iter().map(|w| best_shuffle(w)).collect::<Vec<_>>(); |
|||
for s in solutions { |
|||
println!("{}, {}, ({})", s.original, s.shuffled, s.score); |
|||
} |
|||
} |
|||
// Implementation iterating over all permutations |
|||
fn _best_shuffle_perm(w: &String) -> Solution { |
|||
let mut soln = Solution { |
|||
original: w.clone(), |
|||
shuffled: w.clone(), |
|||
score: w.len(), |
|||
}; |
|||
let w_bytes: Vec<u8> = w.clone().into_bytes(); |
|||
let mut permutocopy = w_bytes.clone(); |
|||
let mut permutations = permutohedron::Heap::new(&mut permutocopy); |
|||
while let Some(p) = permutations.next_permutation() { |
|||
let hamm = hamming(&w_bytes, p); |
|||
soln = min(soln, |
|||
Solution { |
|||
original: w.clone(), |
|||
shuffled: String::from(str::from_utf8(p).unwrap()), |
|||
score: hamm, |
|||
}); |
|||
// Accept the solution if score 0 found |
|||
if hamm == 0 { |
|||
break; |
|||
} |
|||
} |
|||
soln |
|||
} |
|||
// Quadratic implementation |
|||
fn best_shuffle(w: &String) -> Solution { |
|||
let w_bytes: Vec<u8> = w.clone().into_bytes(); |
|||
let mut shuffled_bytes: Vec<u8> = w.clone().into_bytes(); |
|||
// Shuffle once |
|||
let sh: &mut [u8] = shuffled_bytes.as_mut_slice(); |
|||
thread_rng().shuffle(sh); |
|||
// Swap wherever it doesn't decrease the score |
|||
for i in 0..sh.len() { |
|||
for j in 0..sh.len() { |
|||
if (i == j) | (sh[i] == w_bytes[j]) | (sh[j] == w_bytes[i]) | (sh[i] == sh[j]) { |
|||
continue; |
|||
} |
|||
sh.swap(i, j); |
|||
break; |
|||
} |
|||
} |
|||
let res = String::from(str::from_utf8(sh).unwrap()); |
|||
let res_bytes: Vec<u8> = res.clone().into_bytes(); |
|||
Solution { |
|||
original: w.clone(), |
|||
shuffled: res, |
|||
score: hamming(&w_bytes, &res_bytes), |
|||
} |
|||
} |
|||
fn hamming(w0: &Vec<u8>, w1: &Vec<u8>) -> usize { |
|||
w0.iter().zip(w1.iter()).filter(|z| z.0 == z.1).count() |
|||
} |
|||
</lang> |
|||
{{out}} |
|||
<pre> |
|||
abracadabra, caadabarabr, (0) |
|||
seesaw, esswea, (0) |
|||
elk, lke, (0) |
|||
grrrrrr, rrrrgrr, (5) |
|||
up, pu, (0) |
|||
a, a, (1) |
|||
</pre> |
|||
=={{header|Scala}}== |
=={{header|Scala}}== |