R:\ is a virtualbox drive visible to Windows but actually a Linux dir.
Discourse only allows me to upload images, so here are the two files:
Cargo.toml
[package]
name = "wordladder"
version = "0.1.0"
authors = ["Mark"]
[profile.release]
codegen-units = 1
[dependencies]
regex = "0.2"
rand = "0.4"
lazy_static = "1.0"
src/main.rs:
#[macro_use]
extern crate lazy_static;
extern crate rand;
extern crate regex;
use std::fs::File;
use std::io;
use std::io::{BufReader,BufRead};
use std::collections::HashSet;
use std::time::{Duration, Instant};
use regex::Regex;
static WORDFILE: &str = "/usr/share/hunspell/en_GB.dic";
const SIZE: usize = 4; // Should be even
const STEPS: usize = SIZE;
type WordSet = HashSet<String>;
type WordVec = Vec<String>;
type Letters = Vec<char>;
fn main() {
if let Ok(words) = read_words(WORDFILE, SIZE) {
let timer = Instant::now();
let mut count = 1;
print!("Try ");
loop {
print!(".");
if let Some(ladder) = generate_ladder(&words, STEPS) {
println!("{}", count);
for word in ladder {
println!("{}", word);
}
break;
}
count += 1
}
println!("{:.05} sec", as_secs(timer.elapsed()));
}
}
fn as_secs(duration: Duration) -> f64 {
duration.as_secs() as f64 + duration.subsec_nanos() as f64 * 1e-9
}
fn generate_ladder(words: &WordSet, steps: usize) -> Option<WordVec> {
let mut words = words.clone();
let compatibles = words.clone();
let mut ladder = vec![];
let mut prev = update_words_and_ladder(&mut ladder, &mut words,
&compatibles);
for _ in 0..steps + 1 {
let compatibles = compatible_words(prev.as_str(), &words);
if compatibles.is_empty() {
return None
}
prev = update_words_and_ladder(&mut ladder, &mut words,
&compatibles);
}
let first: Letters = ladder[0].chars().collect();
let last: Letters = ladder[ladder.len() - 1].chars().collect();
for i in 0..first.len() {
if first[i] == last[i] {
return None // Don't accept any vertical letters in common
}
}
Some(ladder)
}
fn update_words_and_ladder(ladder: &mut WordVec, words: &mut WordSet,
compatibles: &WordSet) -> String {
let mut rng = rand::thread_rng();
let prev = rand::seq::sample_iter(&mut rng, compatibles, 1)
.unwrap()[0];
ladder.push(prev.to_string());
words.remove(prev);
prev.to_string()
}
fn compatible_words(prev: &str, words: &WordSet) -> WordSet {
let mut compatibles = WordSet::new();
let prev_chars: Letters = prev.chars().collect();
let size = prev_chars.len() - 1;
for word in words.iter() {
let mut count = 0;
let word_chars: Letters = word.chars().collect();
for i in 0..prev_chars.len() {
if prev_chars[i] == word_chars[i] {
count += 1;
}
}
if count == size {
compatibles.insert(word.to_string());
}
}
compatibles
}
fn read_words(wordfile: &str, size: usize) -> io::Result<WordSet> {
lazy_static! { static ref RE: Regex = Regex::new(r"^[a-z]+").unwrap(); }
let mut words = WordSet::new();
let file = File::open(wordfile)?;
for line in BufReader::new(file).lines() {
if let Ok(line) = line {
if let Some(captures) = RE.captures(&line) {
let word = &captures[0];
if word.len() == size {
words.insert(word.to_uppercase());
}
}
}
}
Ok(words)
}
As noted this compiles and runs fine with 1.28 on Windows and Linux even after doing a cargo update. But with 1.29 it only works on Linux. However, taking your hint, I tried it on C: and it worked fine.
So it looks like the problem is with the virtualbox drive (which I guess looks like a network shared drive to Windows). This is a pain for me because I do all my editing on Linux and only use Windows for compiling and testing but will have to always have to copy to C: to do this now: unless it gets fixed of course. So, for now, I'll hold off on 1.29 and hope that this is fixed. (I'll add an issue about it: #54216.)