ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

20212309实验四《python程序设计》实验报告

2022-05-31 23:35:23  阅读:169  来源: 互联网

标签:count python list 石头 content 20212309 str 实验报告 剪刀


 

 

20212309《Python程序设计》实验报告

 

课程:《Python》程序设计

班级:2123

姓名:沈烨

学号:20213209

实验教师:王志强

实验日期:2022年5月30日

必选/选修:公选课

 

1.实验内容

Python综合运用:尝试使用python写一个程序,能够在与人进行猜拳的同时学习玩家的猜拳习惯,并利用该习惯提高计算机的胜率。

预想功能:读入玩家出招,输出计算机和玩家的出招及结果,并将历史战绩记录在一个txt文档中。

 

  1. 实验过程及结果

(一)构想的提出与功能的确认

这个程序的灵感来源于一个研究:人们猜拳时,总是有这样一个倾向:第一个出石头;如果赢了,下次出招保持不变;如果输了,下次倾向于出克制上次对方出招的招。但是我认为,人与人的习惯是不同的。所以我想通过在猜拳过程中学习出招习惯来更大程度提高胜率。从某种意义上说,这也有着深度学习的影子。

 

 

(二)代码的书写

程序的几个主要模块:

 

创建并初始化记录文件:

为了避免除零错误,这里预先填入了一些数据,也起到了在前几局对局数据较少时稳定各对局情况出现比例的作用。

 

# 创建记录文件
file = open(r"remember.txt", "w+")
time = str(datetime.datetime.today())
file.write(time+"\n")
file.write("(以下内容为初始化)\n")
file.write("石头 石头,石头石头 石头,剪刀石头 石头,布石头 剪刀,石头石头 剪刀,剪刀石头 剪刀,布石头 布,石头石头 布,剪刀石头 布,布\n")
file.write("剪刀 石头,石头剪刀 石头,剪刀剪刀 石头,布剪刀 剪刀,石头剪刀 剪刀,剪刀剪刀 剪刀,布剪刀 布,石头剪刀 布,剪刀剪刀 布,布\n")
file.write("布 石头,石头布 石头,剪刀布 石头,布布 剪刀,石头布 剪刀,剪刀布 剪刀,布布 布,石头布 布,剪刀布 布,布\n")
file.write("记录开始:\n")
file.write("玩家   AI\n")
file.close()

 

定义猜拳函数:

在程序中0代表石头,1代表剪刀,2代表布。猜拳函数finger()读入1,2,3并输出石头,剪刀,布。

 

# 定义猜拳函数
def finger(out):
    if out == 0:
        return "石头"
    if out == 1:
        return "剪刀"
    if out == 2:
        return "布"

 

处理记录文件中的历史记录:

学习玩家猜拳习惯,也就是猜测指定上局对局情况下玩家下局倾向于如何出招。也就是说,需要得到过往对局中一共27种出招情况。我在这里使用了.readlines方法读出过往对局数据,再通过.count方法提取各情况出现次数并用元组list[][][]存储。

 

# 学习猜拳习惯
file = open(r"remember.txt", "r")
content_list = (file.readlines())
content_str = str(content_list)
file.close()


# 定义计数变量
summary = content_str.count(",") - 27
list = [[[0, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 0]]]

list[0][0][0] = content_str.count("石头 石头,石头") - 1
list[0][0][1] = content_str.count("石头 石头,剪刀") - 1
list[0][0][2] = content_str.count("石头 石头,布") - 1

list[0][1][0] = content_str.count("石头 剪刀,石头") - 1
list[0][1][1] = content_str.count("石头 剪刀,剪刀") - 1
list[0][1][2] = content_str.count("石头 剪刀,布") - 1

list[0][2][0] = content_str.count("石头 布,石头") - 1
list[0][2][1] = content_str.count("石头 布,剪刀") - 1
list[0][2][2] = content_str.count("石头 布,布") - 1

list[1][0][0] = content_str.count("剪刀 石头,石头") - 1
list[1][0][1] = content_str.count("剪刀 石头,剪刀") - 1
list[1][0][2] = content_str.count("剪刀 石头,布") - 1

list[1][1][0] = content_str.count("剪刀 剪刀,石头") - 1
list[1][1][1] = content_str.count("剪刀 剪刀,剪刀") - 1
list[1][1][2] = content_str.count("剪刀 剪刀,布") - 1

list[1][2][0] = content_str.count("剪刀 布,石头") - 1
list[1][2][1] = content_str.count("剪刀 布,剪刀") - 1
list[1][2][2] = content_str.count("剪刀 布,布") - 1

