讲动人的故事,写懂人的代码
2.6 故事4: 一直让玩家不断猜
我们全班要一起用三种语言来写第4个故事啦。这可能是我们所有故事中最复杂的一个了。不过别担心,贾克强已经把这个故事的需求都用投影仪展示出来了。
- 程序会提示玩家猜两个骰子的点数之和。
- 如果玩家第一次输入点数之和就答错了,程序就会提示‘第一次猜就错了哦’(You guessed it wrong on the first try.),并让玩家继续猜。
- 如果玩家第二次或之后输入点数之和也答错了,但这次猜测比上次更接近正确答案,程序就会提示‘更热了’(Hotter.),并让玩家继续猜。
- 如果离正确答案更远了,程序就会提示‘更冷了’(Colder.),并让玩家继续猜。
- 如果距离正确答案的距离和上次一样,程序就会提示‘不冷不热’(Neither cold nor hot.),并让玩家继续猜。
- 如果玩家猜对了,程序就会提示‘恭喜你答对了!’(You win!),并让玩家继续猜。
贾克强:“故事4对于Rust新手来说,可能有些挑战性。但别担心,这个故事,我来帮你们写Rust代码哦。”

2.6.1 Rust版故事4
2.6.1.1 初始化 previous_guess
贾克强:“故事4是让玩家不断地猜测,所以我们把原来只猜一次的代码,放入了一个循环中。这样一来,就不需要原来猜一次的代码了。“
”然后,我们新增了一行代码。为了能判断玩家的猜测是否接近答案,我们增加了一个previous_guess变量来存储玩家的上一次猜测。在玩家第一次猜测之前,previous_guess变量的值应该为空。但是,一旦玩家猜了第一次,这个变量就不会再是空的。因此,我们为这个变量使用了Option<u32>类型。这意味着previous_guess既可以是一个u32的32位无符号整数(表示玩家猜测的点数),也可以是None(表示玩家还没有猜测过)。在Rust中,None是一个枚举值(也就是枚举类型Option<u32>的变体),用来表示‘无效’或‘未设置’。“
- println!("Please input your guess (between 2 and 12).");
-
- let mut guess = String::new();
-
- io::stdin()
- .read_line(&mut guess)
- .expect("Failed to read line");
-
- let guess: u32 = guess.trim().parse().expect("Please type a number!");
-
- println!("You guessed: {guess}");
-
- match guess.cmp(&sum_of_two_dice) {
- Ordering::Less | Ordering::Greater => println!("You guessed it wrong on the first try"),
- Ordering::Equal => println!("You win!"),
- }
+ let mut previous_guess: Option<u32> = None;
2.6.1.2 增加循环结构
贾克强:“我们在这里添加了一个loop循环,让代码能够反复进行玩家的输入和猜测。loop在Rust中是一个无尽的循环,但别担心,我们在后面的故事中,可以使用break语句来结束它哦!”
+ loop {
2.6.1.3 获取玩家输入
贾克强:“这部分代码和原代码有些相似,它们都是把玩家的输入读取出来,然后解析成u32类型的整数哦。”
+ println!("Please input your guess (between 2 and 12).");
+
+ let mut guess = String::new();
+
+ io::stdin()
+ .read_line(&mut guess)
+ .expect("Failed to read line");
+
+ let guess: u32 = guess.trim().parse().expect("Please type a number!");
+
+ println!("You guessed: {guess}");
2.6.1.4 新的比较逻辑
贾克强兴奋地解释道:“这里,我们新增了对previous_guess的检查哦。如果previous_guess是None(也就是说这是我们的第一次猜测),我们就直接将当前的猜测和骰子的和进行比较。若玩家第一次猜得不对,那我们就会把当前的猜测存入previous_guess中。”
他继续说:“Some(guess)的意思是,我们把guess封装在一个Some枚举中,并赋值给previous_guess,这样previous_guess保存的值就从None变成了Some(guess)。这就意味着,previous_guess不再是空的了,而是包含了玩家上一次的猜测值哦。”
+ match previous_guess {
+ None => match guess.cmp(&sum_of_two_dice) {
+ Ordering::Less | Ordering::Greater => {
+ println!("You guessed it wrong on the first try.");
+ previous_guess = Some(guess);
+ 