#文档名:软工课设06_第24组_week 8
#编写人:尹鸿伟
#校对:杨彦军
#编写时间:2020年11月2日 10:11:20
8-9周项目进度
- 在第8周开始时我们完成了对本项目的总体设计,完成了需求分析等工作,整体项目已经确定方向并且心中已经有了雏形。
- 在第9周刚开始时我们已经完成了程序的第一版开发,即控制台版本的黄金点游戏,玩家在控制台一次输入数据,并在控制台反馈最终得分,同样也能通过matplotlib生成的图片来直观的体会结果
- 通过短暂几天的学习,我们最终在第9周末尾的时候完成了GUI程序的开发,用户输入和结果展示等都实现了图形化界面。
程序方法介绍
- _ init_()方法:定义了GameBoard类和Player类的属性,GameBardr类中有playerNum储存玩家数量,players [ ] 储存实例化的玩家,g_nums [ ] 储存每轮的G值,player_scores [score, last_input] 存储玩家分数和最后一轮输入player_inputs [ [ ], [ ] ]储存玩家每轮输入。Player类中每个玩家有对应的id。
- get_player_number:从键盘获得玩家数量。本函数中还包含一个**get_entry()**函数,此函数规定了玩家数量只能输入整形切不能小于0。
- get_player_input:从键盘获得玩家每轮的输入,此函数中同样包含一个**get_entry()**函数,此函数规定了玩家输入只能为float型,切必须大于0小于100。
- start_round():判断是否再来一局游戏。
- get_player_input():将玩家的输入储存到player_scores,并且在此函数中完成G值的计算。
- get_result:计算每位玩家的输入与G值的差值的绝对值,并且返回一个玩家差值绝对值升序排列的字典 temp_dic [ (id,abs),…],并为差值绝对值最小的加分,最大的减分。在本函数的最后,我们调用了matplotlib库来更加直观的展示游戏结果,每次游戏的G值用线性图来呈现,每轮每个玩家的输入则用散点图呈现,更加清晰直观的看到G值的走向。
程序源码
GameBoard.py:
"""
文件名: GameBoard.py
功 能: 游戏主界面类定义。
修改人: 杨彦军,尹鸿伟
修改日期: 2020.11.1
修改内容: 添加游戏GUI界面。
"""
import matplotlib.pyplot as plt
from tkinter import *
from Player import Player
class GameBoard:
def __init__(self):
self.playerNum = self.get_player_number() # 玩家数量
if 0 == self.playerNum:
return
self.players = [] # 存储实例化的玩家
self.g_nums = [] # 存储每轮的G_num
self.player_scores = {} # int: [score, last_input] type, 存储玩家分数和最后一轮输入
self.player_inputs = [] # [[], []] type, 存储玩家每轮输入
for player_id in range(self.playerNum): # 实例化玩家
self.players.append(Player(player_id))
self.player_scores[player_id] = [0, 0]
self.start_round()
def start_round(self):
while True:
self.get_player_input()
keep_play = self.get_result()
if 'n' == keep_play:
break
def get_player_input(self):
inputs = []
for player in self.players:
player_input = player.get_player_input()
self.player_scores[player.get_id()][1] = player_input # 缓存玩家最后一轮输入
inputs.append(player_input)
# 计算G_num
g = sum(inputs) / len(inputs) * 0.618
self.g_nums.append(g)
self.player_inputs.append(inputs)
def get_result(self):
temp_dic = {}
# 计算绝对值阶段
for player_id, player_input in self.player_scores.items():
temp_dic[player_id] = abs(player_input[-1] - self.g_nums[-1]) # 用户输入与G值的绝对值
temp_dic = sorted(temp_dic.items(), key=lambda x: x[1], reverse=False) # 升序排序,返回的temp_dic [(id,abs),...] type
# 计分阶段
player_id, player_abs = temp_dic[0]
for player in temp_dic: # player (id,abs) type, 遍历查找是否有相同绝对值
if player_abs != player[1]:
break
self.player_scores[player[0]][0] += self.playerNum # 加N分
player_id, player_abs = temp_dic[-1]
for player in temp_dic[::-1]: # 逆序列表来找绝对值最大的
if player_abs != player[1]:
break
self.player_scores[player[0]][0] += -2 # 加-2分
# matplotlib展示阶段
result_window = Tk()
result_window.title('本轮结束')
Label(result_window, text='---Score Table---\n' +
''.join(f'玩家 {player_id} 当前分数 {self.player_scores[player_id][0]}\n'
for player_id in self.player_scores)).grid(row=0, column=0)
# todo: MATPLOTLIB FIGURE
fig = plt.figure(figsize=(4, 4), tight_layout=True)
plt.xlabel('Game Round')
plt.ylabel('Number')
plt.plot(self.g_nums, label='G-num', marker='o', ls=':')
plt.plot(self.player_inputs, marker='x', ls='')
plt.legend()
plt.grid()
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
canvas = FigureCanvasTkAgg(fig, master=result_window)
canvas.draw()
canvas.get_tk_widget().grid(row=0, column=1)
plt.close()
choice = StringVar()
choice.set('n')
def get_entry(c):
choice.set(c)
result_window.destroy()
return
Button(result_window, text='再玩一轮', command=lambda: get_entry('y')).grid(row=2, column=0, sticky=E)
Button(result_window, text='结束游戏', command=lambda: get_entry('n')).grid(row=2, column=1, sticky=W)
mainloop()
return choice.get()
def get_player_number(self):
input_window = Tk()
input_window.title('玩家数量')
Label(input_window, text='本次游戏共有多少名玩家:').grid(row=0, column=0)
num = StringVar()
num.set('0')
entry = Entry(input_window, width=8, textvariable=num)
entry.grid(row=0, column=1)
error_msg = StringVar('')
Label(input_window, textvariable=error_msg).grid(row=1, column=0, columnspan=2)
def get_entry():
try:
if 0 < int(num.get()):
input_window.destroy()
return
except ValueError:
pass
error_msg.set('-非法输入,请重新输入-')
Button(input_window, text='确认', command=get_entry).grid(row=2, column=0, columnspan=2)
mainloop()
return int(num.get())
game = GameBoard()
Player.py:
"""
文件名: Player.py
功 能: 游戏的用户类定义。
修改人: 杨彦军
修改日期: 2020.11.1
修改内容: 添加玩家输入GUI界面。
"""
from tkinter import *
class Player:
def __init__(self, id):
self.id = id # int type
def get_player_input(self):
input_window = Tk()
input_window.title('输入数字')
Label(input_window, text=f'玩家 {self.id} ,请输入你的数字:').grid(row=0, column=0)
num = StringVar()
num.set('0')
entry = Entry(input_window, width=8, textvariable=num)
entry.grid(row=0, column=1)
error_msg = StringVar('')
Label(input_window, textvariable=error_msg).grid(row=1, column=0, columnspan=2)
def get_entry():
try:
if 0 < float(num.get()) < 100:
input_window.destroy()
return
except ValueError:
pass
error_msg.set('-非法输入,请重新输入-')
Button(input_window, text='确认', command= get_entry).grid(row=2, column=0, columnspan=2)
mainloop()
return float(num.get())
def get_id(self):
return self.id
运行展示
后续展望
- 把用户输入界面(原在Player类中)整合到Gameboard类中
- 游戏结束时能讲matplotlib生成的图表保存到本地
- 完成界面的美化
- 完成更多代码的注释