本来这个程序是早就编完了的,一直没时间发布博客。时至今日已时隔多天,也算是复习一下事件驱动型编程的过程吧。

1 事件驱动型编程

本质上这次的作业是披着猜数字皮的图形化界面编程,好在 simplegui 比 MFC 简单多了,按照 Scott 老师给出的“七步模板”,就能编出来。那么什么叫事件驱动型编程呢?大概意思就是:给 frame 某种刺激(比如按下按钮,输入一个字符串),就会触发事件以执行相应的回调函数(event handler)。

以猜数字为例,“输入我猜的数字并按下 enter 键”这个动作就是“给 frame 一个刺激”,这叫事件(event);“将输入的数字 guess 与 secret number 比较看是大了小了还是等了”这个功能则由回调函数 input_guess(guess) 来完成。

通过给frame上某个元件一个刺激去激发回调函数这个过程就叫“事件驱动型编程(event-driven programming)”。

2 作业要求

这次迷你项目内容很简单,就是猜数字,但是是图形化界面的猜数字。因此在这个要求下,我们是借猜数字这个题,来熟悉如何搭建一个对话框,并且在这个对话框上能够完成点击按钮、输入内容这两个操作,并且在处理事件后返还给用户一个处理结果,说白了就和我们现在在操作系统上所使用的对话框是一样的。

现在直接放一下我写的程序所弹出的对话框:

对着这个图,我们看一下本次作业的要求:

2-1 两种游戏模式

(1)搭建一个对话框,里面有两个按钮,分别代表“猜数字范围为0~1000”以及“猜数字范围为0~100”;

【implement】使用一个全局变量 last_time_range 来控制这一点,当选择模式一,则last_time_range == 100;如果选择模式二,则last_time_range == 1000。

(2)点击上述任意一个按钮,都会开始相应模式下的游戏,它们的区别在于两点:所需要猜测的数字范围不同,容错次数不同。

【implement】因此这两个按钮有一个公有的辅助函数new_game(number_range),把上述 last_time_range 作为参数传递进来,会产生一个给定范围内的随机数,该随机数即为 secret number。

2-2 自动开启下一轮游戏

(1)在本轮游戏结束后(猜测次数用完,或者正确猜到结果),将自动开启下一轮游戏;

【implement】本部分内容在 input_guess(guess) 函数中予以设定。

(2)自动开启下一轮游戏时,将仍然使用当前模式下的数字范围;

【implement】本部分内容在 input_guess(guess) 函数中予以设定。

(3)如果结束一轮游戏后想换一种范围试试,可以换另一个按钮点点看。

【implement】应注意,在点击这两个按钮中任意一个的时候,都是要将“剩余次数”复位的。比如我可以上一次游戏玩到一半,还有3次猜测次数时,忽然想重启一盘游戏玩玩,如果这个时候点击了上面两个按钮之一,则需要把剩余次数也归为7或者10。

2-3 猜测数字

(1)通过输入框输入所猜的数字,按下 enter 键来将输入的数字传入程序进行判断。这里应该增加异常处理,比方说如果输入的不是数字怎么办?输入的数字范围不对怎么办?

【implement】本部分内容在 input_guess(guess) 函数中予以设定。

(2)对于猜数字次数是有所限制的,对第一种模式,次数为7次;第二种模式,次数为10次;

【implement】分别在这两个按钮的回调函数中予以设定,所使用到的全局变量为 allowed_guesses 和 last_time_allowed_guess 。前者为一个不断变动的量,每次猜错都会减一,而后者为一个固定值,用于存储当前模式下所对应的可猜测次数,比如模式一下会固定 last_time_allowed_guess == 7,模式二下会固定 last_time_allowed_guess == 10,保存这两个值的意义在于:在一轮游戏结束后,需要以当前模式开启下一轮游戏,因此我们需要知道当前模式下到底能猜几次?而显然,之前那个 allowed_gusses 现在已经变动了,故我们还需要再设定一个全局变量专门用来存放可猜测次数,且不许变动。

(3)对于待猜测数字 secret number 并非由人设定,而是利用计算机随机数发生器来产生。

3 代码清单

 import SimpleGUICS2Pygame.simpleguics2pygame as simplegui
