目录
游戏介绍
这是一场电脑和人类的博弈。游戏规则是:一共有21个火柴(默认),人类选手先开始取火柴,一次可以取1-3根火柴。接下来就是电脑取。谁取完火柴后,总火柴数只剩下1或0,那位选手就输掉了游戏,而赢家会有奖励。这款小游戏的游戏页面不限于枯燥无味的python黑色文本页面,拓展使用了turtle库进行图形展示,让这款游戏的可视性更强。
海龟画布已经擦掉4根火柴的效果
一、代码展示
from turtle import*
import time
import random
speed(0)
sticks = int(numinput("enter number of sticks: ", "21"))
while sticks < 15 or sticks > 30: # 检测火柴总数是否符合规范
print("invalid, have to be 15-30")
sticks = int(numinput("enter number of sticks: ", "21"))
#海龟画布的一些初始化设置
w, h = [1000, 500]
setup(w, h)
dis = 50 # 屏幕边缘离火柴的距离
step = (w-dis*2)/(sticks-1) # 火柴之间间隔
cnt = 0 # 记录取走火柴的累加情况
coor_x=[(-w/2+dis)+i*step for i in range(sticks)] # 每个火柴开始画的x坐标
coor_y = (-h+dis)/2
colors, white = [["red", "darkblue", "orange", "darkgreen",
"darkgoldenrod", "black", "purple"], ["white"]] # 序列解包
def draw_line(nums, colors): # 绘制火柴的函数,nums是要绘制的火柴数量
setheading(90) # 火柴垂直于屏幕
pensize(3)
nums = min(nums, len(coor_x)) # 取较小值,避免
for i in range(0, nums):
pu() # 抬笔
pencolor(colors[i % len(colors)])
goto(coor_x[i], coor_y)
pd() # 落笔
fd(h-dis*2)
is_win=False
draw_line(sticks, colors) # 绘制总火柴数
gift = ["薯片", "谢谢参与", "饮料", "王者皮肤"]
with open("input.txt", "r") as file:
txt = file.read()
print(txt.format(sticks), "\n") # 打印一段存储在txt文件中的游戏介绍
while sticks >= 2: # 主程序
num = int(input("enter sticks to take:"))
if num > 3 or num < 1:
print("take 1-3 sticks once!")
continue
# 人机互战的代码
cnt = cnt+num # 累计拿去的火柴
draw_line(cnt, white) # 在海龟屏幕里抹去拿掉的火柴
sticks = sticks-num # 剩余的火柴
if sticks <= 1: # 人类选手输的情况
print("you lost! you can try again")
is_win=False
break
else: # 若人类未输,电脑取火柴
print("there are {}sticks left".format(sticks))
ro = random.randint(1, 3)
sticks = sticks-ro
time.sleep(1)
print(f"i am going to take away... {ro} sticks\n")
cnt = cnt+ro
draw_line(cnt, white) # 用白线条覆盖原来的彩色线条,实现擦除效果
if is_win:
time.sleep(1) # 人类选手赢的情况
print("oh no, i lose!", "\n")
time.sleep(1)
done() # 关闭海龟画布页面
print("great, you beat the computer...you are worth being rewarded! ",
"\nyou get:", gift[random.randint(0, len(gift)-1)])
txt文本文档内容如下:
a competition between human and AI is taking place...
remember, the rule is: whoever left the last stick or no sticks lost the game.
game begins! there are {} sticks in total
you can only take 1-3sticks once, good luck!
txt文本文档的写入
二、代码讲解
这个代码看起来好像很长,其实他就是由很多个简单的小部分衔接在一起的组成的,我们来介绍这几个部分:1.海龟画布初始化和检测用户输入 2.海龟画五彩火柴部分 3.主程序:人类输入和机器人输入 4.奖励环节
1.海龟画布初始化和检测用户输入
首先第一行我们写from turtle import* 而不是直接import turtle,主要是因为使用前者可以直接使用海龟库内一定义项目名称,而且使用的是函数的绝对路径,不需要确定引用,所以就比较方便。注意到这里没有写turtle.xxx,直接写xxx就是这个原因。
变量sticks是用户输入的总火柴数,默认是21,我们这里使用while条件循环检测sticks是否太大或太小。然后就是序列解包,把1000,500分别赋值给宽w和高h,然后setup(w,h)设置海龟屏幕大小。
dis是火柴离屏幕边缘的距离。step是火柴之间的间隔,等于火柴排序总长/间隔数量。但我们没有间隔数量,所以我们想用火柴数量代替。火柴数量=间隔数量+1,稍微变换一下,我们得到step=火柴总长/(火柴数量-1)。另外火柴排序总长就是屏幕宽w减火柴离两边屏幕边缘的距离dis*2。所以就有了step=(w-dis*2)/(sticks-1)。
2.绘制火柴的函数draw_line()
怎么绘制火柴呢?其实和之前我做的绘制坐标轴刻度很像:火柴垂直于x轴,之间有固定的间隔,且都是靠x坐标轴的自增来实现绘制的。其中nums是循环次数,代码每循环一次,就画一根火柴。大家可能有些不太理解 nums=min(nums,len(coor_x))是要干什么。他其实就是一行规避程序报错的代码(处理边界问题)。因为有时候如果只剩下2根火柴,而此时又到了电脑,他有随机生成3的概率,这样剩下的火柴数就可能会变成-1,而cnt (记录取走火柴的累加情况)就会超过coor_x索引。因此我们要把cnt控制在len(coor_x),也就是列表长度内。至于为什么cnt会有这个影响,等我们看到主程序部分大家也许就会更清楚了。
剩下的代码都不难,就是反复执行抬笔,找到火柴的x,y坐标和落笔画火柴的代码。
3.主程序
主程序分为人类输入和电脑输入。我们想实现的功能是:人类或电脑输入一个数后,火柴剩余数量减去这个数,并显示出剩余sticks,同时海龟屏幕中抹去取走的火柴。对于实现让终端显示剩下火柴数这个功能,我们很容易就想到,就是让sticks每次在num和ro输入后自减num和ro,并在终端显示自减后的sticks。对于实现让海龟屏幕抹去取走的火柴的功能也不难,用draw_line()绘制白色线条来覆盖原来的彩色线条就好了嘛!我们这里要稍微注意,对于绘制白色线条的位置,我们要用累加位置,因为draw_line()中开始抹的火柴位置永远是第一个火柴的摆放位置。所以如果我们用num或ro的数量当draw_line()的循环数量nums,画笔永远会在前三个火柴的位置重复画白线。
4.奖励环节。
奖励环节就简单了,他在循环之外。因为如果人类输了,os._exit()就会停止执行程序内的所有代码,所以只有人类赢了才有机会到循环外面来获得奖励。存储礼物的列表的索引是 random.randint(0,len(gift)-1),即随机索引(范围是从0到该列表的最大索引)。
呵呵,我输了
抱歉各位,本人智商有限,可能暂时演示不了奖励环节的代码了,留给大家自行探索