第六周作业
一、理论学习
1、完成慕课第十一章的学习。

2、学习UML以及其它软件建模方法。学习链接:
https://zhuanlan.zhihu.com/p/88324971
https://blog.csdn.net/fwj380891124/article/details/8349736
https://blog.csdn.net/u012195214/article/details/79979169
https://www.jianshu.com/p/4c9f795da7ea
3、学习体会:
(1)通过用户故事进行用例建模可以准确地给出开发过程中的功能性需求,在开发过程中,根据用例模型可以明确知道需要完成什么样的功能,从而一步步对其进行开发。
(2)面向对象分析设计可以通过类和对象来实现,类是抽象的,对象是具体的,通过类的实例化可以给对象赋予相关属性和行为。面向对象设计能够使系统更加容易维护和扩展。
(3)UML与其它软件建模方法优劣比较:
结构化建模方法,常用数据流图等进行表述,它从系统整体出发,一步一步地进行分析设计,阶段性强,适用于结构性强的大规模软件开发,但开发周期较长。原型法开发周期短,有用户参与,开发出来的系统更符合要求,但不适用于大规模软件开发。UML是一种面向对象的软件系统建模方法,独立于任何程序设计语言,适用于静态结构和动态行为,适用于并行、分布式系统,且可用于软件开发不同阶段,方便后期系统测试和维护,通用性强,但不太适用于大型软件的整体建模。UML主要采用用例图、序列图、状态图等可视化图形来对软件开发过程进行建模,具有一定的规范性,能够直观地进行理解和阅读。
二、实践学习(成员:曹宇轩,刘昕昕)
1、小组主要采用VISIO软件下的UML模板进行建模,主要有出口成诗、点字成诗两种模式,选择完模式之后系统会自动生成相应的题目,对于出口成诗环节,用户需要点击题目进行选择从而进一步回答,而点字成诗不用选择题目,按顺序进行回答即可,完成所有回答或超时后系统会自动给出回答情况和得分情况,整个用例模型如下:

2、项目计划

3、实践环节(本周刘昕昕负责编写出口成诗功能和修改点字成诗干扰函数;曹宇轩负责编写出口成诗测试代码,进行独立的GUI代码编写尝试)
(1)出口成诗基本功能,见https://github.com/lxxlccly/rjgc4下的ckcs.py文件。首先在诗句中挑选了合适的词生成题目文件,见/poet/question.txt,每次运行程序时,从该文件中读取题目,并随机挑选其中12个词(不重复)作为本次游戏题目,并从tssbs.json文件中读取诗句库,程序如下:
def get_question(self):
'''获得题目'''
all_question = []
with open('./poet/question.txt', encoding="utf-8") as f:
for row in f:
word = row.replace('\n', '').replace('\r', '')
all_question.append(word)
while 1:
random_poet = random.randint(0, len(all_question) - 1)
if all_question[random_poet] not in self.questions:
self.questions.append(all_question[random_poet])
if len(self.questions) == self.question_amount:
break
def get_poet_library(self):
'''诗词库'''
address = './poet/tssbs.json'
with open(address, 'r', encoding='utf-8') as load_f:
self.all_poet = json.load(load_f)
(2)开始游戏并计时,首先在屏幕上显示题目和题目编号,输入编号选择题目进行回答,回答完成后系统根据诗词库自动验证回答是否正确,若回答正确,则此题目不再显示,若回答错误则该题能够再次进行选择和回答,若超时或完成所有回答,系统跳入下一环节。程序如下:
def start(self):
'''开始游戏'''
self.get_question()
self.get_poet_library()
a_threading = time_limit.MyThread(target=self.cycle)
a_threading.start()
a_threading.join()
@time_limit.limit_decor(LIMIT_TIME) # 超时设置(s)
def cycle(self):
answer_unfinished = 1
while answer_unfinished:
for i in range(self.question_amount):
if self.unanswered[i] == 1:
if (i + 1) % 4 == 0:
print('{0:>2}、{1}'.format(i + 1, self.questions[i]))
else:
print('{0:>2}、{1}'.format(i + 1, self.questions[i]), end=' ')
print('请输入编号选择问题')
number = input()
print('请回答:')
answer = input()
re_answer = re.findall(r'[\u4E00-\u9FA5]+', answer)
for i in range(len(self.all_poet)):
for j in range(len(self.all_poet[i]['paragraphs'])):
if self.all_poet[i]['chapter'].find(self.questions[int(number) - 1]) != -1 \
or self.all_poet[i]['paragraphs'][j].find(self.questions[int(number) - 1]) != -1:
sentence = re.findall(r'[\u4E00-\u9FA5]+', self.all_poet[i]['paragraphs'][j])
if re_answer == sentence:
self.answers[int(number) - 1] = answer
self.unanswered[int(number) - 1] = 0
if self.unanswered[int(number) - 1] == 0:
print('回答正确')
else:
print('回答错误')
if self.unanswered == [0] * self.question_amount:
answer_unfinished = 0
return 1
运行结果如下:

