编程过程分享1「欢迎萌新入坑」:Python:做一个上海计算机二级答题系统的过程

发布于:2022-10-18 ⋅ 阅读:(639) ⋅ 点赞:(0)

目录

准备工作:

选择题:

选择题主代码:

其他题:

其他代码:

接下来参观一下副程序:

计算机二级是大学计算机专业必过的一科老师的资料大礼包也不会缺席。你有没有这样的经历:当自信满满的打开复习资料准备做时,看到的却是这样的场景:

 

怎么做?傻眼了吧。
别急,上有政策下有对策,既然老师大发慈悲地给我们试卷,我们就为它量身定做一套答题系统。

准备工作:


首先,我们把四种题型分别存一个txt文件,因为是19年B场,所以我给他记成19b加上标识字:
19bx.txt 选择题:x
19bt.txt 填空题:t
19bc.txt 调试题:c
19bb.txt 编程题:b
为了方便编程,可以提前调整一下格式,比如我个人喜欢一个题后加上一个空行,把答案放在每道题开头(后面可以加上解析)。
像这样子:

然后因为有些题编程结果以图片展示,为了储存图片,我又加了个目录,截好图按序号标好:

 

再次,因为pygame标准字库打不出中文,我又加了几个字库,马不实在在网上下普惠体免得扯上版权问题,随便改了个名字:

 

好了,准备工作做好了,万事俱备只欠东风,准备工作做得再好,也得有不错的程序内容撑腰。下面,就有请大家欣赏我写的程序(英语没学好,很多名字乱取的,请大家多多包涵哈)。

程序部分:


话不多说,上手导入库、全局变量和函数。

import pygame
import random
import time
import threading

#窗口大小:
DA=(550,700)
#窗口颜色:
tse=(random.randint(220,255),random.randint(220,255),random.randint(220,255))
#字体:
ZD=20
#打印字上限:
KI=25
KIA=KI+1
YV=1.3
#时间/分:
TM=120
#分数:
f=0
#反馈记录:
ch=open("ylu.txt",'a+',encoding="utf-8")

def tsa():# 随机生成一种字体颜色
    a=[0,50,100]
    random.shuffle(a)
    return (random.randint(a[0],50+a[0]),random.randint(a[1],50+a[1]),random.randint(a[2],50+a[2]))
def xi(l1,l2):#洗:用于将2列表对应打乱
    xi= random.randint(0, 1001)
    random.seed(xi)
    random.shuffle(l1)
    random.seed(xi)
    random.shuffle(l2)
def Ja(l):#加一个序号列表
    l0=[]
    for i in range(len(l)):
        l0.append(i)
    return l0
def p(u,a) :# 选择题判断
    if u in [ord(a)-65,ord(a)-97,ord(a)-49]:
        return True
    else :
        return False

由于这些东西都是编程过程中一个个加的,不太好细讲,就先留个印象吧。
其次是一个pygame必备的一段代码(当然每个人用的函数可能有差异):

def Q():
    pygame.init()
    global scr
    scr=pygame.display.set_mode(DA)
    scr.fill(tse)
    pygame.display.flip()
    clk=pygame.time.Clock()
    while True :
        clk.tick(5)
        for event in pygame.event.get() :
            if event.type==pygame.QUIT :
                pygame.quit()
                exit()

看完基础部分,就让我带你们看看程序中的第一个重点部分:选择题。

选择题:

选择题类:
首先,我们要定义一个选择题的类。大家可以思考一下一道选择题有哪些组成部分呢?
答案很简单,一道选择题无非就题干、选项、答案三类。
作为一个人,我们可以一眼看出选择题的题干、选项、答案。但计算机不一样,计算机很笨,它看不出题干、选项、答案,需要我们告诉它。下图可见,前面几行是题干,中间几行是选项,后面又标明了答案和“解析”。

 

那么题干、选项、答案各多少行呢?
题干:任意行  选项:4行  答案:1行(仅开头)
那问题又来了,既然题干任意行,你怎么知道选项哪几行,答案哪行呢?
你可能会忽略一点:选项答案行数是固定的,那我们可以倒过来,[:-5]题干,[-5:-1]选项,[-1]答案解析。
但是为了为之后随机做铺垫,我们可以把题干、选项的序号去掉。
至于找出答案,我们可以用split函数给答案解析行分开,第一项为答案。
在类中,我又定义了一个方法,是为判断选项用的。
代码如下:

