继续“黄金点游戏”的版本迭代。
12周的“黄金点游戏”中,我们仅用一个提示窗口简要地描述本轮的游戏状态,以及各玩家在当前轮次结束后的总分。 现在,我们①添加了一个竖式的表格和一个树型的表格,用以描述各玩家目前的输入与得分情况(直接公布),以及历史的得分情况(如果展开树表)。同时,我们②添加了一个轮次-G值的折线图到计分板中,以便玩家分析G值变化的趋势。
在显示计分板之前,我们③开启了一个语音播报功能;在计分板显示之前,语音将播报本轮的G值,同时播报本轮的获胜玩家名。我们的语音播报段代码有足够的鲁棒性,它支持多个玩家同时获胜的播报,也支持中英文、数字玩家名同时出现时的播报。
综上所述,对比前后两个版本迭代,我们实现了至少三个新的功能。在后续的版本迭代后,我们会优化各功能的显示,并且加入一组更强大的AI与玩家共同游戏(正在实现中,暂未写入当前版本)。
代码如下:
import random
import os
import sys
import time
from tkinter import *
from tkinter import ttk
import tkinter
import tkinter.messagebox as messagebox
import copy
import win32com.client
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
def on_quit_scoreboard():
scoreboard = None
class Player:
def __init__(self):
self.is_human = False
self.name = "Hawaii"
self.score = 0
self.choice = []
self.gain = []
def setPlayerName(self,st):
self.is_human = True
self.name = st
def newChoice(self,mid,x = 0):
temp = 0
if not self.is_human:
temp = mid*(random.randint(0,32767)+1)/(32769)
if random.randint(0,32767) > 32000:
temp = min(100-0.000001, temp+0.1*mid*(random.randint(0,32767)+1)/(32769))
else:
temp = x
self.choice.append(temp)
def win(self,n):
self.gain.append(n)
self.score+=n
def draw(self):
self.gain.append(0)
self.score+=0
def lose(self):
self.gain.append(-2)
self.score-=2
def showName(self):
return self.name
def choice_i(self,i):
i-=1
if(0<=i and i<len(self.choice)):
return self.choice[i]
else:
return -1
def gain_i(self,i):
i-=1
if(0<=i and i<len(self.gain)):
return self.gain[i]
return -1
class Game:
def Start(self,st):
self.n = eval(st)
name_list = []
label_list = []
entry_list = []
for i in range(self.n):
tmp_label = Label(self.root,text = "玩家"+str(i+1)+"的姓名")
tmp_label.grid (row = i+1,sticky = E)
tmp_entry = Entry(self.root)
tmp_entry.grid (row = i+1,column = 1,sticky = E)
label_list.append(tmp_label)
entry_list.append(tmp_entry)
'''for i in entry_list:
name_list.append(i.get())'''
tmp_button = Button(self.root,text = "确定",command = lambda:self.addPlayer(entry_list))
tmp_button.grid(row = self.n,column = 2,sticky = E)
#self.root.update()
#self.newTurn()
def __init__(self):
self.n = 0
self.t = 0
self.p = []
self.mindis = 0
self.maxdis = 0
self.G_list = []
self.mindis_list = []
self.maxdis_list = []
self.root = Tk()
self.root.title = ('黄金点游戏')
l_users = Label(self.root,text = "人数")
l_users.grid (row=0,sticky = W)
self.entry0 = Entry(self.root)
self.entry0.grid(row = 0,column = 1,sticky = E)
self.scoreboard = None
Button(self.root,text = "开始",command = lambda :self.Start(self.entry0.get())).grid(row = 0,column = 2)
self.root.mainloop()
'''while self.n<1:
print("请输入游戏人数:")
self.n = eval(input())'''
'''for i in range(self.n):
st = input("请输入玩家"+str(i)+"的姓名(若姓名为AI,则为AI):")
if(st != "AI"):
self.p.append(Player())
self.p[-1].setPlayerName(st)
else:
self.p.append(Player())'''
def addPlayer(self,entry_list):
for i in entry_list:
self.p.append(Player())
if i.get() != 'AI':
self.p[-1].setPlayerName(i.get())
self.newTurn()
def cal(self):
avg = 0.0
for i in self.p:
avg+=i.choice_i(self.t)
avg/=self.n
avg*=0.618
#print("裁判公布G值:",avg)
self.G_list.append(avg)
self.mindis =100.0
self.maxdis = 0.0
dis = []
for i in self.p:
dis.append(abs(i.choice_i(self.t)-avg))
self.mindis = min(dis)
self.maxdis = max(dis)
self.mindis_list.append(self.mindis)
self.maxdis_list.append(self.maxdis)
#print("maxdis:",self.maxdis," mindis:",self.mindis)
for i in range(self.n):
if dis[i] == self.mindis:
self.p[i].win(self.n)
elif dis[i] == self.maxdis:
self.p[i].lose()
else :
self.p[i].draw()
if self.scoreboard != None :
self.scoreboard.destroy()
self.scoreboard = tkinter.Tk()
self.scoreboard.title("计分板")
#scoreboard.geometry('800x600')
self.scoreboard.resizable(False, False)
self.scoreboard.protocol("WM_DELETE_WINDOW", on_quit_scoreboard)
tree0 = ttk.Treeview(self.scoreboard)
tree0["columns"] = ("输入","总分")
#tree0.column("玩家", width=150)
tree0.column("输入", width=150)
tree0.column("总分", width=150)
#tree0.heading("玩家", text="玩家")
tree0.heading("输入", text="输入")
tree0.heading("总分", text="总分")
#tree0.pack(side='left')
#vsb0 = ttk.Scrollbar(self.scoreboard, orient="vertical", command=tree0.yview)
#vsb0.pack(side='right', fill='y')
#tree0.configure(yscrollcommand=vsb0.set)
j = 0
for i in self.p:
choice_string = str(i.choice_i(self.t))
score_string = str(i.score) + "(" + str(i.gain_i(self.t)) + ")"
#tree0.insert("", j, text="", values=(i.showName(), score_string))
tree0.insert("", j, text=i.showName(), values=(choice_string, score_string))
j = j + 1
tree0.pack()
tree = ttk.Treeview(self.scoreboard, selectmode = 'browse')
tree.pack(side='left')
vsb = ttk.Scrollbar(self.scoreboard, orient="vertical", command=tree.yview)
vsb.pack(side='right', fill='y')
tree.configure(yscrollcommand=vsb.set)
for k in range(1, self.t+1):
myid = tree.insert("", 0, "第" + str(k) + "轮", text = "第" + str(k) + "轮: G值" + str(self.G_list[k-1]), values=("1"))
for i in self.p:
tree.insert(myid, 0, "第" + str(k) + "轮" + str(i), text = "玩家 " + i.showName() + " 输入 " + str(i.choice_i(k)) + ",得 " + str(i.gain_i(k)) +" 分", values=("2"))
tree.pack()
turns = []
Gs = []
turns.append(0)
Gs.append(0)
for k in range(1, self.t + 1):
turns.append(k)
Gs.append(self.G_list[k-1])
f = Figure(figsize=(5, 4), dpi=100)
f_plot = f.add_subplot(111)
canvs = FigureCanvasTkAgg(f, self.scoreboard)
canvs.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
f_plot.clear()
f_plot.plot(turns, Gs)
canvs.draw()
#plt.plot(turns, Gs, linewidth=4)
#plt.title("G",fontsize=20)
#plt.xlabel("Turn", fontsize=12)
#plt.ylabel("G", fontsize=12)
# 设置坐标轴刻度标记的大小
#plt.tick_params(axis='both',labelsize=10)
#plt.show()
speak_out = win32com.client.Dispatch('SAPI.SPVOICE')
speak_out.Speak("第" + str(self.t) + "轮: G值" + str(self.G_list[self.t - 1]) + ",获胜玩家为")
for i in self.p:
if i.gain_i(self.t) == 2:
speak_out.Speak(i.showName())
#self.scoreBoard()
def input_number(self,entry_list):
mid = 50 * 0.618
if len(self.G_list) > 0:
mid = self.G_list[-1]
for i in range(self.n):
if self.p[i].is_human:
if not entry_list[i].get():
return
self.p[i].newChoice(mid,eval(entry_list[i].get()))
else:
self.p[i].newChoice(mid)
self.cal()
self.newTurn()
def newTurn(self):
self.t+=1
#print("第 "+str(self.t)+" 轮")
turn_label = Label(self.root,text = "第 "+str(self.t)+" 轮")
turn_label.grid(row = 0,column = 0,sticky = W)
self.turnLabel = Label(self.root)
label_list = []
entry_list = []
for i in range(self.n):
tmp_label = Label(self.root,text = "玩家"+str(i+1)+"的数字")
tmp_label.grid (row = i+1,column = 0,sticky = W)
if self.p[i].is_human:
tmp_entry = Entry(self.root)
tmp_entry.grid (row = i+1,column = 1,sticky = W)
tmp_entry.show = "*"
entry_list.append(tmp_entry)
else:
tmp_entry = Label(self.root,text = "AI 已经生成数字")
tmp_label.grid(row = i+1,column = 1,sticky = W)
entry_list.append(tmp_entry)
label_list.append(tmp_label)
tmp_button = Button(self.root,text = "确定",command = lambda:self.input_number(entry_list))
tmp_button.grid(row = self.n,column = 2,sticky = E)
def scoreBoard(self):
st = '第'+str(self.t)+'轮游戏\n裁判公布G值:'+str(self.G_list[-1])+'\n'
for i in self.p:
st+=i.showName()+":\n"+"输入 "+str(i.choice_i(self.t))+"\t得 "+str(i.gain_i(self.t))+'\t当前得分:'+str(i.score)+'\n'
messagebox.showinfo(title="计分板", message=st)
print("欢迎进入黄金点游戏!")
#while True:
game = Game()