--- /dev/null
+# The Tank AI Challenge
+
+Your goal is to design an AI tank which does its best to: 1) stay alive; 2) kill all enemy tanks.
+
+Rules:
+- All tanks have 1hp.
+- Tanks shoot bullets. Bullets explode on contact with tanks and other bullets, and bounce once on contact with a wall.
+- Each tank can have up to 5 bullets in the air at a time.
+
+Each tick, you get a bunch of inputs:
+- A pathmap of the level (which you can ask whether an area is passable)
+- A list of friendly and enemy units (including bullets), each with its attributes (trajectory, position, hp, speed, power, shots, etc)
+- Your attributes (position, hp, speed, power, etc)
+
+Ticks occur 30 times per second. When called, you'll return one action, which can be:
+- Move toward (x,y)
+- Fire a projectile toward (x,y)
+- Do nothing
+That is all.
+
+An AI script looks like a list of ordered (test, action) pairs. The game will consider each test in turn, and the first matching will be the action taken. Here's an example:
+
+- If there is a bullet that will collide with me in less than 15 ticks, shoot a bullet at its location.
+- If there is a bullet that will collide with me in less than 30 ticks, move perpendicular to its trajectory.
+- If there is an enemy within 100 pixels, shoot a bullet at it.
+- Finally, move toward the closest enemy tank.
+
h2, h3, h4, h5 { margin:0; margin-bottom:0.5em; }
ul, ol, li { list-style: none ! important; margin:0; padding:0; }
+table { border-spacing:0; }
+td { text-align:center; vertical-align:middle; }
+
+table.grid { position:absolute; top:0; left:0; z-index:10; }
+table.grid,
+table.grid td { outline:1px solid rgba(255,255,255,0.1); color:transparent; font: 18pt monospace;
+ margin:0; padding:0; white-space:nowrap; overflow:hidden; }
+.gridShowCoords table.grid td:hover { color:rgba(255,255,255,0.1); }
+
.rounded { border-radius:1em; -moz-border-radius:1em; -webkit-border-radius:1em; }
.box {
padding:0.5em; background-color:rgba(0,0,0, 0.1); color:#787878;
border:0; background-color:rgba(0,0,0, 0.1) ! important; color:#5c5c5c; }
#config input[type=checkbox] { top:0.33em; }
-#viewport { position:relative; top:1em; width:500px; height:500px; margin:0 auto; overflow:hidden; }
+#viewport { position:relative; top:1em; width:500px; height:500px; margin:0 auto; /* overflow:hidden; */ }
#info { position:fixed; bottom:10px; right:1em; }
#info #state { font-weight:bold; }
#info label { display:block; float:left; width:3em; margin-right:0.5em; color:#787878; }
<div><label for="pathmap">overlay pathmap</label> <input id="pathmap" name="pathmap" value="1" type="checkbox"></div>
<div><label for="aipaths">overlay ai paths</label> <input id="aipaths" name="aipaths" value="1" type="checkbox"></div>
<div><label for="trajectories">trace trajectories</label> <input id="trajectories" name="trajectories" value="1" type="checkbox"></div>
+ <div><label for="gridCoords">show coords on hover</label> <input id="gridCoords" name="gridCoords" value="1" type="checkbox"></div>
</div>
<div id="viewport"></div>
# Bugs
-
+- Tanks seem to get stuck on some corners
# TODOs
+- How-to overlay
+- Restart level button
+- AI: Line-of-sight for dodging, firing
+- AI: Don't shoot if it'll kill you or your friends
+- AI: Lead shots on moving targets
+- Config-driven unit-types (name, stats, properties; pointers to behavior scripts, assets)
+- DSL for AI scripts
+- Countdown to start
+- User system (so I know whose scripts are whose)
+- Game scoring
- Move game objects into namespace `tanks`
- Move portal into namespace (ideas: `portal`, canvas tools... `easel`, or `ezl`)
-- Classes should have generalize()-ed version of instance methods on them.
+- Support touch events (for iPad?)
# Notes
- Replace *2 and /2 with shifts at compile-time
- Clipping will suck (masking is easy -- overflow:hidden)
-
-
-
-
-# The Tank AI Challenge
-
-Your goal is to design an AI tank which does its best to: 1) stay alive; 2) kill all enemy tanks.
-
-Rules:
-- All tanks have 1hp.
-- Tanks shoot bullets. Bullets explode on contact with tanks and other bullets, and bounce once on contact with a wall.
-- Each tank can have up to 5 bullets in the air at a time.
-
-Each tick, you get a bunch of inputs:
-- A pathmap of the level (which you can ask whether an area is passable)
-- A list of friendly and enemy units (including bullets), each with its attributes (trajectory, position, hp, speed, power, shots, etc)
-- Your attributes (position, hp, speed, power, etc)
-
-Ticks occur 30 times per second. When called, you'll return one action, which can be:
-- Move toward (x,y)
-- Fire a projectile toward (x,y)
-- Do nothing
-That is all.
-
-An AI script looks like a list of ordered (test, action) pairs. The game will consider each test in turn, and the first matching will be the action taken. Here's an example:
-
-- If there is a bullet that will collide with me in less than 15 ticks, shoot a bullet at its location.
-- If there is a bullet that will collide with me in less than 30 ticks, move perpendicular to its trajectory.
-- If there is an enemy within 100 pixels, shoot a bullet at it.
-- Finally, move toward the closest enemy tank.
+- Classes should have generalize()-ed version of instance methods on them.
traceTrajectories : false
},
debug : {
- tanks : 1
+ gridShowCoords : true
+
}
};
\ No newline at end of file
this.root =
this.grid =
- new Grid(COLUMNS,ROWS, CELL_SIZE)
+ new Grid(COLUMNS,ROWS, REF_SIZE)
.appendTo(this.viewport);
this.level =
LBT = new tanks.Game();
ctx = LBT.level.ctx;
- P = LBT.addUnit(new PlayerTank(1), 6,9);
+ P = LBT.addUnit(new PlayerTank(1), 5,9);
E =
LBT.addUnit(new Tank(2), 0,1);
LBT.addUnit(new Tank(2), 1,0);
$('#config [name=aipaths]').attr('checked', p.overlayAIPaths);
$('#config [name=trajectories]').attr('checked', p.traceTrajectories);
+ $('#config [name=gridCoords]').attr('checked', tanks.config.debug.gridShowCoords);
+ $('#viewport .layer.grid')[(tanks.config.debug.gridShowCoords ? 'add' : 'remove')+'Class']('gridShowCoords');
+
// $('#config [name=bullets]').val(c.debug.projectiles);
// updateBullets( c.debug.projectiles );
}
p.overlayPathmap = $('#config [name=pathmap]').attr('checked');
p.overlayAIPaths = $('#config [name=aipaths]').attr('checked');
p.traceTrajectories = $('#config [name=trajectories]').attr('checked');
+ tanks.config.debug.gridShowCoords = $('#config [name=gridCoords]').attr('checked');
+
+ $('#viewport .layer.grid')[(tanks.config.debug.gridShowCoords ? 'add' : 'remove')+'Class']('gridShowCoords');
}
function spawnBullet(x,y, atX,atY){
Level = Rect.subclass('Level', {
+ _cssClasses : 'portal layer level',
init : function init(game, w,h){
Rect.init.call(this, w,h);
this.walls = [];
this.setup();
+ this.canvas.remove();
},
setup : function setup(){
}
// Try to blow up nearby tanks
- var t = this.nearLike(66, 'Y.is(Tank, _) && _.align !== '+this.align).shift();
+ var t = this.nearLike(66, 'Y.is(Tank, _) && _.align !== this.align').shift();
if (t) {
// console.log('I gotcha!', t);
this.shoot(t.loc.x, t.loc.y);
},
recalculatePath : function recalculatePath(){
- var t = this.nearLike(10000, 'Y.is(Tank, _) && _.align !== '+this.align).shift()
+ var t = this.nearLike(10000, 'Y.is(Tank, _) && _.align !== this.align').shift()
, pm = this.game.pathmap
;
, x1 = bb.x1 - within, y1 = bb.y1 - within
, x2 = bb.x2 + within, y2 = bb.y2 + within
;
- return this.game.pathmap.get(x1,y1, x2,y2).filter(fn || Y.op.K(true));
+ return this.game.pathmap.get(x1,y1, x2,y2).filter(fn || Y.op.K(true), this);
},
shoot : function shoot(x,y){
},
drawShape : function drawShape(ctx){
+ var tbody = $('<tbody/>')
+ , cols = this.cols, rows = this.rows, size = this.size
+ ;
+
+ Y(0, rows).forEach(function(y){
+ var row = $('<tr class="row row'+y+'" />').appendTo(tbody);
+ Y(0, cols).forEach(function(x){
+ $('<td class="cell cell'+x+'_'+y+' col'+x+'">'+x+','+y+'</td>')
+ .width(size).height(size)
+ .appendTo(row);
+ }, this);
+ }, this);
+
+
+ this.table =
+ $('<table class="grid" cellspacing="0" cellpadding="0" />')
+ .width(this.layerWidth)
+ .height(this.layerHeight)
+ .append(tbody)
+ .prependTo( this.layer );
+
+ this.canvas.remove();
+
+ return this;
+ },
+
+ _drawShape : function drawShape(ctx){
var size = this.size
, rows = this.rows
, cols = this.cols