刷课机简史
最近预约打疫苗很难约上,借此回忆一下当年写刷课机的历史。
资源不足的时候,如何分配就成了大问题。官方一定有一套分配方法,也一定会导致资源错配,分配结果必定不能真实反映获取资源的意愿,而民间也自然会产生另一套再分配方法。在世界二流大学,想上课的学生很多,能选课的名额却很少,僧多粥少问题非常严重,于是诞生了“刷课”这门学问。
故事的大背景是,每个学生毕业前要上够一些选修课,尤其是“文化素质课”和“文化素质核心课”,要上5门还是8门;这些课的质量良莠不齐,有些给分标准不严,于是热门的课(质量好,或是给分“水”的课)供大于求。官方指定的分配机制作为一级市场,具体的分配机制其实没那么重要,好玩的其实是二级市场的变迁。不过,为了文章的完整性,这里简单介绍一下官方选课流程的抽签制度。每学期末,所有学生给下一学期想上的课填报志愿(对,就是让高考学生PTSD的用词),课程分为三类(必修,限选,任选),每一类里面可以选一个第一志愿,两个第二志愿,和无限量第三志愿(只要时间不冲突)。之后,每门课程按照总容量开始录取,本专业必修课的学生严格优先于外专业来选修的人,而同类学生里面从高志愿开始录取;当容量快要满的时候,当前批次的学生随机排序抽签,填满课程。为了使博弈更有效,学校甚至定期发布每门课各个类别各个志愿的选课人数。
然而我很早就观察到,有好多人压根没弄懂这套体系,白白浪费了自己的选项。比如说,有一门特别热门的选修课《心理学入门》一共有300个名额,然而每年都有超过1200人把它作为选修第一志愿(也就是这些人各有大约25%几率选上);之后还有600到800人把它作为选修第二志愿,他们的中签概率是零。这个第二志愿本来可以用在别的稍冷门的课上,这样选择纯属浪费,也说明他们不懂规则。(当然,在我设计的Waiting List新体系里,第一志愿人数没有比课程名额多太多的情况下,选第二志愿在Waiting List里占个好位置还是有用的。)
我作为新生,初来乍到,分析完了规则之后自然先研究了不作弊的玩法:给定所有想上的课,观察人数,规划一下怎么最大化自己被抽中的期望,然后有的放矢的用掉自己的志愿名额。我也听说了规则之外的玩法,找不再需要选课的高年级学长学姐帮忙用他们的第一志愿选课,抽中之后再跟自己调换。所谓换课操作,指的是找个夜深人静的夜晚,一方退课之后另一方马上提交选课,刚好用掉空出来的名额。
由于安排课表的过程过于痛苦,我开始尝试写一些脚本,自动的刷新网页,然后一看到有空的名额就自动选课。刚开始只是自己用,后来也让因为提前修高年级课程彻底弄乱课表的同学用。现在回想起来,也正是那个时候,“可以写程序”的消息了传出去,各种不同的刷课程序也如雨后春笋般出现了。有了这么有力的工具,我的课表自然也充实起来,我把自己想上的各种五花八门的课都给上了,课表非常充实。
In particular,学校“建议”每学期不要超过32学分(培养方案里安排的一般在22~26),“限制”只能选37学分(抽签阶段只能抽37学分的课);借助有些必修课限制本院学生选课的规则和其他必修课自带劝退属性,这37学分可以全部用来抽选修课,抽签结束后再把必修课加回来。加上刷课机,能选好多门选修课,只要时间不冲突就行。我曾经拼出过47学分和51学分的课表,当然之后也退掉了一些不合适的课,一般也有40+学分。超学分上限选课慢慢也成了同学当中的常规操作,理论上辅导员要找这么做的人谈话,当人人都这么做的时候也就没什么了。
与此同时,二级市场也广泛存在。有价值就有买卖,经济管理学院的同学非常争气,践行本学科的精神,给选修课的名额标了价,开始有经管的学生在社交网站上求购某门课程,和卖家撮合成功后就换课。当然,我也不知道第一个这么做的是不是他们学院的人,只是我第一次听说的人是,所以他们学院躺枪了。很不幸的,刷课机的存在也扰乱了市场,即使是夜深人静的时候,卖家退掉的课也会被抢走,他们似乎把这种现象称为被“狙”了。于是市场变得非常有趣,没人知道某门课是不是会被某刷课机用户抢走;真正的热门课自然是不敢交易的,一定被抢,除非有刷课机的人都已经选上了。我也曾经出过乌龙,本来要把某门课让给同学,约好在饭堂当面操作,结果怎么退课都退不掉;原来宿舍电脑上还跑着刷课机呢,还是可以同时盯着好多门我感兴趣的课程的最新版,我手动退掉后不断帮我自动抢回来。
故事的转折点是我加入了课程咨询委员会。刚开始第一个任务是GPA体系改革,我调研了一圈国外高校,抹掉了这些年来的水涨船高,还用哈佛做把学生当顾客导致GPA Inflation的反面教材;整个体系的设计太进步了,若干年后被“申请出国失败以为是因为自己GPA低”(明明是自己太菜)的学弟学妹们开了倒车,他们报告第一页仍然用哈佛做对标,这是后话。
弄完了被甩给我的锅,我开始推进自己很在意的议题:选课。恰逢这时候社会舆论对有人能用钱买到热门选修课的意见很大,我得以推进这个问题。我一直觉得,只有有钱的学生和会写代码的学生能上自己想上的课,是非常不公平的;也许因为自己骨子里是个社会主义者?(当然,也可以往坏的方面说,我就是见不得有人能用钱买到特权,尤其是他们能买到我用本事换来的特权。)
其实问题的根本在于资源匮乏,好课少;我仍旧调研了一圈国外高校,发现他们几乎没有这种问题。反而是国内其他学校都有类似的问题,各有各的解决方法,北大的公式最fancy,有99个志愿点可以自由分配,虽然最后几乎全都要砸到一门热门课上。我表示解决问题的根本方法是多开好课,校领导们表示短期内难以缓解,于是还是得从分配机制上入手。
能不能节约资源,从被浪费的课(上到一半退掉的课)里面抠回来一点?当时期中考试前后退课只罚款50元,没有任何别的后果,我觉得改成和复旦一样按学分算钱,贵一点,可以避免有人同时选太多课(“屯”课)再退掉,老师当中有一些争议,觉得这样对穷学生不公平——富学生仍然会抢一大堆课再退。讨论到一半,教育部下了命令,退课一律不准收费。于是只能退而求其次,对齐国际标准,期中退课在成绩单上记一个Withdrawn。
这条路走不通,我便想着给二级市场增加一些阻力。我觉得Waiting List最靠谱,彻底杀掉一切换课交易,按最初抽签结果来,每个没选上的人都随机抽一个顺序。这样又公平又高效,也不用刷课了。校领导们觉得方案在机制设计角度挺不错的,就是担心实现细节上有问题,于是我还和负责开发选课系统的程序员讨论了各种corner case,设想各种提醒功能。为了避免最后时刻突然被选上一门课来不及退掉,老师们还特意加入了一个时间段,只能退课不能选新的,让同学可以冷静一下仔细检查自己的课表。同时,因为最开始的志愿选择决定了一切,教务处还特意准备了新的“选课指导”材料,争取所有同学都能弄懂规则,充分参与博弈。
程序员们开发这么复杂的新体系需要时间,而选课市场的乱象已经等不及了。于是教务处给选课系统打了一些临时补丁。按照体育部的要求,体育课不许退课,于是不会浪费了。英语课非常热门,换课猖獗,于是退课之后空位不会马上放出来,统一延迟到晚上六点,方便所有同学一起抢;后来为了增加流动性,改成中午十二点和晚上六点分两次放出。作为程序员的我,自然写出了定时提交请求的程序。作为委员的我,也第一时间建议把定时改成随机延迟(我不记得有没有被采纳)。
过渡期里面,教务处的老师也严打刷课机,孙麟同学就因为写的刷课机太机械化了被抓了现行,需要去写检查。我的代码有各种随机延迟,而且完全模拟人工操作点击,所以也从没被抓到过。由于有刷课机的人少了,选自己想上的课变容易了不少——没有别的程序和我的程序竞争了。我甚至不知道,在学校发了公告杀鸡儆猴之后,还有没有第二个刷课程序正在运行。
只是Waiting List一直没开发完成上线——哪怕程序员都开始讨论压力测试了,领导们却说要先为大类招生做准备;毕竟学生不再能按院系分类,以前各种处理必修课优先的逻辑都要改,想必数据库结构要大动筋骨。于是时间一晃就过去了,等他们真的准备上线的时候,我已经即将毕业,不能再选下学期的课了。我直到这时候才和教务老师confess了我也写过刷课机,而且比较自信我的代码就算不是最强的也能排前三。能黑白两道通吃,吃饭砸锅,彻底封死所有刷课机,算是我的自我救赎。
没能亲身体验“后刷课机”时代的选课市场,是我的一大遗憾。现在,刷课机彻底被扫进了历史的垃圾堆,想上什么课就加入Waiting List,然后或耐心等待、或焦急刷新排名,总之不用做任何操作。能帮同学们省下来一点和选课系统斗智斗勇的精力,也算我的一点小贡献。后来再问学弟学妹,他们对选课的过程没什么印象,我觉得这就是最好的结果。
本文与疫苗预约系统没有任何关联。附近只有一个疫苗接种点的预约网站是基于队列的,其余的全部基于轮询。
发表回复