CodeTank 是一款基于html5的编程小游戏,由于曾经做过一段时间的机器人足球,类似的小游戏对我来说并不陌生,其主要功能就是为用户提供一系列游戏运行的基本操作,对于这一款游戏来说比如设置tank的运行,tank的雷达的运行和tank火炮的运行,同时还有一系列基础的动作和函数,用户通过这一系列的基础动作和函数设计战术动作从而达到消灭敌人保全自己的目的。
这类游戏的鼻祖为一个叫Robcode的游戏,当然在腾讯刚开始推出这一款编程小游戏时也有不少质疑,很多人觉得这一款游戏是抄袭Robocode,当然也有许多人为腾讯辩护,关于抄袭的这个问题我在这篇文章中并不打算过多的进行讨论,如果大家有兴趣可以参看这篇文章,先不讨论其优劣,我们还是先来看看这一款游戏的界面,通过QQ号可以直接登录(我大企鹅就是牛逼~),登录以后我们遍可以添加自己的tank了,可是我们还没有任何tank呀,所以在这个时候我们需要创建我们的第一个tank,关于新手创建tank的过程在帮助文档中有详细描述,在这篇文章中也会简单的给大家做一个简短的介绍,由于javascript我自己也不是很熟,只是一边自己学习思考一篇记录一下自己的心得体会。
,首先工欲善其事必先利其器,所以我们对codetank提供的代码结构必须要有所了解,并且,最好是能够熟悉其官方示例代码,基于这个原则我们先来了解其基本框架:
Jx().$package(function(J){
Robot = new J.Class({extend : tank.Robot},{
/**
*robot主循环
**/
run:function(){
},
/**
*看到其他robot的处理程序
**/
onScannedRobot:function(e){
},
/**
*被子弹击中的处理程序
**/
onHitByBullet:function(e){
},
/**
*和墙碰撞的处理程序
**/
onHitWall:function(e){
},
onRobotDeath:function(e){
}
});
});
查看其官方示例发现其代码结构比较简单明确,首先我们可以看到,主要的函数接口有5个,分别为主函数接口,扫描到敌人的函数接口,被子弹击中的函数接口,和墙碰撞以及与其他机器人碰撞的接口,这些接口看起来都比较简单,然后我们可以查看几何官方示例代码,主要包括了开炮,运行、旋转等操作,都十分具有代表性,在实际中我们可以参考其示例代码设计自己的战术,通过这几天的学习我设计了一套简单的战术,也许并不是太有效但是毕竟是自己设计的第一个战术,还是很开心的我的战术基本描述为:1.根据tank位置找到离当前位置最近的角落点
2.让tank运行到最近的角落点,在这个过程中如果发现敌人直接开炮。在运行到角落点的过程中运行顺序为让tank保持方便逆时针运行的方向,这个主要是方便下面步骤进行批处理。
3.运行到角落后扫描整个战场,此时只用扫描90°方向,大大提高了扫描效率
4.在扫描过程中发现敌方的坦克则应该立即开炮,当然以最大火力开炮(暂时不考虑炮身发热)
5.若在角落被击中则以逆时针方向躲避到下一角落,在躲避过程中首先旋转炮管使其与tank运行方法一致,运行到下一个角落进行扫描。
6.若在运行过程中碰撞到其他tank则直接调转炮身刚正面(这个战术有待商榷)
7若与墙壁发生碰撞,则进行调整运行到最近角落
以上为整个战术过程,实际代码如下:
Jx().$package(function(J){
var corner=false;
var flag=1;
var stopWhenSeeRobot;
var smartTurn=function(angle){
if(angle>180){
angle=angle-360;
}
else if(angle<-180){
angle=angle+360;
}
return angle;
};
var getGunAngleToTurn=function(angleGunToTurn){
return (angleGunToTurn+this.getHeading()-this.getGunHeading())%360;
};
var smartFire=function(robot,robotDistance) {
if (robotDistance > 200 || robot.getEnergy() < 15) {
robot.fire(1);
} else if (robotDistance > 50) {
robot.fire(2);
} else {
robot.fire(3);
}
}
var widthorheight=false;
Robot = new J.Class({extend : tank.Robot},{
/**
*robot主函数
**/
run:function(){
this.setUI(tank.ui["While"]);
this.say("square ghost!","#887cff");
var currentPos=this.getPos();
var size=this.getBattleFieldSize();
var sizeTank=this.getSize();
var heading=this.getHeading();
var dis1=Math.abs(currentPos[0])+Math.abs(currentPos[1]);
var dis2=Math.abs(currentPos[0]-size[0])+Math.abs(currentPos[1]);
var dis3=Math.abs(currentPos[0])+Math.abs(currentPos[1]-size[1]);
var dis4=Math.abs(currentPos[0]-size[0])+Math.abs(currentPos[1]-size[1]);
var mindis=Math.min(Math.min(dis1,dis2),Math.min(dis3,dis4));
if(mindis===(dis1)){
this.say("1");
this.turnLeft(smartTurn(90-heading),null);
widthorheight=false;
this.ahead(currentPos[1]-sizeTank[1]);
this.turnLeft(90);
this.ahead(currentPos[0]-sizeTank[0]);
}
else if(mindis===(dis2)){
this.say("2");
this.turnLeft(smartTurn(360-heading));
this.ahead(size[0]-sizeTank[0]-currentPos[0]);
this.turnLeft(90);
this.ahead(currentPos[1]-sizeTank[1]);
widthorheight=true;
}
else if(mindis===dis3){
this.say("3");
this.turnLeft(smartTurn(180-heading));
this.ahead(currentPos[0]-sizeTank[0]);
this.turnLeft(90);
this.ahead(size[1]-currentPos[1]-sizeTank[1]);
widthorheight=true;
}
else{
this.say("4");
this.turnLeft(smartTurn(270-heading));
this.ahead(size[1]-currentPos[1]-sizeTank[1]);
this.turnLeft(90);
this.ahead(size[0]-currentPos[0]-sizeTank[0]);
widthorheight=false;
}
corner=true;
this.loop(function(){
var tankangle=this.getHeading();
var angleToTurn1=smartTurn(tankangle-this.getGunHeading()+90);
this.turnGunLeft(angleToTurn1);
this.turnGunLeft(90);
this.turnGunRight(90);
});
},
/**
*看到其他robot的处理程序
**/
onScannedRobot:function(e){
this.say("别跑啊亲!~","#887cff");
var size=this.getBattleFieldSize();
var sizeTank=this.getSize();
if (stopWhenSeeRobot){
var dis=e.getDistance();
if(dis<50)
{
this.fire(3);
this.turnLeft(90);
if(widthorheight){
var dis=size[0]-2*sizeTank[0];
this.say(dis.toString());
this.ahead(dis);
}
if(!widthorheight){
var dis=size[1]-2*sizeTank[1];
this.say(dis.toString());
this.ahead(dis);
}
widthorheight=!widthorheight;
}
this.stopMove();
var angleToRobot=e.getBearing();
var angleGunToTurn=getGunAngleToTurn.call(this,angleToRobot);
this.turnGunLeft(smartTurn(angleGunToTurn));
// smartFire(this,e.getDistance());
this.fire(3);
this.scan();
}
else{
// smartFire(this,e.getDistance());
this.fire(3);
}
},
/**
*被子弹击中的处理程序
**/
onHitByBullet:function(e){
var tankangle=this.getHeading();
var angleToTurn1=smartTurn(tankangle-this.getGunHeading());
this.say(angleToTurn1.toString());
this.turnGunLeft(smartTurn(angleToTurn1));
var currentPos=this.getPos();
var size=this.getBattleFieldSize();
var sizeTank=this.getSize();
this.say(corner.toString());
if(corner){
this.turnLeft(90);
if(widthorheight){
var dis=size[0]-2*sizeTank[0];
this.say(dis.toString());
this.ahead(dis);
}
if(!widthorheight){
var dis=size[1]-2*sizeTank[1];
this.say(dis.toString());
this.ahead(dis);
}
widthorheight=!widthorheight;
}
},
/**
*和墙碰撞的处理程序
**/
onHitWall:function(e){
var currentPos=this.getPos();
var size=this.getBattleFieldSize();
var sizeTank=this.getSize();
var heading=this.getHeading();
var dis1=Math.abs(currentPos[0])+Math.abs(currentPos[1]);
var dis2=Math.abs(currentPos[0]-size[0])+Math.abs(currentPos[1]);
var dis3=Math.abs(currentPos[0])+Math.abs(currentPos[1]-size[1]);
var dis4=Math.abs(currentPos[0]-size[0])+Math.abs(currentPos[1]-size[1]);
var mindis=Math.min(Math.min(dis1,dis2),Math.min(dis3,dis4));
if(mindis===(dis1)){
this.say("1");
this.turnLeft(smartTurn(90-heading));
widthorheight=false;
this.ahead(currentPos[1]-sizeTank[1]);
this.turnLeft(90);
this.ahead(currentPos[0]-sizeTank[0]);
}
else if(mindis===(dis2)){
this.say("2");
this.turnLeft(smartTurn(360-heading));
this.ahead(size[0]-sizeTank[0]-currentPos[0]);
this.turnLeft(90);
this.ahead(currentPos[1]-sizeTank[1]);
widthorheight=true;
}
else if(mindis===dis3){
this.say("3");
this.turnLeft(smartTurn(180-heading));
this.ahead(currentPos[0]-sizeTank[0]);
this.turnLeft(90);
this.ahead(size[1]-currentPos[1]-sizeTank[1]);
widthorheight=true;
}
else{
this.say("4");
this.turnLeft(smartTurn(270-heading));
this.ahead(size[1]-currentPos[1]-sizeTank[1]);
this.turnLeft(90);
this.ahead(size[0]-currentPos[0]-sizeTank[0]);
widthorheight=false;
}
},
onHitRobot:function(e){
var tankangle=this.getHeading();
var angleToTurn1=smartTurn(tankangle-this.getGunHeading());
this.turnGunLeft(smartTurn(angleGunToTurn));
this.fire(3);
}
});
});
代码较为冗长且没有足够的注释,各位勉强看一下,以上代码为开源代码,搜索kq2h5可以找到我的代码,欢迎大家来战,同时也欢迎大家提出改进意见。以上代码的设计思路主要参考示例代码中的corner代码,由于在角落只受到来自某一个象限的攻击,所以极大的保护了自己,特别是在混战当中,另外位于角落的tank只要将炮身旋转90°即可扫描整个战场,大大提高了扫描战场的效率,当然也就更加容易发现“敌人”,基于此目的我参考了corner示例代码,然而示例代码不管tank在任何位置都要跑到左上角,这无疑给敌人提供了许多攻击的机会,所以我选择最近的角落,另外若是受到攻击不进行躲避的话也就成了活靶子,所以我设计了一个躲避算法,当然,这个躲避算法太有规律了,并不是很好的算法,整个战术还有待改进和提高。
标签: 代码游戏, codetank, javascript
可是随着时间的推移,我们看到了太多的少年天才,看到了太多的煊赫家室,看到了太多无奈与妥协,所以我们终于接受了自己只是一个平凡的普通人这个事实。所以有人在没有主角光环加持下变得不知所措,变得茫然甚至报复社会。我能理解他们,曾经以为自己是主角,到最后却只是陪衬的滋味是有多么难受!!
其实并没有什么不公平,只是有些许的无奈罢了,若生天地间,事事都如意,那才是一件让人惊恐的事情吧。面对太多困惑,面对太多不知所措,面对太多惶恐,面对太多忽视与尴尬,我们才会渐渐成长,我们不是这个世界的中心,可是我们却是我们生活的中心,那些不如意让我们渐渐成长为一个坚强的样子,然后撑起生活的天空。
最近天气不太好,天气也是阴沉沉的,气压有些大,加上闷热的天气让人觉得很沉闷,呆在实验室也有种特别厌恶的情绪,所以早早的就离开了~
Welcome to StackEdit!
Hey! I’m your first Markdown document in StackEdit1. Don’t delete me, I’m very helpful! I can be recovered anyway in the Utils tab of the Settings dialog.Documents
StackEdit stores your documents in your browser, which means all your documents are automatically saved locally and are accessible offline!Note:
- StackEdit is accessible offline after the application has been loaded for the first time.
- Your local documents are not shared between different browsers or computers.
- Clearing your browser’s data may delete all your local documents! Make sure your documents are synchronized with Google Drive or Dropbox (check out the Synchronization section).
Create a document
The document panel is accessible using the button in the navigation bar. You can create a new document by clicking New document in the document panel.Switch to another document
All your local documents are listed in the document panel. You can switch from one to another by clicking a document in the list or you can toggle documents using Ctrl+[ and Ctrl+].Rename a document
You can rename the current document by clicking the document title in the navigation bar.Delete a document
You can delete the current document by clicking Delete document in the document panel.Export a document
You can save the current document to a file by clicking Export to disk from the menu panel.Tip: Check out the Publish a document section for a description of the different output formats.
Synchronization
StackEdit can be combined with Google Drive and Dropbox to have your documents saved in the Cloud. The synchronization mechanism takes care of uploading your modifications or downloading the latest version of your documents.Note:
- Full access to Google Drive or Dropbox is required to be able to import any document in StackEdit. Permission restrictions can be configured in the settings.
- Imported documents are downloaded in your browser and are not transmitted to a server.
- If you experience problems saving your documents on Google Drive, check and optionally disable browser extensions, such as Disconnect.
Open a document
You can open a document from Google Drive or the Dropbox by opening the Synchronize sub-menu and by clicking Open from…. Once opened, any modification in your document will be automatically synchronized with the file in your Google Drive / Dropbox account.Save a document
You can save any document by opening the Synchronize sub-menu and by clicking Save on…. Even if your document is already synchronized with Google Drive or Dropbox, you can export it to a another location. StackEdit can synchronize one document with multiple locations and accounts.Synchronize a document
Once your document is linked to a Google Drive or a Dropbox file, StackEdit will periodically (every 3 minutes) synchronize it by downloading/uploading any modification. A merge will be performed if necessary and conflicts will be detected.If you just have modified your document and you want to force the synchronization, click the button in the navigation bar.
Note: The button is disabled when you have no document to synchronize.
Manage document synchronization
Since one document can be synchronized with multiple locations, you can list and manage synchronized locations by clicking Manage synchronization in the Synchronize sub-menu. This will let you remove synchronization locations that are associated to your document.Note: If you delete the file from Google Drive or from Dropbox, the document will no longer be synchronized with that location.
Publication
Once you are happy with your document, you can publish it on different websites directly from StackEdit. As for now, StackEdit can publish on Blogger, Dropbox, Gist, GitHub, Google Drive, Tumblr, WordPress and on any SSH server.Publish a document
You can publish your document by opening the Publish sub-menu and by choosing a website. In the dialog box, you can choose the publication format:- Markdown, to publish the Markdown text on a website that can interpret it (GitHub for instance),
- HTML, to publish the document converted into HTML (on a blog for example),
- Template, to have a full control of the output.
Note: The default template is a simple webpage wrapping your document in HTML format. You can customize it in the Advanced tab of the Settings dialog.
Update a publication
After publishing, StackEdit will keep your document linked to that publication which makes it easy for you to update it. Once you have modified your document and you want to update your publication, click on the button in the navigation bar.Note: The button is disabled when your document has not been published yet.
Manage document publication
Since one document can be published on multiple locations, you can list and manage publish locations by clicking Manage publication in the menu panel. This will let you remove publication locations that are associated to your document.Note: If the file has been removed from the website or the blog, the document will no longer be published on that location.
Markdown Extra
StackEdit supports Markdown Extra, which extends Markdown syntax with some nice features.Tip: You can disable any Markdown Extra feature in the Extensions tab of the Settings dialog.
Note: You can find more information about Markdown syntax here and Markdown Extra extension here.
Tables
Markdown Extra has a special syntax for tables:| Item | Value |
|---|---|
| Computer | $1600 |
| Phone | $12 |
| Pipe | $1 |
| Item | Value | Qty |
|---|---|---|
| Computer | $1600 | 5 |
| Phone | $12 | 12 |
| Pipe | $1 | 234 |
Definition Lists
Markdown Extra has a special syntax for definition lists too:- Term 1
- Term 2
- Definition A
- Definition B
- Term 3
- Definition C
- Definition D
part of definition D
Fenced code blocks
GitHub’s fenced code blocks are also supported with Highlight.js syntax highlighting:// Foo
var bar = 0;
Tip: To use Prettify instead of Highlight.js, just configure the Markdown Extra extension in the Settings dialog.
Note: You can find more information:
Footnotes
You can create footnotes like this2.SmartyPants
SmartyPants converts ASCII punctuation characters into “smart” typographic punctuation HTML entities. For example:| ASCII | HTML | |
|---|---|---|
| Single backticks | 'Isn't this fun?' |
‘Isn’t this fun?’ |
| Quotes | "Isn't this fun?" |
“Isn’t this fun?” |
| Dashes | -- is en-dash, --- is em-dash |
– is en-dash, — is em-dash |
Table of contents
You can insert a table of contents using the marker[TOC]:MathJax
You can render LaTeX mathematical expressions using MathJax, as on math.stackexchange.com:The Gamma function satisfying is via the Euler integral
Tip: To make sure mathematical expressions are rendered properly on your website, include MathJax into your template:
<script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML"></script>
Note: You can find more information about LaTeX mathematical expressions here.
UML diagrams
You can also render sequence diagrams like this:Note: You can find more information:
Support StackEdit

