填坑篇——猜谜游戏,一个有趣小游戏的代码实现以及迭代升级| 青训营笔记

176 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天

 ps:由于最近春节事务较多,走亲访友的,还有实验室布置的任务,所以一直是咕咕鸟,本来打算日更的。本文是对于伴学笔记第一天的案例1的代码实现和介绍。

1. 简介

 在很多与朋友的聚会中,自然少不了玩一些助兴的小游戏,在这其中数字炸弹最为常见,那么什么是数字炸弹呢?

 数字炸弹就是在一个数字范围内,有一个数字作为炸弹,谁猜中这个炸弹就被惩罚.比如范围是1 ~ 99,炸弹是60,然后猜了一个数字是30,30不是炸弹,那么现在猜数字的范围就缩小到30 ~ 100, 又猜了一个数字80,80也不是炸弹,那么现在又缩小范围到30~80,每次猜不能猜边界上的值,直到有人猜中这个炸弹,然后就受到惩罚。

 而本文所实现的猜谜游戏可以说和数字炸弹十分相近,就让我来带着你用实现这个有意思的小游戏。

2. 猜谜游戏的迭代以及代码实现

2.1 使用rand类生成随机数

 对于一个猜谜游戏的实现,那随机数的生成必不可少。而在GO语言中,要实现随机数的生成我们应当用到math/rand包中的函数,使用rand.Intn()函数生成随机数。具体代码如下:

package main

import (
	"fmt"
	"math/rand"
)

func main() {
	maxNum := 100
	secretNumber := rand.Intn(maxNum)
	fmt.Println("The secret number is ", secretNumber)
}

2.2 随机数种子的生成

 如果读者将上方代码进行了运行,那将会发现随机数正确生成了,但是却存在一个问题:生成的随机数它一直是同一个值,并不会因为执行而发生变化,这是为什么呢?

 这是因为rand.Intn方法将返回一个非负伪随机数,其值范围在半开区间 [0, n)。而rand.Intn函数生成随机数会受随机数种子的影响,如果为输入随机数种子,将会使用默认的种子作为随机数种子。故而想要实现随机数的生成,我们还需要生成随机数种子。

 我们可以将当前的时间作为随机数种子进行传入,以实现不同时间生成不同随机数的功能。在获取当前时间时,我们可以使用官方提供的time包,利用该包,高效的实现对时间的获取。具体代码优化如下:

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)
}

2.3 实现对用户输入的读取

 在以上的代码,我们已经成功实现了对于随机数的生成。但作为一个猜谜游戏,用户的输入自然必不可少。想要实现对用户输入的读取,我们可以使用bufio中的NewReader方法将os.stdin标准输入流中的数据读取到reader变量中来,最后再使用strings包中的方法将"\n"进行去除。具体代码实现如下:

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)
	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)
}

2.4 实现对用户输入的判断逻辑

 现在的代码已经能很好的实现数据的读取和随机数的生成了,接下来就是猜谜游戏的判断逻辑相关代码的编写。

 对于猜谜游戏而言,判断逻辑应该是:假设生成的随机数值为X,如果用户输入的值与生成值相比,输入值小于生成值,则应当返回“输入值小了”;如果输入值大于生成值,则返回“输入值大了”;如果输入值等于生成值,则返回“恭喜你获胜”。具体相关代码如下:

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)
	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)
	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!")
	}
}

2.5 实现游戏循环,简易版猜谜游戏完成

 在上方代码的基础上,我们可以发现已经完成了猜谜游戏的基本功能。但是在广泛的情况下,应当是没有猜中继续给玩家猜谜的机会,所以,我们可以将之前的代码放到一个循环之中,以期实现更加完善的代码功能,具体代码如下:

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
		}
	}
}

3. 课后作业——使用fmt.Scanf简化代码的实现

 具体代码如下:

package main

import (
	"fmt"
	"math/rand"
	"strconv"
	"time"
)

func main() {
	maxNum := 100
	rand.Seed(time.Now().UnixNano())
	secretNumber := rand.Intn(maxNum)
	var input string
	
	for {
		fmt.Printf("Please input your guess: ")
		fmt.Scanf("%v",&input)
		fmt.Scanln()//使用scanln吸取换行符
		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
		}
	}
}