(3)给出本次游戏的所有回答情况和最终的得分,程序如下:
def print_grade(self):
'''打印成绩'''
print('总结:')
right_amounts = 0
for i in range(self.question_amount):
if self.answers[i] != '':
print('{0:>2}、回答正确。您的回答为:{1}'.format(i + 1, self.answers[i]))
right_amounts += 1
else:
print('{0:>2}、回答错误/未回答。'.format(i + 1))
self.grade = right_amounts / self.question_amount * 100
print('您的总得分为:%.1f分' % self.grade)
运行结果如下:

(4)进行了代码规范性检查和修改。

(5)编写测试代码,见https://github.com/lxxlccly/rjgc4下的test_ckcs.py文件。
编写思路:
1)在循环过程中,模拟每一次的输入,验证最终结果是否与预期相符
2)验证从题目库里获取的题目是否与设定值相同,设定获取前十二个题目。
3)验证从诗词库获取到的诗词是否与设定的相符,通过首尾两首诗词进行验证。
4)验证打印出的回答情况和得分是否与设定的相符。
程序如下:
@mock.patch('builtins.input', new=mock.Mock(
side_effect=chain(['1', '寥落古行宫,宫花寂寞红。', '2', '白头宫女在,閒坐说玄宗。',
'3', '白头宫女在,閒坐说玄宗。', '4', '白日依山尽,黄河入海流。',
'5', '白日依山尽,黄河入海流。', '6', '三日入厨下,洗手作羹汤。',
'7', '愿君多采撷,此物最相思。', '8', '红豆生南国,春来发几枝。',
'9', '君自故乡来,应知故乡事。', '10', '来日绮窗前,寒梅着花未?',
'11', '返景入深林,复照青苔上。', '12', '返景入深林,复照青苔上。'])))
def test_cycle(self):
self.poet_game.questions = ["行宫", "宫女", "玄宗", "白日", "黄河", "洗手",
"相思", "红豆", "故乡", "寒梅", "深林", "青苔"]
address = './poet/tssbs.json'
with open(address, 'r', encoding='utf-8') as load_f:
self.poet_game.all_poet = json.load(load_f)
self.poet_game.cycle()
self.assertEqual('寥落古行宫,宫花寂寞红。', self.poet_game.answers[0])
self.assertEqual('白头宫女在,閒坐说玄宗。', self.poet_game.answers[1])
self.assertEqual('白头宫女在,閒坐说玄宗。', self.poet_game.answers[2])
self.assertEqual('白日依山尽,黄河入海流。', self.poet_game.answers[3])
self.assertEqual('白日依山尽,黄河入海流。', self.poet_game.answers[4])
self.assertEqual('三日入厨下,洗手作羹汤。', self.poet_game.answers[5])
self.assertEqual('愿君多采撷,此物最相思。', self.poet_game.answers[6])
self.assertEqual('红豆生南国,春来发几枝。', self.poet_game.answers[7])
self.assertEqual('君自故乡来,应知故乡事。', self.poet_game.answers[8])
self.assertEqual('来日绮窗前,寒梅着花未?', self.poet_game.answers[9])
self.assertEqual('返景入深林,复照青苔上。', self.poet_game.answers[10])
self.assertEqual('返景入深林,复照青苔上。', self.poet_game.answers[11])
@mock.patch('random.randint', new=mock.Mock(side_effect=chain([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])))
def test_get_question(self):
self.poet_game.get_question()
self.assertEqual("行宫", self.poet_game.questions[0])
self.assertEqual("宫女", self.poet_game.questions[1])
self.assertEqual("玄宗", self.poet_game.questions[2])
self.assertEqual("白日", self.poet_game.questions[3])
self.assertEqual("黄河", self.poet_game.questions[4])
self.assertEqual("洗手", self.poet_game.questions[5])
self.assertEqual("相思", self.poet_game.questions[6])
self.assertEqual("红豆", self.poet_game.questions[7])
self.assertEqual("故乡", self.poet_game.questions[8])
self.assertEqual("寒梅", self.poet_game.questions[9])
self.assertEqual("深林", self.poet_game.questions[10])
self.assertEqual("青苔", self.poet_game.questions[11])
def test_get_poet_library(self):
self.poet_game.get_poet_library()
self.assertEqual("行宫", self.poet_game.all_poet[0]["chapter"])
self.assertEqual(["寥落古行宫,宫花寂寞红。", "白头宫女在,閒坐说玄宗。"],
self.poet_game.all_poet[0]["paragraphs"])
self.assertEqual("塞下曲·野幕敞琼筵", self.poet_game.all_poet[len(self.poet_game.all_poet) - 1]["chapter"])
self.assertEqual(["野幕敞琼筵,羌戎贺劳旋。", "醉和金甲舞,雷鼓动山川。"],
self.poet_game.all_poet[len(self.poet_game.all_poet) - 1]["paragraphs"])
def test_print_grade(self):
'''print_grade的测试函数'''
self.poet_game.answers = ['一二三四五六七', '', '', '', '', '', '', '', '', '', '', '']
with mock.patch('builtins.print') as mock1:
self.poet_game.print_grade()
mock1.assert_has_calls([
mock.call('总结:'),
mock.call(' 1、回答正确。您的回答为:一二三四五六七'),
mock.call(' 2、回答错误/未回答。'),
mock.call(' 3、回答错误/未回答。'),
mock.call(' 4、回答错误/未回答。'),
mock.call(' 5、回答错误/未回答。'),
mock.call(' 6、回答错误/未回答。'),
mock.call(' 7、回答错误/未回答。'),
mock.call(' 8、回答错误/未回答。'),
mock.call(' 9、回答错误/未回答。'),
mock.call('10、回答错误/未回答。'),
mock.call('11、回答错误/未回答。'),
mock.call('12、回答错误/未回答。'),
mock.call('您的总得分为:8.3分')
])
运行通过:

