昨天晚上在Startup News上看到了腾讯前端团队搞了个挑战游戏前端特工,挺有意思的,今天通关了,现在把攻略整理一下。
第一关:消失的时间
这一关比较简单,写入用户名和邮箱之后点击“打开”后,它会提示你抓包,打开Chrome的Network,发现发送的请求表单中有一个timestamp为空,在Console中随便输入new Date().getTime(),在Elements中找到那个元素编辑,把时间值value写进去就搞定了。
第二关:企鹅的老脸
这一关麻烦一点,左边的圆角相对好一点,右边的基础知识点是用CSS画三角形,本来我的旋转和边框颜色都没问题,就是旋转原点没用过是Google出来的,但是值一直都不对,然后发现Console里面提示“CSS3企鹅”,呵呵,Google一下轻松搞定!
左边:
-webkit-border-radius: 20px 30px;
右边:
-webkit-transform: rotate(-60deg); -webkit-transform-origin: top right; border-color: transparent #000;
第三关:坦克大战
唉,我只能说世界太奇妙,看到这一关的时候我感动得都快哭了!去年公司内部组织了一次的黑客竞赛,主题就是腾讯前端团队的坦克大战,我心爱的坦克Tony Stark莫名其妙地倒在了初赛的赛场上,让我好生郁闷。之后我都差不多忘了他了,没想到在这里焕发第二春,废话不多说,祭出我的撒手锏,我的Tony毫发无伤,谈笑间对手灰飞烟灭,过关!钢铁侠内部构造如下:
/** * CODETANK * Copyright (c) 2012, Tencent AlloyTeam, All rights reserved. * http://CodeTank.AlloyTeam.com/ * * @version 1.0 * @author TAT.Csonlai * * .d8888b. 888 88888888888 888 TM * d88P Y88b 888 ````888```` 888 * 888 888 888 888 888 * 888 .d88b. .d88888 .d88b. 888 8888b. 88888b. 888 888 * 888 d88""88b d88" 888 d8P Y8b 888 "88b 888 "88b 888 .88P * 888 888 888 888 888 888 88888888 888 .d888888 888 888 888888K * Y88b d88P Y88..88P Y88b 888 Y8b. 888 888 888 888 888 888 "88b * "Y8888P" "Y88P" "Y88888 "Y8888 888 "Y888888 888 888 888 888 * */ Jx().$package(function(J){ var seeyou = 0; var space = 19 + 88; var keepscan = false; var crossing = false; var fighting = false; var smartTurn=function(angle){ angle = angle % 360; if(angle>180){ angle=angle-360; } else if(angle<-180){ angle=angle+360; } return angle; }; var notSmartTurn = function(angle, flag) { angle = angle % 360; if (flag * angle < 0) { if (Math.abs(angle) == 180) angle = -angle; else angle = smartTurn(angle); } if (Math.abs(angle) < 8 || Math.abs(smartTurn(angle)) < 8) angle = 0; return angle; }; var getGunAngleToTurn=function(angleGunToTurn){ return (angleGunToTurn+this.getHeading()-this.getGunHeading())%360; }; var getEnemyCoordinates = function(bearing, distance){ var x = this.getX() + distance * Math.cos((this.getHeading() + bearing) * 2 * Math.PI / 360); var y = this.getY() - distance * Math.sin((this.getHeading() + bearing) * 2 * Math.PI / 360); return x.toFixed(0) + "," + y.toFixed(0); }; var getDirection = function(){ var heading = this.getHeading(); if (Math.abs(heading) < 1 || Math.abs(heading - 360) < 1) { long = this.getX() - space; direction = 1; } else if (Math.abs(heading - 90) < 1) { long = this.getBattleFieldHeight() - this.getY() - space; direction = 4; } else if (Math.abs(heading - 180) < 1) { long = this.getBattleFieldWidth() - this.getX() - space; direction = 3; } else if (Math.abs(heading - 270) < 1) { long = this.getY() - space; direction = 2; } var array = new Array(); array[0] = long; array[1] = direction; return array; }; var getAngleToTurn = function(ex, ey) { var bearing; if (ex == 0) bearing = ey > 0 ? -180 : 180; else { bearing = Math.atan((ey - this.getY()) / (ex - this.getX()))* 180 / Math.PI; if ((ex - this.getX()) > 0) bearing = - bearing; else bearing = 180 - bearing; } return bearing - this.getGunHeading(); // return bearing; }; Robot = new J.Class({extend : tank.Robot},{ /** *robot主函数 **/ run:function(){ this.setUI(tank.ui["purple"]); var direction; var bh = this.getBattleFieldHeight(); var bw = this.getBattleFieldWidth(); var x = this.getX(); var y = this.getY(); var angle = 0; var hh = y < (bh - y) ? y : (bh - y); var ww = x < (bw - x) ? x : (bw - x); var oo = hh < ww ? hh : ww; if (oo == x) { direction = 3; angle = 180; } else if (oo == (bw - x)) { direction = 1; angle = 0; } else if (oo == y) { direction = 4; angle = 90; } else if (oo == (bh - y)) { direction = 2; angle = 270; } // this.setAdjustRadarForGunTurn(true); this.setAdjustGunForRobotTurn(true); this.setTurnLeft(smartTurn(angle - this.getHeading())); this.setGunTurnLeft(smartTurn(angle - this.getGunHeading() - 180)); this.execute(); this.ahead(oo - space + 80); this.turnRight(90); this.loop(function(){ var heading = this.getHeading(); if (Math.abs(heading) < 1 || Math.abs(heading - 360) < 1) { long = this.getBattleFieldWidth() - this.getX() - space; direction = 1; } else if (Math.abs(heading - 90) < 1) { long = this.getY() - space; direction = 4; } else if (Math.abs(heading - 180) < 1) { long = this.getX() - space; direction = 3; } else if (Math.abs(heading - 270) < 1) { long = this.getBattleFieldHeight() - this.getY() - space; direction = 2; } var angle = long * 90 / 115; if (angle <= 90) { a1 = angle; a2 = 0; a3 = 0; a4 = 0; } else if (angle > 90 && angle <= 270) { a1 = 90; a2 = angle - a1; a3 = 0; a4 = 0; } else if (angle > 270 && angle <= 450) { a1 = 90; a2 = 180; a3 = angle - a1 - a2; a4 = 0; } else if (angle > 450 && angle <= 630) { a1 = 90; a2 = 180; a3 = 180; a4 = angle - a1 - a2 - a3; } else { a1 = 90; a2 = 180; a3 = 180; a4 = 180; } // this.log(a1 + ":" + a2 + ":" + a3 + ":" + a4); crossing = false; this.setAhead(long, function(){ keepscan = false; crossing = true; this.setGunTurnLeft(smartTurn(this.getHeading() - this.getGunHeading() - 180)); this.setTurnRight(90); this.setAhead(120); this.execute(); }); //this.log("1:" + (this.getHeading() - this.getGunHeading() - 90 + a1)); this.setGunTurnLeft(notSmartTurn(this.getHeading() - this.getGunHeading() - 90 + a1, 1), function(){ // this.log("2:" + (this.getHeading() - this.getGunHeading() - 90 + a1 - a2)); this.setGunTurnLeft(notSmartTurn(this.getHeading() - this.getGunHeading() - 90 + a1 - a2, -1), function(){ // this.log("3:" + (this.getHeading() - this.getGunHeading() - 90 + a1 - a2 + a3)); this.setGunTurnLeft(notSmartTurn(this.getHeading() - this.getGunHeading() - 90 + a1 - a2 + a3, 1), function(){ // this.log("4:" + (this.getHeading() - this.getGunHeading() - 90 + a1 - a2 + a3 - a4)); this.setGunTurnLeft(notSmartTurn(this.getHeading() - this.getGunHeading() - 90 + a1 - a2 + a3 - a4, -1), function(){ // keepscan = false; // crossing = true; // this.setGunTurnLeft(smartTurn(this.getHeading() - this.getGunHeading() - 180)); // this.setTurnRight(90); // this.setAhead(120); // this.execute(); }); this.execute(); }); this.execute(); }); this.execute(); }); this.execute(); }); }, onHitWall:function(e){ this.turnLeft(e.getBearing() - 90); }, onHitRobot:function(e){ // this.stopMove(); // this.log("HitRobot"); if (this.isTeammate(e.getName())) { this.say("你挡着我了,亲~!"); } else { this.say("Good dogs don't block the way!"); var angleToRobot=e.getBearing(); var angleGunToTurn=getGunAngleToTurn.call(this,angleToRobot); var angleToTurn=smartTurn(angleGunToTurn); this.turnGunLeft(angleToTurn); this.fire(3); this.scan(); // var array = getDirection.call(this); // if (!crossing) { // keepscan = true; // this.ahead(-10); // this.fire(3); // this.log(array[0]); // } } }, onScannedRobot:function(e){ // this.log(getEnemyCoordinates.call(this, e.getBearing(), e.getDistance())); // this.log("ScannedRobot"); // this.say(e.getName() + " " + (++seeyou)); // this.stopMove(); if (this.isTeammate(e.getName())) { this.say("加油啊,亲~!"); } else { this.say(e.getName() + ",只是因为在人群中多看了你一眼……"); this.broadcastMessage(getEnemyCoordinates.call(this, e.getBearing(), e.getDistance())); var angleToRobot=e.getBearing(); var angleGunToTurn=getGunAngleToTurn.call(this,angleToRobot); var angleToTurn=smartTurn(angleGunToTurn); this.turnGunLeft(angleToTurn); if (e.getDistance() <= 100) this.fire(3); else if (e.getDistance() <= 200) this.fire(2); else this.fire(1); // this.scan(); } }, onHitByBullet:function(e){ if (this.isTeammate(e.getName())) { this.say("Hold your fire!"); } else { this.say("别打我啊,亲!"); var angleGunToTurn=e.getHeading() - this.getGunHeading() + 180; var angleToTurn=smartTurn(angleGunToTurn); this.turnGunLeft(angleToTurn); this.fire(e.getPower()); } }, onBulletHit:function(e){ this.say(e.getName() + ",你还有导弹拦截系统?"); }, onMessageReceived:function(e){ var message = e.getMessage().split(","); this.turnGunLeft(smartTurn(getAngleToTurn.call(this, message[0], message[1]))); }, onRobotDeath:function(e){ this.say(e.getName() + ",你死的好~~~~~~~~~~~~~惨哪!") }, onWin:function(e){ // var x = this.getBattleFieldWidth()/2 - this.getX(); // var y = this.getBattleFieldHeight()/2 - this.getY(); // var angle = Math.atan(y/x); // this.turnRight(this.getHeading() + angle); // this.ahead(Math.sqrt(x * x + y * y)); this.say("Welcome to Iron Man's world!"); }, onDeath:function(e){ this.say("我还会再回来的~~!"); } }); });
第四关:三重门
这一关就像在考试一样,不过还是一些基础知识,直接贴答案吧。
第五关:金字塔迷宫
这一关的意思其实就是哪一条路径的数组加在一起和最大,求解!昨天晚上我就这道题没玩过,到十点多太困就睡了,今天上班把手头上的事情处理完之后继续看这个问题,它的解决思路首先要明确就是分治法,每一个元素到达底层的最大值就是它自身的值加上左右子节点到达底层最大值中的较大者。
方便起见,首先引入jQuery,打开Chrome的Console,输入:
var s = document.createElement("script"); s.src = "http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"; s.onload = function() {console.info("loaded")}; document.body.appendChild(s);
然后执行:
for (var i = 0; i < 12; i++) { var ele = $("#row_12").children(":eq(" + i + ")"); ele.data("v", Number(ele.text())); } for (var i = 11; i >= 1; i--) { var row = $("#row_" + i), next_row = $("#row_" + (i + 1)); for (var j = 0; j < i; j++) { var left = Number(next_row.children(":eq(" + j + ")").data("v")), right = Number(next_row.children(":eq(" + (j + 1) + ")").data("v")); var max = Math.max(left, right), target = row.children(":eq(" + j + ")"); target.data("v", Number(target.text()) + max); if (max === left) target.css("background-color", "red"); else target.css("background-color", "blue"); } }
上面的代码会给11层往上的每一个元素添加背景颜色,红色代表该元素想左边走到底层的值最大,蓝色代表向右边走值最大,所以最后的效果如下:
代码不太好看,有点quick-and-dirty,不过效果已经达到了,而且貌似每次的数字都会变化哦。
至此腾讯闯关第一季结束!收工!