后端实践(一):GO语言工程实践课后作业:实现思路、代码以及路径记录|青训营;

91 阅读3分钟

这只是一个小项目,开源代码部分参照了课程GitHub,但这也是我们完成大项目的第一步。

项目需求

  1. 猜数游戏:由go随机生成一个1-100之间的整数,由使用者进行输入,如果输入的数与随机生成的数相等,则输出正确;否则继续游戏,直到猜中数字。
  2. 有输入输出的提示,实现“猜数游戏”
  3. 用fmt.Scanf改动代码,使其更加简洁。

实现思路

代码必须要有良好的结构性,我们大致可以根据需求将代码分为以下四个模块:

  1. 生成随机数
  2. 输入
  3. 判断是否猜中
  4. 分支语句及循环语句:若是猜中,则跳出,未猜中则继续。

流程图如下:

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语言中,也有可能像我这样什么也没有发生:

1690508320473.png 那假设,万一我们都不愿意看到的事情,也就是每一次随机出的数是同一个,怎么办? 我们可以打开go语言中自带的帮助部分,打开方式和C、Java中一样,都是把鼠标停在rand库上面,然后摁着ctr,单击鼠标左键。 打开了如图所示界面:

1690510351980.png 我们可以根据上面的介绍修改,引入一个种子:

func main() {
	maxNum := 100
	//每一次使用之前都要生成相应的随机数种子,不然每一次都会生成相同随机数
	rand.Seed(time.Now().UnixNano())
	secretNumber := rand.Intn(maxNum)
	fmt.Println("The secret number is ", secretNumber)
}

结果如下所示,可以解决之前遇见的问题。

1690510224838.png

输入数

代码如下所示,其中关键点由注释给出:

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)

本次完整展现了三种结果,分别为正确输入、空白输入和错误输入:

1690512159851.png

分支判断

之后的代码就很是容易了,我们可以使用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
                    }
            }

由此,本次小项目完成。