(6)修改点字成诗环节的干扰函数,从另一首诗里选出干扰字,干扰字不能凑成一句诗,且干扰字不与正确答案里面的字重复,代码如下:
def get_disturb(self, number, len_question):
'''获得对诗句进行干扰的汉字
#随机汉字
i = 0
while i < len_disturb:
head = random.randint(0xb0, 0xf7)
body = random.randint(0xa1, 0xfe)
val = f'{head:x} {body:x}'
word = bytes.fromhex(val).decode('gb2312', errors='ignore') #或者用decode('gbk')
self.questions[number].append(word)
i += 1
'''
len_disturb = 12 - len_question
while 1:
random_poet = random.randint(0, len(self.all_poet) - 1)
if random_poet not in self.poet_number:
sentence_amount = len(self.all_poet[random_poet]['paragraphs'])
if sentence_amount != 0:
random_sentence = random.randint(0, sentence_amount - 1)
sentences = re.findall(r'[\u4E00-\u9FA5]+', self.all_poet[random_poet]['paragraphs'][random_sentence])
i = 0
while len_disturb > 4:
if sentences[0][i] not in self.questions[number]:
self.questions[number].append(sentences[0][i])
len_disturb -= 1
i += 1
i = 0
while len_disturb > 0:
if sentences[1][i] not in self.questions[number]:
self.questions[number].append(sentences[1][i])
len_disturb -= 1
i += 1
break
(7)学习python中Tkinter模块,尝试编辑一个带有图片的界面,并对文字颜色和字体,和界面大小进行简单的编辑,见gui.py文件,运行结果如下:

总结:
1)每次代码规范性检查的时候,都会提醒类实例化的对象名称要全部大写,但我看大部分情况大家都是用的小写,有点迷。
2)编写某些函数的测试代码时不知从何下手,比较困难,部分函数的测试功能不是很完美。
3)目前进行了一些调试,许多bug以及修复,但部分功能可能还存在未知的bug,也存在许多可以进行优化的地方,待做完界面之后再进行整体调试和优化。
三、学习记录
| 学习时间 | 学习内容 |
| 3.24 13:00-15:00 | 慕课第十一章 |
| 3.24 15:00-17:30 | UML及其它建模方法 |
| 3.25 14:00-18:00 | 编写出口成诗游戏的基本功能程序 |
| 3.26 9:00-10:30 | 对回答及验证功能进行修改 |
| 3.28 9:00-10:20 | 修改点字成诗干扰函数 |

浙公网安备 33010602011771号