class Xua():
    def __init__(self,s):
        s[0]=s[0][2:]
        self.t=s[:-5]#'\n'.join()
        self.x=s[-5:-1]
        for i in range(len(self.x)):
            self.x[i]=self.x[i][2:]
        self.db=s[-1].split()
        self.d=self.db[0]
    def y(self,u):
        a=input("答案:")
        b=ord(self.d)-65
        return u.index(b),a

选择题主代码:


首先,我们需要询问输入的试卷名。你可能会问,这段代码写在最前面不是更好吗?
其实从编程语法的角度来说,确实可以写在最前面。但由于我用的了threading库的多线程,Q1()和Q()代码的运行顺序是随机的,如果先问了,有可能Q()窗体还没建好,Q1()直接用了,那样就只好挨Error红码一顿训了。
但好在人的手速和机速肯定没法比,只要Q1()当头一问,就乖乖跑到Q()后面运行了,那就啥事也没有了。
试卷问完把对应的x.txt一读,就该把选择题列表l录入s(每题一组)。由于我一开始预设每题的分段依据为空行,那我们可以把s每行strip()一下,把l空行与空行之间的元素打包放进s里面。再把批量把s的每个元素都“哐当”一下封印成一个选择题类。为了防止背答案,直接题序搅成一锅粥。
然后就可以开始打印题干了。
需要注意的是,有些题干某行字数太多了,直接飚到窗口外看不见了。就像这样:

 

那怎么办呢?其实很简单,我们可以设一个打印字的上限KIA,打完自动换行,即每次打印从上一个位点(j(循环次序)*KIA)到下一个位点。
那下一个位点是什么呢?你可能会说:下一个位点肯定是(j+1)*KIA噻。那可不一定咯,万一这一段刚好中途到头,计算机一看,卧靠,(j+1)*KIA项啥都没有,那只能又找你闹去了。
所以你得判断段长>j*KIA安全了才用(j+1)*KIA,不然段长只得自当结尾了。

题干打出来,接下来又是一个有意思的问题:选项乱序。
你可能会问,刚才题目乱序不就避免背答案了,你选项再乱一次有何意义?那当然得有意义。试想一下,当你练过几遍题后一看,“以下各项... 选D!”你这个题练得有啥意义?你选项再乱一下虽然还是可以不自觉背答案,但你把题干答案一起背了还是总能学到点东西的。所以选项乱序还是有必要地!
那你选项是乱了,答案不会乱啊!我做了一个Ja()函数记选项原本的序号,把它贴在选项上洗一洗,之后选完在沿着Ja过的列表找答案顺序就好了:

 

打印选项和打印题干大同小异没啥好说的。至于问答案和判断正误其实本来也没啥好说的,但我为了追求输入多元化倒是给它加了点花:abcd,ABCD,1234有啥不可以的,反正就着方便来嘛。那问题来了,鬼知道a=A=1怎么算呢?ascii知道:

 

用ord可以将字符转数字,剩下功夫就是算了。在打印的时候,统一起见,全部转为大写字母:

 

将选择题的基本流程讲完,接下来就是发放福利的时候了。二话不说,代码走起:

