黄金点游戏代码仓库地址为:https://dev.azure.com/v-zhilin/_git/GoldPoint
项目估计时间
由于这个项目非常简单,基本上一个小时就可以编写完成,因此如果事先使用PSP表格来对项目进行规划,反而会拖延项目完成的时间。在这个项目中,我认为PSP不需要使用。
接口设计
首先我们将整个软件架构分为3块,第一块为交互模块,这个模块的任务主要负责和比赛程序的输入输出进行交互,并将获得的数据预处理后发送给第二个模块;第二个模块为策略模块,这个模块主要实现一些策略,这些策略能根据给定的预处理数据来预测下一次黄金点的值;第三个模块为控制模块,主要负责协调交互模块和策略模块之间的工作。下面分别介绍这三个模块:
交互模块
-
主要文件为:
data.py
-
主要函数:
Data.observe()
-
主要函数功能描述:读取标准输入流的数据格式,通过
numpy
的矩阵变换获得两个输出:- 黄金点历史信息:
g_history
:这是一个1维的ndarray
,记录了从第一轮开始到当前轮的所有黄金点值(ground truth) - 各队提交历史信息:
team_history
:这是一个3维 ndarray :记录了从第一轮开始到当前轮每个队的提交信息,其中第一维表示队伍的编号,第二维表示对应的轮数,第三维表示提交的第一个数和第二个数.
- 黄金点历史信息:
策略模块
-
主要文件为:policy.py
-
成员函数:
成员函数名 成员函数功能 Policy.__init__
(game_iter, team_num)
设定策略模块的基本信息:游戏进行的轮数,
队伍的数量,各个策略的全局参数
Policy.__basic__average(arr) 平均策略,获得当前给定队列的平均值点 Policy.moving_avg
( g_history, team_history)
滑动平均策略,根据给定的历史黄金点信息,
通过滑动平均预测下一个黄金点的信息,
对Policy.__moving_avg__(arr) 的一次封装
Policy.__check_fluct__
(g_history)
检测黄金点的波动,返回最近
check_window
次内黄金点的波动范围
Policy.moving_exp_avg
( g_history, team_history)
指数滑动平均策略,根据给定的历史黄金点信息,
通过指数滑动平均预测下一个黄金点的信息
Policy.__detect_fluct__
(g_history, team_history)
检测其他队伍干扰的情况,根据每个队伍的输入和
黄金点的偏差,如果这个偏差大于一定的值,我们
认为这个队伍会对黄金点进行干扰,当我们采取干
扰策略时,我们的目标是制造干扰,但同时也不想
因为干扰造成失分,因此这个函数会返回一个干扰
队伍产生干扰的平均值,当我们进行干扰时,干扰
值会选择小于这个值进行扰动
[此函数在第二轮比赛中已经废弃]
Policy.random_fluctuation
(pred, max_bias, exp_mea)
这个函数在第二轮比赛中已经进行了修改:当检测
到黄金值在最近几轮中稳定时(波动范围小于2),
我们采取扰动策略,根据滑动平均的预测值基础上,
随机增加10-40作为一个干扰值,并根据这个干扰值
重新调整我们自身的滑动平均预测值;如果黄金点在
最近几轮中波动较大(大于2),说明有队伍在进行
干扰,那么我们采取的措施是通过提交滑动平均,
指数滑动平均两个值进行预测。结果返回所要提交的两个数
Policy.predict
(g_history, team_history)
这个函数作为外部模块(控制模块)调用本模块时的接
口,基于以上的策略进行组合输出最终提交的两个数字
控制模块
- 主要文件:
get_numbers.py
- 没有成员函数,主要功能为衔接交互模块和策略块,进行最终提交。
异常处理
由于本次编程内容非常简单,而且设计处理的数据量非常小,代码编程过程中不会有引发异常的情况,因此不做对异常处理的实现。
合作方式
本次合作方式,主要为:两人先一起协商策略,我(林郅琦)负责代码编写的实验测试,邢宇负责代码复审。在第一轮比赛结束后,代码调整的半小时里,我(林郅琦)主要负责代码编写和实验验证,邢宇负责想法的提出和策略的阈值评估。
自我评价
-
优点:
- 编程速度快
- 对
numpy
向量化接口非常熟悉 - 对代码的细节能够做到较好处理
-
缺点:
- 想法较为简单,有点鲁莽
队友评价
-
优点:
- 想法较好(尤其体现在第一轮结束后对代码的调整上)
- 复审仔细
- 快速的找到策略的阈值,尤其是在第一轮比赛吃完饭后,只有半小时的调整时间里,能很快确定判定波动大小的阈值。
-
缺点:
- 参与代码编写的工作不是很多(主要是因为我把一不小心就写完了全部的代码)
合作照片
实际花费时间
第一轮比赛前
流程 | 花费时间 |
---|---|
方案制定 | 5min |
代码编写 | 40min |
代码复审 | 20min |
组合测试(与代码复审同时进行) | 20min |
结果分析 | 10min |
总共耗时 | 1h 15min |
第一轮至第二轮比赛间
流程 | 花费时间 |
---|---|
方案制定及上一轮数据分析 | 10min |
代码编写 | 15min |
组合测试 | 5min |
实际上第二轮的时候,方案制定->代码编写->组合测试 是一个循环过程,上面的表格为总体的每个项目所花费的时间。
比赛感悟
在第一轮比赛的时候,我们队很稳的拿到了倒数第一名(13/13),但实际上,在比赛前给的夏令营赛季复盘数据中,我们的代码能稳定的跑在第一名,究其原因,是因为夏令营的数据收敛了,这导致我们的扰动策略大获成功,而在现场的比赛中,由于许多队伍都进行的干扰,G点一直处在4-6的波动范围内,所以导致比赛过程中预测出现重大失误。同时在夏令营的数据上,指数滑动平均的表现远远好于滑动平均的表现,而在现场第一轮比赛的复盘数据中,我们发现,使用滑动平均反而优于指数滑动平均,而且采用指数滑动平均配合滑动平均(少干扰)的策略能让我们在现场第一轮复盘数据上稳定达到第一名,于是我们决定在第二轮采用这样的策略,最后比赛成果为第三名(3/13)。最后发现人心不可测啊,还是强化学习好。