import random ### global variable ###
secret_number = -1 # 被猜测数
allowed_guesses = -1 #允许次数
last_time_range = -1 #当前所选范围
last_time_allowed_guess = -1 # 保存当前局允许次数 ### helper function ###
def new_game(number_range):
random_number=random.randrange(0,number_range,1)
return random_number def compare_number(input_number):
global secret_number
global allowed_guesses
if (secret_number > input_number):
result = "Higher!"
allowed_guesses -= 1
elif (secret_number < input_number):
result = "Lower!"
allowed_guesses -= 1
else:
result = "Correct!"
return result ### event handler ###
def choice_100():
global last_time_range
global secret_number
global allowed_guesses
global last_time_allowed_guess
last_time_range = 100
secret_number = new_game(100)
print "The secret number has been set! (range: 0~100) "
allowed_guesses = 7
last_time_allowed_guess = 7 def choice_1000():
global last_time_range
global secret_number
global allowed_guesses
global last_time_allowed_guess
last_time_range = 1000
secret_number = new_game(1000)
print "The secret number has been set! (range: 0~1000) "
allowed_guesses = 10
last_time_allowed_guess = 10 def input_guess(guess):
global last_time_range
global secret_number
global allowed_guesses
global last_time_allowed_guess
if (secret_number==-1): # 初次进入游戏时,应检测是否选择范围
print "The secret number hasn't been set, please choose a button to set the secret number."
elif (guess.isdigit() == False): # 检测输入是否为数字
print "Please input a valid number!"
elif ((int(guess)<0) or (int(guess)>=last_time_range)): # 检测是否输入的是有效范围内的数字
print "Please input a number in the correct range!"
else:
input_number = int(guess)
result = compare_number(input_number)
if (result=="Correct!"):
print "The number you guess is: " + guess + ", " + result + "\n\n" + "You win! A new game in the same range is start..."
secret_number = new_game(last_time_range) # 以当前范围为下一局游戏范围
elif (allowed_guesses != 0):
print "The number you guess is: " + guess + ", " + result + "\n" + str(allowed_guesses) + " chances left."
else:
print "The number you guess is: " + guess + ", " + result + "\n\n" + "You lost. A new game in the same range is start..."
allowed_guesses = last_time_allowed_guess
secret_number = new_game(last_time_range) # 以当前范围为下一局游戏范围 ### create a frame ###
frame = simplegui.create_frame("Guess the number!",200,200) ### register event handlers ###
frame.add_button("Range is 0~100", choice_100, width=200)
frame.add_button("Range is 0~1000", choice_1000, width=200)
frame.add_input("Enter a guess", input_guess, width=200) ### start frame ###
frame.start()

4 代码测试

4-1 常规测试(失败情况下)

本次选择range为0~100,也就是共有7次猜测机会,测试结果如下:

[evaluate IIPP2.py]
The secret number has been set! (range: 0~100) 
The number you guess is: 13, Higher!
6 chances left.
The number you guess is: 40, Lower!
5 chances left.
The number you guess is: 23, Higher!
4 chances left.
The number you guess is: 33, Lower!
3 chances left.
The number you guess is: 30, Lower!
2 chances left.
The number you guess is: 28, Lower!
1 chances left.
The number you guess is: 26, Lower! You lost. A new game in the same range is start...

4-2 常规测试(成功情况下)

本次选择range为0~100,也就是共有7次猜测机会,测试结果如下:

[evaluate IIPP2.py]
The secret number has been set! (range: 0~100)
The number you guess is: 30, Higher!
6 chances left.
The number you guess is: 40, Higher!
5 chances left.
The number you guess is: 50, Lower!
4 chances left.
The number you guess is: 45, Lower!
3 chances left.
The number you guess is: 43, Correct! You win! A new game in the same range is start...

4-3 异常处理测试

在这种情况下,我要试验如果输入数字超出了给定范围将会如何,假如我选了0~100范围,却输入了300,将得到这样的结果:

[evaluate IIPP2.py]
The secret number has been set! (range: 0~100)
Please input a number in the correct range!

或者说假如第一轮游戏的时候,我没有选择任何范围就直接输入数字了(可以发现这次没出现第一行的“The secret number has been set! (range: 0~*) ”字样):

[evaluate IIPP2.py]
The secret number hasn't been set, please choose a button to set the secret number.

说明程序对于这样的错误操作情况也能予以较好的应对。

2016.6.29

by 悠望南山