Q1(): # 选择题
    global f
    global klt
    klt=input('请输入试卷(如19b):')
    l=open('%sx.txt'%klt,'r+',encoding="utf-8").readlines()
    ig=0# 一题起始位置
    fn=0# 分数
    s=[]
    '''把选择题录进列表s:'''
    for i in range(len(l)):
        l[i]=l[i].strip()
        if l[i]=='':
            s.append(l[ig:i])
            ig=i+1
    for i in range(len(s)):
        s[i]=Xua(s[i])
    random.shuffle(s)# 题 乱序
    '''做题循环:'''
    for i in range(len(s)):
        scr.fill(tse)
        i0=0#列位
        """打出题干"""
        for k in range(len(s[i].t)):
            for j in range(int(len(s[i].t[k])/KIA)+1):
                if len(s[i].t[k])>j*KIA :
                    ju=(j+1)*KIA
                else :
                    ju=len(s[i].t[k])
                if j==0 and k==0:
                    ik=str(i+1)+'.'
                else:
                    ik=' '
                scr.blit(pygame.font.Font("B.ttf",ZD).render("%s%s"%(ik,s[i].t[k][j*KIA:ju]),True,tsa()),(10,ZD*i0))
                i0+=1
        """选项乱序"""
        u=Ja(s[i].x)
        xi(s[i].x,u)
        i0+=2
        """打出选项"""
        for k in range(len(s[i].x)):
            asa=tsa()
            for j in range(int(len(s[i].x[k])/KI)+1) :
                if len(s[i].x[k])>j*KI :
                    ju=(j+1)*KI
                else :
                    ju=len(s[i].x[k])
                if j==0:
                    ik=chr(65+k)+'.'
                else :
                    ik=' '
                scr.blit(pygame.font.Font("B.ttf",ZD).render("%s%s"%(ik,s[i].x[k][j*KI :ju]),True,asa),(20,ZD*i0))
                i0+=1
            i0+=1
        print(i+1,end=".")
        """问答案"""
        try:
            pygame.display.flip()
            u0,a0=s[i].y(u)
            chr(u0)
            ord(a0)
        except:
            u0,a0=u.index(ord(s[i].d)-65),'0'
        """判断正误"""
        if p(u0,a0):
            fn+=1.5
            scr.blit(pygame.font.Font("g.ttf",ZD*2).render("正确(^v^)¥",True,(0,200,0)),(100,ZD*i0))
            pygame.display.flip()
            time.sleep(1)
        else:
            scr.blit(pygame.font.Font("g.ttf",ZD*2).render("错误/(UnU)\\",True,(200,0,0)),(100,ZD*i0))
            i0+=2
            a0=ord(a0)
            if a0<65:
                a0+=16
            elif a0>96:
                a0-=32
            scr.blit(pygame.font.Font("g.ttf",ZD).render("答案:%s,你选成%s"%(chr(u0+65),chr(a0)),True,asa),(20,ZD*i0))
            i0+=2
            for k in range(len(s[i].db)-1) :
                asa=tsa()
                scr.blit(pygame.font.Font("B.ttf",ZD).render("%s"%(s[i].db[k+1]),True,asa),(20,ZD*i0))
                i0+=1
            pygame.display.flip()
            input("ok?")
    '''统计分数:'''
    if fn%1==0:
        print("选择题得分:%d (满分:15)"%(fn))
    else:
        print("选择题得分:%d.%d (满分:15)"%(fn,fn*10%10))
    f+=fn

实现效果:

 

 

其他题:


其实选择题讲完,其他题也就讲了一大半了。无非修修补补走特色题型主义依法治题。
值得一提的是填空题的答案部分。填空题的答案有两个特点。一个是一道题多个空,甚至一个空有多个正确答案,有时候答案还有空格。
咋办呢?我们可以研究一下答案特征:

 

首先,我们得剥离出答案。每个空有n):分开,那我们就以“)”来split,前后各少取两位(注意把第0项删了),至于多答的,再split 个(“【”),删个】。因为用了split,后面判断用in来替“==”就行。
答中有空,我们可以注意到答案和解析之间两空,那答案解析split两空分割出答案就好。
就像这样:

 


后面两种题型没有标答怎么评判呢?
那换言之你知道调试编程怎么判?反正我不知道。那就用最弱智的办法:问呗。弄出来填满分,弄不出填0分,中间的自己判断。反正就一个自测没必要作假:

 

而图片就用pygame的标准操作加个行数就ok:

 

接下来,又是代码大大大礼包,你可能消化不了,但鉴于我精力有限,一时半会解释不完,那也就让你消化不良好了。


其他代码:


填空题类:

class Tan():
    def __init__(self,s):
        s[0]=s[0][2 :]
        yx=s.index("运行示例:")
        self.t=s[:yx]
        self.x=s[yx+1:-1]
        self.db=s[-1].split("  ")
        self.d=self.db[0].split(")")
        self.d=self.d[1:]
        for i in range(len(self.d)):
            for j in range(len(self.d[i])):
                if self.d[i][j]=='【':
                    self.d[i]=self.d[i][j+1:-1]
                    break
            self.d[i]=self.d[i].split("【")
            for j in range(len(self.d[i])):
                self.d[i][j]=self.d[i][j].strip("】")
    def y(self,u):
        a,b=[],[]
        for i in range(len(u)):
            a.append(input("%d.答案:"%(i+1)))
            if a[i] in u[i]:
                b.append(True)
            else:
                b.append(False)
        return b,a

填空题代码:

