这只是一个小项目,开源代码部分参照了课程GitHub,但这也是我们完成大项目的第一步。
项目需求
- 猜数游戏:由go随机生成一个1-100之间的整数,由使用者进行输入,如果输入的数与随机生成的数相等,则输出正确;否则继续游戏,直到猜中数字。
- 有输入输出的提示,实现“猜数游戏”
- 用fmt.Scanf改动代码,使其更加简洁。
实现思路
代码必须要有良好的结构性,我们大致可以根据需求将代码分为以下四个模块:
- 生成随机数
- 输入
- 判断是否猜中
- 分支语句及循环语句:若是猜中,则跳出,未猜中则继续。
流程图如下:
graph TD
开始 --> 生成随机数-->输入-->判断是否猜中-->结束
判断是否猜中-->输入
代码及路径记录
引入
package main
import (
"fmt"
"math/rand"
"time"
)
这是所有go语言的起手式,其中引入的外部库可能会有差别,但是大体不差。 其中fmt是基础库,包含有输入输出等一系列函数;math含有一系列数学方法,rand用于生成随机数及其种子;time是时间库,含有很多计算时间的函数。
表格:三种库的作用
| 库名 | 库内容 |
|---|---|
| fmt | 基础库 |
| math | 数学方法库 |
| time | 时间函数库 |
生成随机数的语句
生成随机数也有需要注意的地方,如果我们直接写出如下代码:
func main() {
maxNum := 100
secretNumber := rand.Intn(maxNum)
fmt.Println("The secret number is ", secretNumber)
}
那么就可能会发现一个很奇妙的事情:
每一次生成的随机数都是同一个!
不知道大家有没有用C语言写过生成随机数,我们在其中生成的时候必须注意不能让电脑运行相同的时间,每一次随机都随到同一个数上。当然,在go语言中,也有可能像我这样什么也没有发生:
那假设,万一我们都不愿意看到的事情,也就是每一次随机出的数是同一个,怎么办?
我们可以打开go语言中自带的帮助部分,打开方式和C、Java中一样,都是把鼠标停在rand库上面,然后摁着ctr,单击鼠标左键。
打开了如图所示界面:
我们可以根据上面的介绍修改,引入一个种子:
func main() {
maxNum := 100
//每一次使用之前都要生成相应的随机数种子,不然每一次都会生成相同随机数
rand.Seed(time.Now().UnixNano())
secretNumber := rand.Intn(maxNum)
fmt.Println("The secret number is ", secretNumber)
}
结果如下所示,可以解决之前遇见的问题。
输入数
代码如下所示,其中关键点由注释给出:
fmt.Println("Please input your guess")
reader := bufio.NewReader(os.Stdin) //转化成流,从而实现读取一行等操作
input, err := reader.ReadString('\n')
if err != nil {
fmt.Println("An error occured while reading input. Please try again", err)
return
}
input = strings.Trim(input, "\r\n") //去掉换行符
guess, err := strconv.Atoi(input) //转化成数字
if err != nil {
fmt.Println("Invalid input. Please enter an integer value")
return
}
fmt.Println("You guess is", guess)
本次采用了比较复杂的写法,下面有一个简单的、使用了fmt.Scanf方法的简单写法:
fmt.Println("Please input your guess")
//reader := bufio.NewReader(os.Stdin) //转化成流,从而实现读取一行等操作
var reader string
fmt.Scanf("%s", &reader)
//input, err := reader.ReadString('\n')
input := reader
//err:=reader
if input == "" {
//fmt.Println("An error occured while reading input. Please try again", err)
fmt.Println("An error occured while reading input. Please try again")
return
}
input = strings.Trim(input, "\r\n") //去掉换行符
guess, err := strconv.Atoi(input) //转化成数字
if err != nil {
fmt.Println("Invalid input. Please enter an integer value")
return
}
fmt.Println("You guess is", guess)
本次完整展现了三种结果,分别为正确输入、空白输入和错误输入:
分支判断
之后的代码就很是容易了,我们可以使用if判断来对数值进行相等判断并加以提示,代码如下:
if guess > secretNumber {
fmt.Println("Your guess is bigger than the secret number. Please try again")
} else if guess < secretNumber {
fmt.Println("Your guess is smaller than the secret number. Please try again")
} else {
fmt.Println("Correct, you Legend!")
}
加以循环
然而,单单这样也是不够的,因为玩家只有一次猜测机会,也不知道自己要猜的数是什么,因此我们需要在外层增加一个大循环。
for {
var reader string
fmt.Scanf("%s", &reader)
//input, err := reader.ReadString('\n')
input := reader
//err:=reader
if input == "" {
//fmt.Println("An error occured while reading input. Please try again", err)
fmt.Println("An error occured while reading input. Please try again")
return
}
input = strings.Trim(input, "\r\n") //去掉换行符
guess, err := strconv.Atoi(input) //转化成数字
if err != nil {
fmt.Println("Invalid input. Please enter an integer value")
return
}
fmt.Println("You guess is", guess)
if guess > secretNumber {
fmt.Println("Your guess is bigger than the secret number. Please try again")
} else if guess < secretNumber {
fmt.Println("Your guess is smaller than the secret number. Please try again")
} else {
fmt.Println("Correct, you Legend!")
break
}
}
由此,本次小项目完成。