IIPP迷你项目(二)"Guess the Number!"的更多相关文章

  1. IIPP迷你项目(一)“Rock-paper-scissor-lizard-Spock”

    0 前言——关于IIPP 本系列博客的内容均来自<An Introduction to Interactive Programming in Python (Part 1)>(在此我简称为 ...

  2. IIPP迷你项目(三)“Stopwatch: The Game”

    0 本周项目说明 这一次博客是Coursera的IIPP课程第三周迷你项目的实现,基础要求是做一个秒表,能start能stop能reset,更高的要求是在此秒表的基础上完成两个小游戏,但是鉴于第二个小 ...

  3. IIPP迷你项目(四)"Pong"

    1 小球在墙面的反弹 1-1 让小球在画布上匀速运动 在这一步中,首先应该明确小球是如何匀速运动的.它的方法是规定一个列表v,Scott老师说这代表着“速度(Velocity)”,但是我觉得也可以拿“ ...

  4. Eclipse+Maven创建webapp项目<二> (转)

    Eclipse+Maven创建webapp项目<二> 1.开启eclipse,右键new——>other,如下图找到maven project 2.选择maven project,显 ...

  5. Vue小项目二手书商城:(四)详情页和购物车(emit、prop、computed)

    实现效果: 点击对应商品,对应的商品详情页出现,详情页里面还有“Add to cart”按钮和“×”退出按钮. 点击“Add to cart”可以将商品加入购物车,每件商品只能添加一次,如果把购物车的 ...

  6. Vue小项目二手书商城:(三)前端渲染数据

    实现内容: axios取到的数据在前端使用(父子组件各自应该怎么使用) 一.简单使用(在哪取在哪用) 1.在App.vue中script中加上data(data专属于当前组件,父子组件传参通过prop ...

  7. Vue小项目二手书商城:(二)axios前后端数据交互

    实现内容: 写路由接口(express) axios取数据 一.写接口 1.我们要在前端取到后端的数据(之前写的data.json)可以用vue-resourse或者用axios,在vue2之后官方就 ...

  8. Vue小项目二手书商城:(一)准备工作、组件和路由

    本项目基于vue2.5.2,与低版本部分不同之处会在(五)参考资料中提出 完整程序:https://github.com/M-M-Monica/bukesi 实现内容: 资源准备(mock数据) 组件 ...

  9. Eclipse+Maven创建webapp项目<二>

    Eclipse+Maven创建webapp项目<二> 1.开启eclipse,右键new——>other,如下图找到maven project 2.选择maven project,显 ...

随机推荐

  1. B9:备忘录模式 Memento

    在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可以将该对象恢复到原先保存的状态 UML: 示例代码: class Role { private $hp; pri ...

  2. 我对GFWed的一些自己的见解

    首先来听听维基百科对GFWed的说明 防火长城(英语:Great Firewall of China.经常使用简称:GFW,中文也称中国国家防火墙或防火长城[1],中国大陆民众俗称防火墙[2].功夫网 ...

  3. [性能测试] LoadRunner结果分析 – TPS(转)

    [性能测试] LoadRunner结果分析 – TPS 针对吞吐率和 TPS 的关系,这个在结果分析中如何使用,就个人经验和朋友讨论后,提出如下建议指导,欢迎同僚指正. 相关定义 响应时间 = 网络响 ...

  4. svn命令行版本回滚

    下面以版本号2011回滚到2010为例,在命令行输入: svn merge --dry-run -r 2011:2010 http://my.repository.com/my/project/tru ...

  5. Spring 集成hibernate时配置连接释放模式

    http://zmfkplj.iteye.com/blog/220822 程序出现一个奇怪的现象,用Quartz作业调度启动任务,运行一段时间后,任务会卡在一个查询接口处,久久不能运行完毕. 我本能的 ...

  6. Mysql纯命令行添加用户及权限

    原文链接:http://hi.baidu.com/ngy1991/item/45978bd05d82c7ea785daa42 创建用户: 命令: 1 CREATE USER 'username'@'h ...

  7. Pushlet后台推送

    1.Pushlet 是一个开源的 Comet 框架,Pushlet 使用了观察者模型:客户端发送请求,订阅感兴趣的事件:服务器端为每个客户端分配一个会话 ID 作为标记,事件源会把新产生的事件以多播的 ...

  8. unity, 自定义类中使用print

    在unity脚本中自定义c#类,而且不继承MonoBehaviour的话,若还想在其中使用print函数,可以用MonoBehaviour.print(...).

  9. 关于angularjs在IE里的坑——F12工具打开,功能正常,关闭之后,angularjs not working

    前端时间在做项目的时候,用到了angularjs,期间,发现了一个奇葩的问题,就是在IE11浏览器下,点击下方图1上箭头所示的位置,将此处的开关变为图2中箭头所示的样子,但是发觉没有反应,开关还是灰色 ...

  10. CentOS sendmail安装及邮件域名配置

    http://www.centoscn.com/CentosServer/lighttpd/2013/0726/650.html sendmail是Linux下优秀的邮件系统.在不做任何设定的情况下, ...