A_Dice_Game
一、结对探索
1.1队伍基本信息
结对编号:53
队伍名称:做不出来吃大便
学号 | 姓名 | 作业博客链接 | 具体分工 |
---|---|---|---|
032002337 | 俞许晟 | 前端,双人对战、人机基本功能代码 | |
032002339 | 曾毅楷 | 原型设计、人机AI代码、B站视频 |
1.2描述结对过程
暑假的时候k问我要不要结对我说好
1.3 非摆拍的两人在讨论设计或结对编程过程的照片
二、原型设计
2.1 原型工具的选择
ik :墨刀墨刀墨刀,看到大伙在用就跟着用用,用了之后感觉还挺好使。
2.2 遇到的困难与解决办法
ik :感觉没啥困难,墨刀挺好用的,比较好上手。(虽然做得比较简陋w)
2.3 原型作品链接
2.4 原型界面图片展示
① 主页:
② 双人/人机对战:
③ 结算画面
三、编程实现
3.1 网络接口的使用
ik :本来想前后端结合,也做出了一些尝试,但是想一想这个游戏感觉纯前端又快又好,响应迅速,虽然功能上不会比有后端的丰富(感觉不用那么多功能)。
🐟:
网络接口指的网络设备的各种接口,我们现今正在使用的网络接口都为以太网接口。
常见的以太网接口类型有RJ-45接口,RJ-11接口,SC光纤接口,FDDI接口,AUI接口,BNC接口,Console接口。
使用了RJ-45接口。
3.2 代码组织与内部实现设计(类图)
①游戏逻辑实现:
②AI算法实现:
3.3 说明算法的关键与关键实现部分流程图
①游戏基本逻辑:
② ai算法实现关键:
建立col_cnt
二维数组记录玩家每一列每个点数的数量;建立can_done
数组来记录ai每一列剩余空位的数量。根据这两个数组进行此后算法的编写。
流程图如下图所示(中间省略的部分条件在3.4.2表格中有详细阐述)。
3.4 贴出重要的/有价值的代码片段并解释
3.4.1 基础游戏逻辑
消除相同数字:
//输入列、对手棋盘名,消除对手该列所有和骰子值相同的数
function judge(col, arch) {
//遍历每一行
for (var i = 0; i < 3; i++) {
//如果该行col列元素和NUM相等则置为0
if (arch[i][col] == NUM) {
arch[i][col] = 0;
}
}
}
统计总分:
//传入棋盘名,返回当前棋盘总分
function count(player) {
sum = 0;
//遍历每一列
for (var j = 0; j < 3; j++) {
count_dict = { 0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0 };
//遍历该列的每一个元素
for (var i = 0; i < 3; i++) {
count_dict[player[i][j]] += 1;//使用count_dict统计每个数字出现次数
}
for (num in count_dict) {
sum += num * count_dict[num] * count_dict[num];//根据count_dict计算该列总分
}
}
return sum;
}
判断游戏是否结束:
//传入棋盘名,返回1说明棋盘已满,游戏结束
function check(player) {
var count = 0;
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (player[i][j] == 0)
count += 1;
}
}
return (count == 0)
}
3.4.2 AI逻辑
建立col_cnt
二维数组记录玩家每一列每个点数的数量;建立can_done
数组来记录ai每一列剩余空位的数量。根据这两个数组进行此后算法的编写。
copy_ai = copy.deepcopy(ai)
copy_player = copy.deepcopy(player)
col_cnt = [[0, 0, 0], [0, 0, 0], [0, 0, 0],
[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
can_done = [0, 0, 0]
# 设置col_cnt\can_done
for i in range(3):
for j in range(3):
col_cnt[int(copy_player[j][i])][i] += 1
if copy_ai[i][j] == 0:
can_done[j] += 1
对于棋盘相应的情况,采取相应的策略。
棋盘状态情况(优先级自顶向下) | 采取策略 |
---|---|
对方某一列与己方摇到点数(>=3)相同的多于两个,并且己方棋盘该列有空位 | 填入空位,消除双连/三连 |
对方存在某一列与己方摇到的点数(>=4)相同的点数,并且己方棋盘该列有空位 | 填入空位,消除点数较大的子 |
对方存在某一列存在 “4、5、6 双连 / 三连或者3三连” 且己方摇到点数(>=3)不等于该点数;如果己方棋盘该列有空位,并且另外两列也存在两个及以上空位 | 该列留空,在另外两列运用贪心算法 |
对方存在某一列存在4、5、6 双连 / 三连且己方摇到点数小于3;如果己方棋盘该列有空位,并且另外两列也存在两个及以上空位 | 该列留空,在另外两列选可下的空位多的列落子 |
己方摇到点数1,对方某列存在点数1;如果己方棋盘该列有空位,并且另外两列也存在三个及以上空位 | 该列留空,另外两列选可下的空位多的列落子 |
己方摇到点数2,对方某列仅存在一个点数2;如果己方棋盘该列有空位,并且另外两列也存在三个及以上空位 | 该列留空,另外两列选可下的空位多的列落子 |
己方摇到点数<3 | 在可下空位多的列落子 |
己方摇到点数>=3 | 贪心算法落子 |
贪心算法相关代码
max_point = -162
best_row = 0
best_col = 0
for row in range(3):
for col in range(3):
if col != j:
if ai[row][col] != 0:
continue
else:
copy_ai = copy.deepcopy(ai)
copy_player = copy.deepcopy(player)
copy_ai[row][col] = get_num
copy_player = judge(
col, get_num, copy_player)
point = count(copy_ai)-count(copy_player)
if point > max_point:
best_row = row
best_col = col
max_point = point
ai[best_row][best_col] = get_num
judge(best_col, get_num, player)
return ai
选空位多的列落子代码
colmax = 0
done_max = 0
for col in range(0, 3):
if can_done[col] > done_max:
done_max = can_done[col]
colmax = col
for i in range(0, 3):
if ai[i][colmax] == 0:
ai[i][colmax] = get_num
judge(colmax, get_num, player)
实现“该列留空”则设置avoid_j
变量来避免填入该列。
3.5 性能分析与改进
ik :本打算采用搜索类型的ai算法进行实时分析落子,但考虑到资源与时间的开销问题,最终决定运用条件从句对ai进行落子的规划。最终的算法性能较优,结果较为符合预期(下得比较像个人)。
3.6 单元测试
ik :舍友(032002338袁豪,绰号小圆秘书,自称至尊无敌上天入地唯我独尊唯一神王)搭建了ai对战平台,我将我方ai封装函数与之进行对战,查看对局情况,棋局正常进行(但是被薄纱了呜呜呜呜呜,豪豪太强了,不愧是代码之神)。
🐟:自己反复下and把上线的人机分享给朋友们,胜率非常高😎
3.7 贴出GitHub的代码签入记录,合理记录commit信息
ik:俺的部分基本为本地编写,编写好后用QQ(快!) 传给🐟译为JavaScript进行运作。
🐟:
四、总结反思
4.1 本次任务的PSP表格
Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|
Planning(计划) | 60 | 60 |
Estimate(估计时间) | 20 | 10 |
Development(开发) | 600 | 900 |
Analysis(需求分析(包括学习新技术)) | 300 | 360 |
Design Spec(生成设计文档) | 30 | 20 |
Design Review(设计复审) | 0 | 0 |
Coding Standard(代码规范 ) | 0 | 0 |
Design(具体设计) | 0 | 0 |
Coding(具体编码) | 600 | 900 |
Code Review(代码复审) | 300 | 180 |
Test(测试(自我测试,修改代码,提交修改)) | 120 | 180 |
Test Report(测试报告) | 0 | 0 |
Size Measurement(计算工作量) | 0 | 0 |
Postmortem & Process Improvement Plan(事后总结, 并提出过程改进计划) | 0 | 0 |
Total(合计) | 2030 | 2610 |
4.2 学习进度条
🐟:
第N周 | 新增代码(行) | 累计代码(行) | 本周学习耗时(小时) | 累计学习耗时(小时) | 重要成长 |
---|---|---|---|---|---|
1 | 576 | 576 | 0 | 0 | 搭建了项目页面基本框架,因为已经学过HTML和CSS所以不耗学习时长🕶 |
2 | 266 | 842 | 4 | 4 | 学习了JavaScript基本语法;制作了双人对战python版本的demo |
3 | 662 | 1504 | 8 | 12 | 学习了一些CSS效果,优化了界面美观程度;JavaScript新增人机功能;游戏新增结算悬浮窗功能 |
ik:
第N周 | 新增代码(行) | 累计代码(行) | 本周学习耗时(小时) | 累计学习耗时(小时) | 重要成长 |
---|---|---|---|---|---|
1 | 108 | 108 | 8 | 8 | 了解了flask框架,学会了基本的应用、前后端交互 |
2 | 132 | 240 | 6 | 14 | 了解了pytorch撰写强化学习的大致方法(虽然还是写不出来555) |
3 | 323 | 563 | 0 | 14 | 开始对ai算法进行思考与编写,对下棋策略进行了细致的分析与实现;封装了各类函数,满足了相关接口需求 |
4.3 最初想象中的产品形态、原型设计作品、软件开发成果三者的差距如何?
ik :差别不是很大,因为功能并不是特别复杂,大概定下来后🐟就开工了,一会儿大致的框架都几乎出来了,和原型设计很贴合。唯一没有做好的是写的时候没有过多的了解,直接敲定了纯前端程序的编写,导致要制作在线对战积重难返较为麻烦,也就没有去运作编写在线模块。
🐟:
- 暑假敲定好方向之后自学了HTML+CSS并进行了一些小小实践,所以按照原型设计来编写网页布局很快就完成了;
- 组内讨论
- 用了差不多两三个晚上用python写了一个大概的demo版本(因为python调试方便一点);
- 用了差不多一个晚上自学了JavaScript,并把python代码翻译成JavaScript代码(要命);
- 后面再学习了一些css的特效(比如放缩,延时变换等),使产品更加美观,用户体验更好;
软件开发成果是原型设计的复现和延伸;
最后的成品满足我自己对整个产品简约、美感的期待;
和想象中的产品形态相比,最终产品的页面稍微简单了一些,一开始还有类似于写一个背景故事文案、重画界面以匹配背景、每回合用机械手臂动画下骰子等等对美工和js要求比较高的设想,对两个人的小团队来说难度还是有点高的最后成了废案;
4.4 评价你的队友
ik :么么
🐟:么么范德萨
4.5 结对编程心得体会
ik :hoho!
把游戏做完啦,开心!我觉得我们游戏的用户体验舒适程度应该会是排名比较靠前的,因为中间我们经过了一次次体验产品,站在用户的角度对游戏的各方各面进行打磨(能力范围内),最终较好地适配了电脑和pad(手机屏幕较窄,会出现需要上下滑动的情况),更得到了一个相对满意的ui和交互。
开心的是学习了flask框架,学会了它基本的模板、应用以及前后端交互的一些函数,让我对前后端交互这一块内容有了更深一步的理解(虽然最后没投入使用,只做了个demo,但是学到东西了就很开心耶耶耶)。
遗憾的是还是没能理解强化学习代码以及运用模板进行ai的构建,最终还是用算法来进行ai相关代码的编写。有机会去找一些牛哥拜拜师,学习一下相关的知识。
🌙 ik&小鱼的第二次作业,圆满结束~🌙
🐟:yoyo!
- 很高兴有一个机会可以实践暑假时学的html和css的知识(网课是做一些boring的静态网页一直没有什么兴趣做),实践带给我未知和新奇的挑战,这种机会对我而言是十分宝贵的
- 有压力才有动力。暑假的时候html和css学麻了一直下不了决心学JavaScript,作业push我去抓紧学习。事实上JavaScript和python语法十分相似,非常快就上手了
- 深感自己能力的不足,很多很不错的想法最后因为技术原因成为废案,自己的能力还需要在实践中继续加强
- 感谢我的队友ik,和他的配合非常的愉快🌹
- 很感谢每一个在界面代码还很不完善的时候体验这个游戏的朋友们,谢谢他们宝贵的建议让这个游戏的用户体验越来越好