BZOJ1033 | ZJOI2008 杀蚂蚁 AntBuster

<论一次杀蚂蚁的经历>

<论如何优雅地用工程代码风格写出杀蚂蚁>

引子:

前天(也就是2018-3-18)的时候,刷B站(BZOJ)突然想起要A这题……

于是怂恿WHY一起做……

然鹅种种原因,拖到昨天(2018-3-19)下午才开始做

于是在CYYZ群里开起了校车……

然后

因为巨长的变量名不想手残于是换了VSCode……

然后疯狂盖楼……

 

注意这已经是今天的中午了……,而我交了一遍得了30

下午来了遂调试……发现了几个zz错误

等级没算对啦……sort忘记+1啦……蚂蚁位置忘记更新啦……以及更为严重的,没算点积判断附加攻击到底能不能打到。

晚上开始怀疑人生……此时代码量超过10k

下载了测试数据本地测……开Lemon却不小心点了O2

结果最后半个小时在静态查错,然而并没有什么错,后来的手动测试也证明了这一点

是Lemon开了O2之后,把程序跑错了

我果然花了几乎1h试图卡掉通过开了O2的Lemon……(滑稽)

管他的,进入正题

 

 

 

 


1.构建大框架

我们需要先声明一些变量

注意高亮的部分,我们会经常使用他们。

·

然后是一些函数的Declearation

当然了,构建的时候当然是慢慢添加的,而不是一开始就全部声明。

最后,我们需要确定一下功能块

  1. 读入
  2. 关于蚂蚁的部分
  3. 炮塔攻击模块
  4. 判定游戏结束
  5. 一个总过程,只要不停地调用它就可以了
  6. Debug用的输出函数,Debug的时候只要调用即可
  7. 最后当然还有一个主函数

对于每个函数,我们应该这样规范

前面是函数内局部变量,然后是一个空行,然后是函数的功能部分。

函数与函数之间空行

哦,对了,还有就是多写注释。


现在我们开始实现读入部分

先写一个快速读入

没啥好说的,下面是读入数据。

第一是在当前地图cnt_map里用-1标明是塔,第二是在塔的结构体里面存好位置


到了蚂蚁的部分了

我们考虑用一个队列来操作蚂蚁,那就先写两个函数,方便把队列按照题意排好

这里面cmp_ant_birth是按照出生时间排序,cmp_ant_birth_rev是反过来。

乍一看birth_code没多大用处,但是实际上这方便了把死蚂蚁踢出队列。

·  ·  ·  ·

然后该到生成一个蚂蚁了

首先

这两个限制条件,一个是堵洞口,一个是满队列

cnt_x和cnt_y表示位置,level是等级,birth_code是出生的序号

特别注意等级的计算

算一下血量,记录下上一步的方向(当然是原地不动)和年龄

一气呵成!

ant_map是记录蚂蚁位置的地图,true表示这儿有蚂蚁。


到了分泌信号素了

很简单,枚举每只蚂蚁,注意特判target

在这里target表示在que中的位置,0意味着不存在target


这是蚂蚁拿蛋糕的部分,注意有强约束条件 !target

代码比较长,滑着看。 这一部分也很简单。注意血量上限即可,取min


移动蚂蚁,我们用一个合法数组,这样比较方便

can_w就是了。most_excrate 分泌素最多是多少 final_w是最终的方向,默认卡住不动。

用了ant_x和ant_y缩短代码长度。

条件1

不能越界

塔和蚂蚁

啊哈?找一个最大的分泌素

转身,附带卡住的情况

神奇的限制

最后几行是更新的。
完事了!


蚂蚁变老,起一个比较文艺的名字。

这个没啥好说的……


判定死蚂蚁踢出队列,这里我们直接把蚂蚁的birth_code赋值无限大然后排序,注意记录原队列长度和现队列长度并且不要搞混

还有就是最后的部分,更新Target

这是我最后一个Bug,我在写的时候反复提醒过自己不要漏掉这个部分

结果还是漏了……并且没想起来。


下面是塔的部分

第一个是给出两个向量,计算第二个向量的x2,y2端点(一个是0,0,一个x2,y2)距离第一个向量所在直线的距离。用了叉积

第二个是两点间欧氏距离

第三个是用点积判断C点到向量AB的垂线会不会交AB

函数和图的变量不匹配。

函数里的x1y1是向量AB,x2y2是AC,x3y3是平移过的BC

完事了。


上一半是存在Target,用函数get_distance_pp判一下能打到,就打他,并且处理附加伤害

或者达不到或者没有的情况,那找一个最近的蚂蚁(别忘了队列始终是birth_code排序的?)

用get_distance_pp,更新mindis,记录tar_ant。tar_ant就是你要攻击的那个蚂蚁。


这个是处理附加伤害,枚举蚂蚁并判一下不是原本的蚂蚁,然后构建向量判定就行了。


我干脆一块放上来了。

end_game很简单

ending_output不看也行,这是结束后输出的函数。


处理一秒的事件,你就xjb调用函数就行了,注意顺序


调试函数我就不放了……

后面是main()

大功告成!


·   ·   ·   ·

·   ·   ·   ·


所有的代码:(可能有一些调试注释什么的懒得删了)

祝AC愉快!

发表评论

邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据