猜数字游戏(Go语言实战篇)

41 阅读4分钟

示例代码

 package main
 ​
 import (
     "bufio"
     "fmt"
     "math/rand"
     "os"
     "strconv"
     "strings"
     "time"
 )
 ​
 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)
     for {
         input, err := reader.ReadString('\n')
         if err != nil {
             fmt.Println("An error occured while reading input. Please try again", err)
             continue
         }
         input = strings.Trim(input, "\r\n")
 ​
         guess, err := strconv.Atoi(input)
         if err != nil {
             fmt.Println("Invalid input. Please enter an integer value")
             continue
         }
         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
         }
     }
 }

代码分析

这段代码实现了一个简单的猜数字游戏,它的具体逻辑如下:

  1. 首先导入了必要的包,包括bufio用于读取输入,fmt用于格式化输出,math/rand用于生成随机数,os用于与操作系统交互,strconv用于字符串和数字类型之间的转换,strings用于字符串处理,time用于获取当前时间。

  2. main函数中,程序设置了一个最大数字maxNum为100,并使用当前时间的纳秒级Unix时间戳作为随机数生成器的种子,这样可以保证每次运行程序时生成的随机数都不同。

  3. 然后,程序生成一个0到maxNum之间的随机数secretNumber,这个数字就是玩家需要猜测的秘密数字。

  4. 程序提示玩家输入猜测的数字,并使用bufio.NewReader创建一个读取器reader,用于从标准输入读取玩家的输入。

  5. 接下来,程序进入一个无限循环,不断读取玩家的输入并进行处理:

    • 使用reader.ReadString('\n')读取一行输入,直到遇到换行符为止。

    • 如果读取过程中发生错误,程序会打印错误信息并继续循环,提示玩家重新输入。

    • 读取到的输入字符串会被去除首尾的回车和换行符,得到一个干净的数字字符串。

    • 然后,程序尝试将这个数字字符串转换为整数guess,如果转换失败(例如输入的不是数字),程序会打印错误信息并继续循环,提示玩家重新输入。

    • 如果转换成功,程序会打印玩家的猜测,并根据猜测的大小给出相应的提示:

      • 如果猜测大于秘密数字,程序会提示玩家猜测的数字太大,需要继续尝试。
      • 如果猜测小于秘密数字,程序会提示玩家猜测的数字太小,需要继续尝试。
      • 如果猜测等于秘密数字,程序会打印祝贺信息并跳出循环,游戏结束。
  6. 游戏结束后,程序会退出。

代码改进

修改代码,使用fmt.Scanf()简化代码实现

 package main
 ​
 import (
     "fmt"
     "math/rand"
     "time"
 )
 ​
 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")
     var guess int
     for {
         _, err := fmt.Scanf("%d", &guess)
         if err!= nil {
             fmt.Println("An error occured while reading input. Please try again", err)
             continue
         }
         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
         }
     }
 }

简化过程

fmt.Scanf() 是 Go 语言标准库中的一个函数,用于从标准输入(通常是控制台)读取格式化输入。与使用 bufio.NewReaderstrings.Trim 等操作相比,fmt.Scanf() 可以简化代码实现,因为它直接提供了格式化输入的功能,不需要额外的步骤来处理输入的读取和解析。

在上述代码中,fmt.Scanf() 被用来读取玩家输入的猜测数字。它的使用方式如下:

 _, err := fmt.Scanf("%d", &guess)

此处的 %d 是一个格式化动词,表示期望输入一个整数。&guess 是一个指向 int 类型变量的指针,用于接收输入的值。fmt.Scanf() 会阻塞程序执行,等待用户输入一个整数,然后将输入的值存储在 guess 变量中。

如果输入的格式不正确(例如,用户输入了一个非数字字符),fmt.Scanf() 会返回一个错误,通过捕获这个错误用于提示用户重新输入,这就是代码中 if err!= nil 部分的作用。

作为对比,如果使用 bufio.NewReaderstrings.Trim,需要额外的代码来创建读取器,读取一行输入,然后去除输入字符串的首尾空格。此外,还还需要使用 strconv.Atoi 或其他方法来将字符串转换为整数。这些额外的步骤使得代码更加冗长,而 fmt.Scanf() 则提供了一个更直接和简洁的方式来实现相同的功能。

fmt.Scanf() 通过提供一个直接的格式化输入接口,简化了代码实现,减少了出错的可能性,使代码更加易读和易于维护。