work5
这一次写的内容是黄金豆小游戏,由于现在偏重写服务器端。对于算法层面其实涉及不多,更多偏于工程上的架构。
总而言之本次作业的服务器核心是用web.py所写,而且为了方便其他用户写客户端,架构非常简单。
具体而言,首先从接口上来说,服务器只涉及到两个表单操作,注册表单和提交表单,注册也同样可以在网页上进行。
由于是测试服务器通讯的,为了方便客户端调试很多细节与题设有所不同,但修改起来非常简单。
注册模块:
注册需要提交用户名和密码{[username],[password]}
1.只有在游戏开始前可以进行注册。
2.注册失败,会返回-1.
3.注册成功,会返回0.
4.注册信息会录入注册表中。
提交模块:
提交模式需要提交用户名和密码以及给的数字{[username],[password],[nut]}
1.如果下一轮还未开始用户已经提交,便会等待。
2.如果用户提交后,本轮还未结束,依然等待直到,结束,返回G值
3.若登录失败,则返回-1(测试完毕后,若为按时提交也返回-1)
游戏模块:
1.会等待本轮用户提交完毕才会给出G值(测试完毕后改为,若1秒之后仍未提交,直接失败)。
2.分数策略如提所述。
即服务器与客户端同步,以免发生一开始客户端设计的缺陷引发客户端一次都无法返回有意义的结果。
正式发布时,服务器将不等待客户端的同步。
画图由一个monitor实时返回此时AVG的值。值得一提的是,由于web.py对于线程数有限制(10),我们修改了web.py source里的代码,把THREAD数目放宽才使得该项目成为可能。
测试程序:
开了30个线程测了50组数据,图像反应正常。
#coding=utf-8
import wx
from matplotlib.figure import Figure
import matplotlib.font_manager as font_manager
import numpy as np
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
import web
import datetime
import time
from web import form
import matplotlib.pyplot as plt
import thread
web.config.debug = False
import sys
succ = '0'
fail = '1'
PLAYERNUM = 30
reload(sys)
sys.setdefaultencoding("utf-8")
class Game():
nowtime = 0
paticipate_num = 0
active_num = 0
total =0.0
avg = 0.0
score = {}
times = {}
number = {}
def __init__(self):
pass
G = Game()
x = []
y = []
urls=('/','Index',
'/reg','Reg',
'/login','Login',
'/logout','Logout',
'/showusers','Showusers',
)
app=web.application(urls,globals())
render = web.template.render('templates',base='base')
session = web.session.Session(app, web.session.DiskStore('sessions'),initializer={'login':0,'id':'0'})
db1=web.database(dbn='mysql',
db='golden',
user='root',
pw='199089455',
port=3306,)
###首页
class Index:
def GET(self):
#return web.ctx.ip
return datetime.datetime.now().strftime('%Y%m%d%H%M%S%S')
###注册页
class Reg:
vusername= form.regexp(r".{3,20}$", '用户名长度为3-20位')
vpass = form.regexp(r".{6,20}$", '密码长度为6-20位')
vemail = form.regexp(r".*@.*", "must be a valid email address")
regForm=web.form.Form(
form.Textbox('username',vusername,description=u'用户名'),
form.Password("password",vpass,description=u"密码"),
form.Password("password2", description=u"确认密码"),
form.Button(u"马上注册", type="submit", description="submit"),
validators = [
form.Validator("两次输入的密码不一致", lambda i: i.password == i.password2)]
)
def GET(self):
return render.reg(self.regForm,u'注册成功后自动跳往登陆界面')
def POST(self):
formdata=web.input();
username=web.net.websafe(formdata.username)
password=web.net.websafe(formdata.password)
regdate=datetime.datetime.now().strftime('%Y%m%d%H%M%S')
if not self.regForm.validates() and G.paticipate_num>=PLAYERNUM:
return fail
#判断用户名是否存在:
else:
if len(getUserByUserName(username))>0:
#return render.reg(self.regForm,u'用户名已存在')
return fail
else:
ret=addUser(username,password,regdate)
if ret==0:
#return u'注册成功'
G.paticipate_num+=1
G.score [username]= 0
G.times [username]= 0
G.number[username]= 0
return succ
else:
return fail
###登陆页面
class Login:
loginForm=form.Form(form.Textbox('username',description=u'用户名'),
form.Password("password",description=u"密码"),
form.Button(u"马上登陆", type="submit", description="submit"),)
def GET(self):
if logged():
return 'you are logged '+session.id
else:
return render.login(self.loginForm)
def POST(self):
postdata=web.input()
username=web.net.websafe(postdata.username)
password=web.net.websafe(postdata.password)
nut=float(web.net.websafe(postdata.nut))
rslist=getUserByUserName(username)
if len(rslist)==0:
#return render.login(self.loginForm,'用户名不存在')
return
else:
if password==rslist[0].password:
while G.times[username]>=G.nowtime:
time.sleep(0.001)
G.times[username]+=1
G.number[username]=nut
G.active_num+=1
G.total+=nut
while G.times[username]==G.nowtime:
time.sleep(0.001)
return G.avg*0.618
else:
#return render.login(self.loginForm,'用户名及密码不匹配')
return fail
###注销登陆页面
class Logout:
def GET(self):
session.login=0
session.kill()
return 'you have logged out!'
###显示用户列表
class Showusers:
def GET(self):
if logged():
usersList=getUsers()
return render.users(usersList)
else:
return 'please log in first!'
###判断用户是否登陆
def logged():
if session.login==1:
return True
else:
return False
################################################ 数据库操作部分 begin ############################################################
#增加用户
def addUser(username,password,regdate):
ret=db1.insert('t_user',username=username ,password=password,regdate=regdate)
return ret
#获取用户列表
def getUsers(orderby='regdate'):
rs=db1.select('t_user',order=orderby)
rslist=[]
for r in rs:
rslist.append(r)
return rslist
#根据用户名查询用户信息
def getUserByUserName(username):
rs=db1.select('t_user',where='username="'+username+'"')
rslist=[]
for r in rs:
rslist.append(r)
return rslist
################################################ 数据库操作部分 end ############################################################
################################################ 游戏线程 begin ############################################################
def Gamestart():
while (G.paticipate_num!= PLAYERNUM):
time.sleep(0.1)
if G.paticipate_num== PLAYERNUM:
for G.nowtime in range(1,51):
G.total = 0.0
G.active_num = 0
while G.active_num<G.paticipate_num:
time.sleep(0.1)
print G.nowtime
G.avg = G.total/PLAYERNUM
winner = ""
minsqr = 10000.0
loser = ""
maxsqr = -10000.0
for each in G.number:
if (G.number[each]-G.avg*0.618)*(G.number[each]-G.avg*0.618)<minsqr:
minsqr = (G.number[each]-G.avg*0.618)*(G.number[each]-G.avg*0.618)
winner = each
if (G.number[each]-G.avg*0.618)*(G.number[each]-G.avg*0.618)>maxsqr:
maxsqr = (G.number[each]-G.avg*0.618)*(G.number[each]-G.avg*0.618)
loser = each
G.score[winner] += PLAYERNUM
G.score[loser] -= 2
x.append(G.nowtime)
y.append(G.avg)
G.nowtime=51
################################################ 游戏线程 end ############################################################
POINTS = 300
################################################ 绘图部分 begin ############################################################
class PlotFigure(wx.Frame):
"""Matplotlib wxFrame with animation effect"""
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, title="Monitor", size=(600, 400))
# Matplotlib Figure
self.fig = Figure((6, 4), 100)
# bind the Figure to the backend specific canvas
self.canvas = FigureCanvas(self, wx.ID_ANY, self.fig)
# add a subplot
self.ax = self.fig.add_subplot(111)
# limit the X and Y axes dimensions
self.ax.set_ylim([0, 100])
self.ax.set_xlim([0, POINTS])
self.ax.set_autoscale_on(False)
self.ax.set_xticks([])
# we want a tick every 10 point on Y (101 is to have 10
self.ax.set_yticks(range(0, 101, 10))
# disable autoscale, since we don't want the Axes to ad
# draw a grid (it will be only for Y)
self.ax.grid(True)
# generates first "empty" plots
self.user = [None] * POINTS
self.l_user,=self.ax.plot(range(POINTS),self.user,label='AVG')
# add the legend
self.ax.legend(loc='upper center',
ncol=4,
prop=font_manager.FontProperties(size=10))
# force a draw on the canvas()
# trick to show the grid and the legend
self.canvas.draw()
# save the clean background - everything but the line
# is drawn and saved in the pixel buffer background
self.bg = self.canvas.copy_from_bbox(self.ax.bbox)
# bind events coming from timer with id = TIMER_ID
# to the onTimer callback function
wx.EVT_TIMER(self, TIMER_ID, self.onTimer)
def onTimer(self, evt):
"""callback function for timer events"""
# restore the clean background, saved at the beginning
self.canvas.restore_region(self.bg)
# update the data
temp = G.avg
self.user = self.user[1:] + [temp]
# update the plot
self.l_user.set_ydata(self.user)
# just draw the "animated" objects
self.ax.draw_artist(self.l_user)# It is used to efficiently update Axes data (axis ticks, labels, etc are not updated)
self.canvas.blit(self.ax.bbox)
def __del__( self ):
t.Stop()
########################################################################################################################
TIMER_ID = wx.NewId()
if __name__=="__main__":
thread.start_new_thread(Gamestart,())
thread.start_new_thread(app.run,())
app1 = wx.PySimpleApp()
frame = PlotFigure()
t = wx.Timer(frame, TIMER_ID)
t.Start(50)
frame.Show()
app1.MainLoop()
work5的更多相关文章
- python - work5 - 类与对象 - 拓展题
''' 5:购物车类,包含的功能如下,请自行设计这个类以及类里面的方法:1)用户输入工资后,打印商品列表(商品列表自行设计展示模式)2)允许用户根据商品编号去选择商品3)用户选择商品后,检查余额是否足 ...
- python - work5 - 类与对象
# -*- coding:utf-8 -*- '''@project: jiaxy@author: Jimmy@file: work_20181119.py@ide: PyCharm Communit ...
- Node.js显示页面
首先我们先要下载并安装Nodejs,然后进入Node.js中安装supervisor, npm -g install supervisor -g表示全局模式 (无论windows哪一个用户登陆都可以使 ...
- 4月10日java上机任务
1. 一维数组的创建和遍历. 声明并创建存放4个人考试成绩的一维数组,并使用for循环遍历数组并打印分数.要求: (1) 首先按“顺序”遍历,即打印顺序为:从第一个人到第四个人: (2) ...
- BM算法学习笔记
一种nb算法,可以求出数列的递推式. 具体过程是这样的. 我们先假设它有一个递推式,然后按位去算他的值. ;j<now.size();++j)(delta[i]+=1ll*now[j]*f[i- ...
- 团体程序设计天梯赛(CCCC) L3019 代码排版 方法与编译原理密切相关,只有一个测试点段错误
团体程序设计天梯赛代码.体现代码技巧,比赛技巧. https://github.com/congmingyige/cccc_code
- Java第一次实训
package com.wsy.work; public class JudgeNumber { public static void main(String[] args) { int a = 5; ...
- c++ 条件变量
.条件变量创建 静态创建:pthread_cond_t cond=PTHREAD_COND_INITIALIZER; 动态创建:pthread_cond _t cond; pthread_cond_i ...
- 2018 ACM 网络选拔赛 北京赛区
A Saving Tang Monk II #include <bits/stdc++.h> using namespace std; ; struct node { int x,y,z, ...
随机推荐
- Camel、Pastal、匈牙利标记法区别及联系
在英语中,依靠单词的大小写拼写复合词的做法,叫做"骆驼拼写法"(CamelCase).比如,backColor这个复合词,color的第一个字母采用大写. 这种拼写法在正规的英语中 ...
- GIT使用教程与基本原理
转自:http://blog.csdn.net/wengpingbo/article/details/8985132 说明:该教程全部图片都来自于<pro git>.以下所有的操作,除非特 ...
- trackr: An AngularJS app with a Java 8 backend – Part II
该系列文章来自techdev The Frontend 在本系列的第一部分我们已经描述RESTful端建立在Java 8和Spring.这一部分将介绍我们的第一个用 AngularJS建造的客户端应用 ...
- 通过CSS禁止Chrome自动为输入框添加橘黄色边框,修改/禁止 chrome input边框颜色,
1 /*Chrome浏览器 点击input 黄色边框 禁用*/ .NoOutLine:focus{outline: none} <asp:TextBox ID="txtTeleph ...
- Linux Shell编程(2): for while
; i < ; i++)) do echo "current number is $i" done SERVICES="80 22 25 110 8000 23 2 ...
- zoj 3659 Conquer a New Region
// 给你一颗树 选一个点,从这个点出发到其它所有点的权值和最大// i 到 j的最大权值为 i到j所经历的树边容量的最小值// 第一感觉是树上的dp// 后面发现不可以// 看了题解说是并查集// ...
- Mac 配置jdk
1.打开终端,开始操作 cd ~touch.bash_profile vi .bash_profile 2.在此文本中添加以下内容 export JAVA_HOME=/Library/Java/Jav ...
- chrome console js多行输入
一直以来,Chrome控制台都缺少象IE调试台那样的多行执行模式. 今天意外发现Chrome其实也支持多行模式.默认在Chrome控制台上输入回车后会执行该命令,只需要通过输入Shift+Enter ...
- 【转】终于解决了Apache乱码问题
之前开放了一个空间,给网友提供电台节目音频下载.由于多年节目的文件数量甚多,且分类没有特定格式,图省事,没有制作网页提供分类下载,而是直接利用Apache的目录浏览功能,简单直观. 不过,所在的美国服 ...
- 数据库SQL Server与C#中数据类型的对应关系
ylbtech- .NET-Basic:数据库SQL Server与C#中数据类型的对应关系 数据库SQL SServer与C#中数据类型的对应关系 1.A,返回顶部 数据库 C#程序 int int ...