def Q2():# 填空题
    global f
    #klt=input('请输入试卷(如19b):')
    l=open('%st.txt'%klt,'r+',encoding="utf-8").readlines()
    ig=0
    fn=0
    s=[]
    for i in range(len(l)) :
        l[i]=l[i].strip()
        if l[i]=='' :
            s.append(l[ig :i])
            ig=i+1
    for i in range(len(s)) :
        s[i]=Tan(s[i])
    un=Ja(s)
    xi(s,un)
    for i in range(len(s)) :
        scr.fill(tse)
        i0=0
        for k in range(len(s[i].t)) :
            for j in range(int(len(s[i].t[k])/int(KIA*YV))+1) :
                if len(s[i].t[k])>int(j*KIA*YV) :
                    ju=int((j+1)*KIA*YV)
                else :
                    ju=len(s[i].t[k])
                if j==0 and k==0 :
                    ik=str(i+1)+'.'
                else :
                    ik=' '
                scr.blit(pygame.font.Font("B.ttf",int(ZD*0.8)).render("%s%s"%(ik,s[i].t[k][j*int(KIA*YV) :ju]),True,tsa()),(10,ZD*i0))
                i0+=0.8
        tu=pygame.image.load("./%s/t%d.png"%(klt,un[i]+1))
        tu=pygame.transform.scale(tu,(200,100))
        scr.blit(tu,(10,ZD*i0,200,50))
        i0+=4.5
        for k in range(len(s[i].x)) :
            asa=tsa()
            ik=str(k+1)+"_"*(3-len(str(k)))+'|'
            scr.blit(pygame.font.Font("M.ttf",int(ZD/5*3)).render("%s %s"%(ik,s[i].x[k]),True,asa),(20,ZD*i0))
            i0+=0.65
        pygame.display.flip()
        b0,a0=s[i].y(s[i].d)
        for k in range(len(b0)):
            scr.blit(pygame.font.Font("M.ttf",int(ZD*0.7)).render(str(k+1)+':'+a0[k],True,tsa()),(10,ZD*i0))
            if b0[k] :
                fn+=2.5
                scr.blit(pygame.font.Font("g.ttf",int(ZD*0.7)).render("正确(^v^)¥",True,(0,200,0)),(100,ZD*i0))
            else :
                scr.blit(pygame.font.Font("g.ttf",int(ZD*0.7)).render("错误(UnU)",True,(200,0,0)),(100,ZD*i0))
                scr.blit(pygame.font.Font("M.ttf",int(ZD*0.7)).render("答案:%s"%'/'.join(s[i].d[k]),True,tsa()),(200,ZD*i0))
            i0+=0.7
        for k in range(len(s[i].db)-1) :
            asa=tsa()
            scr.blit(pygame.font.Font("B.ttf",int(ZD*0.7)).render("%s"%(s[i].db[k+1]),True,asa),(20,ZD*i0))
            i0+=0.7
        pygame.display.flip()
        input("ok?")
    if fn%1==0 :
        print("填空题得分:%d (满分:20)"%(fn))
    else :
        print("填空题得分:%d.%d (满分:20)"%(fn,fn*10%10))
    f+=fn
    global qn
    qn=f

实现效果:

 

调试题类:

class Tiao():
    def __init__(self,s):
        s[0]=s[0][2 :]
        yx=s.index("运行示例:")
        self.t=s[:yx]
        self.x=s[yx+1:-1]

调试题代码:

def Q3():# 填空题
    global f
    #klt=input('请输入试卷(如19b):')
    l=open('%sc.txt'%klt,'r+',encoding="utf-8").readlines()
    ig=0
    fn=0
    s=[]
    for i in range(len(l)) :
        l[i]=l[i].strip()
        if l[i]=='' :
            s.append(l[ig :i])
            ig=i+1
    for i in range(len(s)) :
        s[i]=Tiao(s[i])
    un=Ja(s)
    xi(s,un)
    for i in range(len(s)) :
        scr.fill(tse)
        i0=0
        for k in range(len(s[i].t)) :
            for j in range(int(len(s[i].t[k])/int(KIA*YV))+1) :
                if len(s[i].t[k])>int(j*KIA*YV) :
                    ju=int((j+1)*KIA*YV)
                else :
                    ju=len(s[i].t[k])
                if j==0 and k==0 :
                    ik=str(i+1)+'.'
                else :
                    ik=' '
                scr.blit(pygame.font.Font("B.ttf",int(ZD*0.8)).render("%s%s"%(ik,s[i].t[k][j*int(KIA*YV) :ju]),True,tsa()),(10,ZD*i0))
                i0+=0.8
        tu=pygame.image.load("./%s/c%d.png"%(klt,un[i]+1))
        tu=pygame.transform.scale(tu,(200,100))
        scr.blit(tu,(10,ZD*i0,200,50))
        i0+=4.5
        for k in range(len(s[i].x)) :
            asa=tsa()
            ik=str(k+1)+"_"*(3-len(str(k)))+'|'
            scr.blit(pygame.font.Font("M.ttf",int(ZD/5*3)).render("%s %s"%(ik,s[i].x[k]),True,asa),(20,ZD*i0))
            i0+=0.65
        pygame.display.flip()
        ur=(int(un[i]/2)+3)*3
        cv=input("ok?本题估分(/%d分{' ':满)(3分/):"%(ur))
        try :
            fn+=float(cv)
        except :
            if cv==" " :
                fn+=ur
    print("调试题得分:%d (满分:30)"%(fn))
    f+=fn