list[2][0][0] = content_str.count("布 石头,石头") - 1
list[2][0][1] = content_str.count("布 石头,剪刀") - 1
list[2][0][2] = content_str.count("布 石头,布") - 1

list[2][1][0] = content_str.count("布 剪刀,石头") - 1
list[2][1][1] = content_str.count("布 剪刀,剪刀") - 1
list[2][1][2] = content_str.count("布 剪刀,布") - 1

list[2][2][0] = content_str.count("布 布,石头") - 1
list[2][2][1] = content_str.count("布 布,剪刀") - 1
list[2][2][2] = content_str.count("布 布,布") - 1

 

定义判断函数:

判断函数judge()的需求是按照石头、剪刀、布的顺序读入过往玩家出招的数量,把最多的一个作为预测玩家下局出招,并输出克制该出招的出招。

在两个或三个出招倾向相同的情况下,使用随机数来等概率输出。

这里的代码没有太多技巧,直接使用了7个if-elif语句。

 

# 定义判断函数:按照石头/剪刀/布顺序读入player出招习惯,输出克制player最可能出招的出招
def judge(x, y, z):

    if(x > y) and (x > z):
        return 2

    elif(y > x) and (y > z):
        return 0

    elif(z > x) and (z > y):
        return 1

    elif(x == y) and (x > z):
        choose = random.randint(0, 1)
        if choose == 0:
            return 2
        else:
            return 0

    elif(x == z) and (x > y):
        choose = random.randint(0, 1)
        if choose == 0:
            return 2
        else:
            return 1

    elif (y == z) and (y > x):
        choose = random.randint(0, 1)
        if choose == 0:
            return 0
        else:
            return 1

    elif (x == y) and (y == z):
        choose = random.randint(0, 2)
        if choose == 0:
            return 2
        elif choose == 1:
            return 0
        elif choose == 2:
            return 1

 

主体函数:

定义了四个变量:player,content_player,AI,content_AI,分别记录这局以及上局双方出招。

使用while循环,将变量player作为判断变量,读入9时结束循环。

while循环内,首先使用judge()函数依次读入list[content_player][content_AI][0],list[content_player][content_AI][1],list[content_player][content_AI][2],即上局对局情况下玩家出石头、剪刀、布的过往数据,输出克制概率最大的出招的出招作为变量AI的值。

然后读入玩家的出招,打印双方出招finger(player),finger(AI)

 

# 初始化:AI随机出,player读入
AI = random.randint(0, 2)
player = 10

# 防错输
go = 0
while go == 0:
    try:
        print("输入手势:0.石头 1.剪刀 2.布\n   输入“9”结束程序。")
        player = int(input())
        if (player == 0) or (player == 1) or (player == 2) or (player == 9):
            go = 1
    except:
        go = 0

# 输出结果
print("player:{}  AI:{}".format(finger(player), finger(AI)))
    # 判断AI出招
    AI = judge(list[content_player][content_AI][0], list[content_player][content_AI][1], list[content_player][content_AI][2])

 

记录数据:

这是最麻烦的部分。这个部分将会通过.write方法在memory.txt中写入上局双方出招,也就是content_player、content_AI,并且将元组中list[content_player][content_AI][player]这项数据+1,以实时更新细化玩家出招倾向。

 

    # 记录
    file = open(r"remember.txt", "a")
    file.write(str(finger(player)))
    file.write(' ')
    file.write(str(finger(AI)))
    file.write(',')

 

输出实时胜率:

这也是一个比较麻烦的模块。首先定义五个变量:AI_win,rate_AI,player_win,rate_player即AI和player的胜局、胜率以及总对局数summary。双方胜局数可以通过求和元组list中特定的数据来求得。这里使用for循环减少代码量。

 

    # 输出实时胜率
    AI_win = 0
    player_win = 0
    for i in range(2):
        AI_win = list[1][0][i] + list[2][1][i] + list[0][2][i]
    for i in range(2):
        player_win = list[0][1][i] + list[1][2][i] + list[2][0][i]
    rate_AI = AI_win/summary
    rate_player = player_win/summary
    print("AI胜率:{}\nplayer胜率:{}".format(rate_AI, rate_player))

 

记录对局结果:

通过.write方法在memory.txt中写入双方胜率。

 

# 结束
file.write("\n")
file.write("AI胜率:")
file.write(str(rate_AI))
file.write("\n")
file.write("player胜率:")
file.write(str(rate_player))
file.write("\n")

 

