第四次实验报告
程序语言: python
姓名: flyunicorninsky
学号: 12345678910
日期:2023/5/6
一、 问题重述
随机点名程序(越不来上课的人,被点中的概率越高,实现抽查问题、预警等功能)
二、 问题分析
这个代码以随机函数和文件处理为重点。越不来上课的人被点中概率越高想到在每次缺勤后对缺勤同学增加一定的权重,而点名的时候权重越高,点到的几率就越高。预警功能通过打印缺勤次数较多的同学名单来实现。还有就是可视化实现和交互。可视化就是点的名字的可视化,这个虽然在python的屏幕上也可以实现但是为了配合和鼠标的交互,便利点名的老师。我查找资料,使用了python库中的tkinter来实现可视化与交互。
三、 伪代码
选取随机同学的函数伪代码如下:
begin():
bad = 0
sum = 0
if len(unsign) == 0 then
print("已全部点名")
close() #跳转到结束函数
return
for i <- 0 to len(unsign)):
if unsign[i][1] == 0 then
bad <- i
break
else
sum += unsign[i][1]
a <- random.randint(1, 999)
if bad != 0 then
if a % 3 == 0 then
lucky_dog <- random.randint(bad, len(unsign)-1)
else:
a <- random.randint(0, sum - 1)
for i in range(0, len(unsign)):
a -= unsign[i][1]
if a < 0:
lucky_dog <- i
break
else:
lucky_dog <- random.randint(0, len(unsign) - 1)
首先就是判断有无人缺勤过,如果没有直接按照等可能性来选择抽到的同学,如果有就使用另一种方法。这种方法就是先生成一个随机数,判断是否被三整除,被三整除即有三分之一的可能性抽查没缺勤过的同学,其他的就是三分之二的可能性抽查缺勤过的同学。没缺勤过的同学直接在其中使用等可能选取一位,缺勤过的同学则是按照缺勤次数的权重来决定可能性。
四、代码
代码如下:
import math
import random
from tkinter import *
from tkinter import font
# 创建窗口
win = Tk()
myfont = font.Font(size=20)
lucky_dog = 0 # 幸运儿
src_path = 'C:\\Users\\Lenovo\\Desktop\\names.txt'
def begin():
global lucky_dog, content, bad, sum, unsign
bad = 0
sum = 0
if len(unsign) == 0:
print("已全部点名")
close()
return
for i in range(0, len(unsign)):
if unsign[i][1] == 0:
bad = i
break
else:
sum += unsign[i][1]
a = random.randint(1, 999)
if bad != 0: # 还没人缺勤过,所有人等可能
if a % 3 == 0: # 1/3的概率是以前没缺勤过的
lucky_dog = random.randint(bad, len(unsign)-1)
else: # 2/3的概率是以前缺勤过的
a = random.randint(0, sum - 1)
for i in range(0, len(unsign)):
a -= unsign[i][1]
if a < 0:
lucky_dog = i
break
else:
lucky_dog = random.randint(0, len(unsign) - 1)
Label(text=unsign[lucky_dog][0], font=myfont).place(x=150, y=80)
Button(text='结束点名', command=close).place(x=100, y=180, width=190)
Button(text='出勤', command=yes).place(x=50, y=150, width=100)
Button(text='未到', command=no).place(x=200, y=150, width=100)
def close():
n = len(content)
for i in range(n):
for j in range(0, n - i - 1):
if content[j][1] < content[j + 1][1]:
content[j], content[j + 1] = content[j + 1], content[j]
print("以下同学多次缺勤:")
for i in range(n):
if(content[i][1]>2):
print(content[i][0]+"已经缺勤"+str(content[i][1])+"次")
with open(src_path, 'w', encoding='utf-8') as file2:
for i in range(0, len(content)):
file2.write(content[i][0] + " " + str(content[i][1]) + '\n')
win.destroy()
def yes():
unsign.remove(unsign[lucky_dog])
begin()
def no():
for i in range(0, len(content)):
if content[i][0]==unsign[lucky_dog][0]:
content[i][1] += 1
break
unsign.remove(unsign[lucky_dog])
begin()
with open(src_path, encoding='utf-8') as file:
content = file.readlines()
if(len(content)==0):
print("文本空白!")
for i in range(0, len(content)):
content[i] = content[i].split(" ")
content[i][1] = int(content[i][1])
unsign = content.copy()
# 设置窗口标题
win.title('点名程序')
# 设置窗口宽度和高度
win.geometry('350x220')
Button(text='开始点名', command=begin).place(x=100, y=180, width=190)
win.mainloop()
file.close()
五、 实验结果
输出大概如图(以下所有名字皆为实验测试需要随机生成名字,与现实无关)
运行程序后会出现:
点击“开始点名”:
此时点击“出勤”或者“未到”都会自动记录结果并转到下一个随机同学:
当想要结束点名时可以点击“结束点名”主动结束点名,或者是等到所有同学都点过一次名之后自动结束。
结束时会有“已全部点名”提示。并且打印出缺勤超过三次的同学名字以及其缺勤次数起到警示作用。
六、 遇到的一些问题
一开始是想用网页实现,但是JS不太会,想到使用Java来写,因为他有便捷的交互页面,但是Java一直莫名其妙出现一些中文的乱码,尝试了一下解决不了,最后还是使用我大实验的老朋友python。
其实遇到了很多问题,因为这个代码说实话没有什么真正难的地方,主要都是一些不熟悉的地方和一些粗心的点。这里我就只挑几个讲一下。
有两个循环忘记range,单单就(0,len(content))结果就变成一个元组,就相当于只有两个元素,于是一直报超限的错误,debug了好一会。
没有考虑到同学点到一次就不点,缺勤率高的人一直出现在一次点名里,然后几率变更高,最后就一直出现。相当于一个同学在一堂课上会被点到多次,这显然是不合理的。
为了解决上面的问题我新建了一个unsign列表来表示未点到名的同学。我用unsign=content来表示。但是后面也是一直报错,后来才发现这样的数组相当于只是原数组换了一个名字而已,最后使用unsign=content.copy()才解决这个问题。
七、 总结
基本实现了题目所要求的功能,可交互界面也使得对于老师等更加友善。可实现对本次课堂的缺勤数据的保存。
交互界面做得有些粗糙,可以再进一步地完善美化界面;还可以完善一下缺勤次数权重的概率问题。
本次实验更加了解了计算机中随机数的原理。学习了python中tkinter的一些操作。扩大了可视化领域的知识。扩展了思维,实现了将知识应用于实际。
做得很仓促,但是实现的效果还可以(得意)