作词:赵雷 作曲:赵雷
演唱:赵雷
北方的村庄住着一个南方的姑娘
她总是喜欢穿着带花的裙子站在路旁
她的话不多但笑起来是那么平静悠扬
她柔弱的眼神里装的是什么 是思念的忧伤
南方的小镇阴雨的冬天没有北方冷
她不需要臃肿的棉衣去遮盖她似水的面容
她在来去的街头留下影子芳香才会某然的心痛
眨眼的时间芳香已飘散影子已不见
南方姑娘 你是否习惯北方的秋凉
南方姑娘 你是否喜欢北方人的直爽
日子过的就像那些不眠的晚上
她嚼着口香糖对墙满谈着理想
南方姑娘 我们都在忍受着漫长
南方姑娘 是不是高楼遮住了你的希望
昨日的雨曾淋漓过她瘦弱的肩膀
夜空的北斗也没有让她找到迷途的方向
阳光里她在院子中央晾晒着衣裳
在四季的风中她散着头发安慰着时光
南方姑娘 你是否爱上了北方
南方姑娘 你说今天你就要回到你的家乡
思念让人心伤 她呼唤着你的泪光
南方的果子已熟 那是你简单的理想
啦……啦……
小尺度,基于微分方程的方法:
1.BSBC算法:
算法的基本思想:
我认为这个算法其实就是一个迭代的思想,对原始位置的像素进行迭代求解,经过多次迭代之后像素位置的值趋向于稳定,当值趋向于稳定之后就认为达到了修复的目的。
BSBC修复步骤:
a).首先由用户提供修复的图像并指明要修复的区域,用一个和待修复图像同样尺寸的2维逻辑矩阵来标识要修复的区域,(1表示要修复,0表示不要修复)
b)然后进入修补循环
修补循环主要由三个部分构成:信息传递与像素值更新、扩散过程、程序终止检验。其中
(1)信息传递与像素值更新,(每次循环执行A次此步骤):图像的缺损意味着某种信息的丢失。图像修补的目的就在于将可靠的信息从完好的区域到缺损的区域更新方程为:
Eq(1)
Eq(2)
每一个像素点的信息值用该店的拉普拉斯算子表示,这样等照线上的点将具有相同的拉普拉斯值:
因为等照度线上的点应具有相同的的拉普拉斯值,所以如果等照度线在破损区的边界处断裂,就需要沿着等照度线的方向更新
等照度线的方向为梯度方向旋转90°得到,因为等照度线上各个点的灰度相同,且沿着等照度线的方向变化最小,而沿着梯度方向的灰度变化最大,应与等照度线的方向正交,梯度的方向为:
Eq(3)
求等照度方向的源码为:
从源码我们看出其实就是求xx方向和yy方向的梯度值,然后对梯度值进行归一化得到等照度方向。
公式2中
Eq(4)
收敛因子下标M表示与0比取较大值,下标m表示与0比取较小值,下标x,y表示沿着坐标轴方向的差分,下标b,f分别表示向前和向后的差分。
整个信息传递与像素更新过程总结:
首先得到更新方程,更新方程是从影像原始值出发进行迭代,对于待修补的区域,更新的公式见公式1,然后更新公式中有两个参数分别为更新率控制常数
2)扩散过程
扩散的目的是为了消除在更新过程中产生的混叠与模糊。扩散的方程为:
Eq(5)
Eq(6)
3)终止条件,当图像的状态趋于稳定之后我们可以认为图像的修复结束,跳出修复循环,程序结束,终止条件的过程数学公式表达为:当公式7中SSD小于某个给定阈值时则终止。
Eq(7)
基于影像块匹配的影像修复方法:
主要思想为利用已知区域中的相似块来填补待修复区域的空白,主要是在待修复影像的边界处选取一定窗口大小的影像,通过在正确影像区域寻找相似性最大的区域进行寻找,找到相似性最大的区域进行填补。
上图说明了整个影像修复的过程,
通过优先级设置修补辩解的起始位置:
对于边界上p点的一个模板范围
Eq(8)
其中C为信心系数,D为数据系数,信心系数和数据系数的计算公式为:
Eq(9)
其中
信心系数是衡量修复可靠性的依据,对于一个未知区域,周围已知像素越多则对次像素进行修复的可靠性越大。位置系数为衡量待修补点的位置的关键性,一般在纹理交接处的点应该最先修补,有较大的数据系数
上述两图说明了信心系数和数据系数,对于图a,在绿色区域具有较高的信心系数在红色区域具有较低的信心系数,对于图b,在绿色区域具有较高的数据系数,数据系数在影像结构纹理连续的地方具有较大值。
传播纹理和结构信息:
结构和纹理信息的修复通过在已知区域寻找和未知区域最相似的区域来进行修复,修复公式描述如下:
Eq(10)
信心系数值的更新:
进行区域修复后需要对边界进行更新,更新边界的优先级系数:
Eq(11)
通过这样简单的更新规则可以允许使用前一次填补好的进行下一次的计算。
整个处理过程如下:
参考文献:
Bertalmio M, Sapiro G, Caselles V, et al. Image inpainting[C]//Proceedings of the 27th annual conference on Computer graphics and interactive techniques. ACM Press/Addison-Wesley Publishing Co., 2000: 417-424.
Criminisi A, Pérez P, Toyama K. Region filling and object removal by exemplar-based image inpainting[J]. Image Processing, IEEE Transactions on, 2004, 13(9): 1200-1212.
想做一个关于根据日期进行查询的功能,而此功能最好是能够选择输入的日期,这样就能够方便进行查询和格式化,当然咯在选择日期的时候应该选择一个日期范围,这样才能比较好的获取输入日期。
但是boostrap并没有直接提供一个可供输入的日期控件啊!!!为什么连一个可供输入的日期选择控件都不给我。好吧面对这种情况理论上应该自己添开发一个控件,可是我对前端真的不熟,臣妾真的做不到啊!所以我在网上搜索再三终于让我找到了一个比较好用的控件:https://github.com/dangrossman/bootstrap-daterangepicker这时此控件的git地址,控件的介绍很详细,使用起来也比较简单,总的来说就是选择起始日期和终止日期,最终显示在text标签上,控件的下载后介绍图片为:
通过此控件选择起始和终止日期,然后根据起始和终止日期作为一个表单提交给服务器,服务器获取此表单之后解析起止时间,然后在数据库中查询,最终将得到的查询结果显示出来。具体使用代码为:
上面一部分提到了数据范围输入提交表单,下面我们提一提循环显示框,在网上闲逛时突然发现一个超炫的显示窗口,于是乎也用到了我的界面上,虽然感觉有点不搭调,但是好歹看起来比较炫丽,显示效果为:
由于截动态图比较大,而且比较麻烦,所以懒得截动态图了,起始整个显示框是3D的且可以进行旋转,看起来是不是很吊,这个控件主要来源算了,找不到了,大家有兴趣可以网上找找,当然,这个控件还是有一些缺点的也不能说是缺点吧,就是感觉自己用的不是很好,在网页缩放的时候不能自动的进行响应式的布局,在这一点上我觉得对这个控件本身的应用造成了极大的限制,在此情况下,此控件做一个web端的界面是可以的,但是移植到移动端恐怕会引起一些不舒适。
下面是我整个代码的Git地址有兴趣可以下载下来看看:https://github.com/wuweiFrank/JavaDemo1
标签: 3d gallary, 开发, 日期范围选择, Java Web