个人比较得意的代码段:

第一个是通过元组三层嵌套来存储过往对局数据,避免定义27个变量,并且方便了后续数据的调用以及更改。

 

# 定义计数变量
summary = content_str.count(",") - 27
list = [[[0, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 0]]]

list[0][0][0] = content_str.count("石头 石头,石头") - 1
list[0][0][1] = content_str.count("石头 石头,剪刀") - 1
list[0][0][2] = content_str.count("石头 石头,布") - 1

list[0][1][0] = content_str.count("石头 剪刀,石头") - 1
list[0][1][1] = content_str.count("石头 剪刀,剪刀") - 1
list[0][1][2] = content_str.count("石头 剪刀,布") - 1

list[0][2][0] = content_str.count("石头 布,石头") - 1
list[0][2][1] = content_str.count("石头 布,剪刀") - 1
list[0][2][2] = content_str.count("石头 布,布") - 1

list[1][0][0] = content_str.count("剪刀 石头,石头") - 1
list[1][0][1] = content_str.count("剪刀 石头,剪刀") - 1
list[1][0][2] = content_str.count("剪刀 石头,布") - 1

list[1][1][0] = content_str.count("剪刀 剪刀,石头") - 1
list[1][1][1] = content_str.count("剪刀 剪刀,剪刀") - 1
list[1][1][2] = content_str.count("剪刀 剪刀,布") - 1

list[1][2][0] = content_str.count("剪刀 布,石头") - 1
list[1][2][1] = content_str.count("剪刀 布,剪刀") - 1
list[1][2][2] = content_str.count("剪刀 布,布") - 1

list[2][0][0] = content_str.count("布 石头,石头") - 1
list[2][0][1] = content_str.count("布 石头,剪刀") - 1
list[2][0][2] = content_str.count("布 石头,布") - 1

list[2][1][0] = content_str.count("布 剪刀,石头") - 1
list[2][1][1] = content_str.count("布 剪刀,剪刀") - 1
list[2][1][2] = content_str.count("布 剪刀,布") - 1

list[2][2][0] = content_str.count("布 布,石头") - 1
list[2][2][1] = content_str.count("布 布,剪刀") - 1
list[2][2][2] = content_str.count("布 布,布") - 1

 

另一个是所谓程序的“健壮性”,也就是不管使用者如何输入,程序都不会报错,也能及时调整,让使用者重新输入。这一部分我使用了while循环读入变量player,通过变量go判断循环结束与否。只有当player符合要求,go更改为1,结束循环进程继续。并且使用try/expect语句避免输入字母、回车符等字符时报错。

 

    # 读入player出招
    go = 0
    while go == 0:
        try:
            player = int(input())
            if (player == 0) or (player == 1) or (player == 2) or (player == 9):
                go = 1
            else:
                print("输入手势:0.石头 1.剪刀 2.布\n   输入“9”结束程序。")
        except:
            go = 0
            print("输入手势:0.石头 1.剪刀 2.布\n   输入“9”结束程序。")
    if player == 9:
        break

 

  1. 实验过程中遇到的问题和解决过程

 

(一)第一个问题是一开始在记录过往对局时我是用回车符“\n”间隔,但是在使用.count方法时程序无法正确计数,不得已将回车改为了逗号“,”。

 

(二)第二个问题是写主体函数时被绕晕了,后来我再次写了一遍伪代码,逐步验证伪代码正确性,最后写出了正确的主体程序。

 

(三)第三个问题是过往对局情况的存储。一开始我打算直接定义变量,后来发现这几乎不可能。思索无果后我上网参考了前辈的经验,并在群里和同学确认了使用嵌套元组的可行性,解决了这个问题。


4.结课感想与体会

这个程序是我写的第一个大型程序,有着完备的功能和极强的稳定性,虽然没有什么实用性,也还有许多不完美之处,但是作为一个代码作品来说,我已经十分满意了。从构想到付诸实践,在实践中我学会了发现问题、解决问题,在事不可为的情况下与问题妥协。

Python是我目前最擅长的编程语言,极大的自由度、丰富的库调用给予了python无限可能。我使用的编译器pycharm也给我留下了很好的印象:界面简洁,功能一个不落,而且该干活就干活,不没事就弹窗,十分合我心意。

以python开启我的编程之旅,实属我幸。

标签:count,python,list,石头,content,20212309,str,实验报告,剪刀
来源: https://www.cnblogs.com/150314markus/p/16332740.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有