实现效果:

 

编程题类:

class Bia():
    def __init__(self,s):
        s[0]=s[0][2 :]
        self.t=s

编程题代码:

def Q4():# 填空题
    global f
    #klt=input('请输入试卷(如19b):')
    l=open('%sb.txt'%klt,'r+',encoding="utf-8").readlines()
    ig=0
    fn=0
    s=[]
    for i in range(len(l)) :
        l[i]=l[i].strip()
        if l[i]=='' :
            s.append(l[ig :i])
            ig=i+1
    for i in range(len(s)) :
        s[i]=Bia(s[i])
    un=Ja(s)
    xi(s,un)
    for i in range(len(s)) :
        scr.fill(tse)
        i0=0
        for k in range(len(s[i].t)) :
            for j in range(int(len(s[i].t[k])/int(KIA*YV))+1) :
                if len(s[i].t[k])>int(j*KIA*YV) :
                    ju=int((j+1)*KIA*YV)
                else :
                    ju=len(s[i].t[k])
                if j==0 and k==0 :
                    ik=str(i+1)+'.'
                else :
                    ik=' '
                scr.blit(pygame.font.Font("B.ttf",int(ZD*0.8)).render("%s%s"%(ik,s[i].t[k][j*int(KIA*YV) :ju]),True,tsa()),(10,ZD*i0))
                i0+=0.8
        tu=pygame.image.load("./%s/b%d.png"%(klt,un[i]+1))
        scr.blit(tu,(10,ZD*i0,200,50))
        pygame.display.flip()
        ur=(int(un[i]/1)+3)*5
        cv=input("ok?本题估分(/%d分{' ':满):"%(ur))
        try:
            fn+=float(cv)
        except:
            if cv==" ":
                fn+=ur
    print("编程题得分:%d (满分:35)"%(fn))
    f+=fn

实现效果:

 

接下来参观一下副程序:


(其实这倒是应该讲讲的,如果评论区没看到讲解的话,这句话当我没说)
倒计时:

def t():
    global tm
    tm=TM*60
    for i in range(tm):
        time.sleep(1)
        pygame.draw.rect(scr,tse,(DA[0]-90,DA[1]-30,90,30))
        scr.blit(pygame.font.Font("B.ttf",20).render("%d:%d:%d"%(tm/3600,tm%3600/60,tm%60),True,tsa()),(DA[0]-90,DA[1]-30))
        pygame.display.flip()
        tm-=1

线程结束统录分:

def j():
    global n
    while True:
        time.sleep(1)
        if threading.active_count()<n+1:
            try:
                scr.fill(tse)
                scr.blit(pygame.font.Font("B.ttf",int(ZD*0.8)).render('%s 用时:%d 分数:%d\n'%(time.strftime('%y.%m.%d'),TM*60-tm,f),True,tsa()),(10,200))
                ch.writelines('%s %d %d %d\n'%(time.strftime('%y.%m.%d'),TM*60-tm,f,qn))
                print('考试结束,分数:%d,\n前分:%d'%(f,qn))
            except:
                ch.writelines('%s %d %d %d\n'%(time.strftime('%y.%m.%d'),TM*60-tm,f,f))
                print('考试结束,分数:%d'%(f))
            break
    ch.close()

多线程×主程序:

def Q0():
    Q1()
    Q2()
    Q3()
    Q4()
ky=[Q,Q0,t,j]
def main():
    global n
    n=0
    for a in range(len(ky)):
        t=threading.Thread(target=ky[a])
        t.start()
        n+=1
if __name__ == '__main__':
    main()

好了,本期内容就到这里。
这是我的第一个内容,如有不妥,多多指教包涵。
喜欢的可以点赞收藏,希望更新的可以关注(虽然不知道下一期多久产)。
有什么想说的,什么建议啊,什么评价啊啊,都可以在评论区讲讲。
下期不见不散!

2022.10.17

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到