The ACCU CVu magazine https://accu.org/index.php/journal runs a Code Critique in each issue. The idea is to take a bit of code which is usually broken in some way, and to critique it for errors and for failings to be idiomatic. The code is usually C++ for historical reasons. I like to critique by saying C++ is the wrong language, use X, where in the past X has usually been Groovy, Python, or D, or more than one of them. I’d like to introduce Rust into the mix. The current critique question is:
"I’m trying to write a very simple dice game where the computer simulates
two players each throwing dice. The higher score wins and after a
(selectable) number of turns the player who’s won most times wins the game.
(I’m going to make the game cleverer once it’s working.) But the games
always seem to be drawn and I can’t see why. Here is what the program
produces:
dice_game
Let’s play dice
How many turns? 10
Drawn!
How many turns? 8
Drawn!
How many turns? ^D
What’s going wrong - and how might you help the programmer find the problem?
As usual, there may be other suggestions you might make of some other
possible things to (re-)consider about their program."
followed by some C++ code which not only doesn’t work, it shows C++ is so far behind the state of the art that D, Go, and Rust win hands down. I have come up with a Rust solution which has clearly been informed by the C++ solution and probably shouldn’t be. So I am looking for some informed opinion on the code as idiomatic Rust code.
extern crate rand;
use std::io;
use std::io::Write;
use rand::distributions::Range;
use rand::distributions::Sample;
fn play(turns: u8, generator: &mut FnMut()->u8) {
let player1 = (0..turns).into_iter().map(|_|{ generator() }).collect::<Vec<u8>>();
let player2 = (0..turns).into_iter().map(|_|{ generator() });
let total: i32 = player1.iter().zip(player2).map(
|p| if p.0 > &p.1 { 1 } else if p.0 < &p.1 { -1 } else { 0 }
).sum();
if total == 0 {
println!("Drawn!");
}else {
println!("Player {} wins.", if total > 0 { 1 } else { 2 })
}
}
fn main() {
println!("Let's play dice");
let mut between = Range::new(1u8, 7u8); // TODO make this not mut.
let mut rng = rand::thread_rng();
loop {
print!("How many turns? ");
io::stdout().flush().unwrap();
let mut buffer = String::new();
match io::stdin().read_line(&mut buffer) {
Ok(_) =>match buffer.trim().parse::<u8>() {
Ok(turns) => play(turns, &mut ||{ between.sample(&mut rng) } ),
Err(_) => break
},
Err(_) => break
}
}
}