Merge branch 'master' of woozle.org:projects/ctf/tanks

This commit is contained in:
Neale Pickett 2015-07-06 08:49:17 -06:00
commit f202312979
7 changed files with 161 additions and 48 deletions

View File

@ -39,7 +39,7 @@ def read_tank(infile):
def post_tank(headers, code, url):
token = os.environ.get('token')
if not token:
raise RuntimeError("Must provide token in 'token' environment variable")
token = open('token').readline().strip()
request = {}
request['token'] = token
request['name'] = headers.get('Tank-Name', '')

View File

@ -37,6 +37,10 @@
<script type="application/javascript">
window.onload = function() { design(); update(); };
function onSubmit() {
if ($('[name="name"]').val() === "") {
$('#submit-feedback').html("No name?");
return;
}
$('#submit-feedback').html("Submitting...");
// http://stackoverflow.com/questions/169506/obtain-form-input-fields-using-jquery
@ -78,19 +82,26 @@
$('[name="' + name + '"]').val(val);
};
var finishedreqs = 0;
var request = makerequest("name");
request.done(function(msg) {
$('#submit-feedback').html("");
setval("name", msg);
var gotreq = function() {
finishedreqs++;
if (finishedreqs == 13) {
$('#submit-feedback').html("Retrieved.");
}
};
request = makerequest("author");
request.done(function(msg) { setval("author", msg); } );
request.done(function(msg) { gotreq(); setval("author", msg); } );
request = makerequest("color");
request.done(function(msg) { setval("color", msg.replace(/[\r\n]/g, '')); update(); } );
request.done(function(msg) { gotreq(); setval("color", msg.replace(/[\r\n]/g, '')); update(); } );
request = makerequest("program");
request.done(function(msg) { setval("program", msg); } );
request.done(function(msg) { gotreq(); setval("program", msg); } );
var sensorfunc = function(id) {
return function(msg) {
gotreq();
var vals = msg.replace(/[\r\n]/g, '').split(" ");
setval("s"+id+"r", vals[0]);
setval("s"+id+"a", vals[1]);

View File

@ -73,22 +73,20 @@ var SPACING = 150;
var MEMORY_SIZE = 10;
var Forf = function() {
this.datastack = [];
this.cmdstack = [];
this.mem = new Object();
this.builtins = new Object();
this.builtins["debug!"] = function(myforf) { document.getElementById('debug').innerHTML = myforf.datastack.pop(); };
this.builtins["debug!"] = function(myforf) { document.getElementById('debug').innerHTML = myforf.popData(); };
var unfunc = function(func) {
return function(myforf) {
var a = myforf.datastack.pop();
var a = myforf.popData();
myforf.datastack.push(~~func(a)); // truncate, FIXME
};
};
var binfunc = function(func) {
return function(myforf) {
var a = myforf.datastack.pop();
var b = myforf.datastack.pop();
var a = myforf.popData();
var b = myforf.popData();
myforf.datastack.push(~~func(b,a)); // truncate?, FIXME
};
};
@ -119,22 +117,22 @@ var Forf = function() {
this.builtins["abs"] = unfunc(function(a) { return Math.abs(a); });
// FIXME: the three following functions can only manipulate numbers in cforf
this.builtins["dup"] = function(myforf) {
var val = myforf.datastack.pop();
var val = myforf.popData();
myforf.datastack.push(val);
myforf.datastack.push(val);
};
this.builtins["pop"] = function(myforf) {
myforf.datastack.pop();
myforf.popData();
};
this.builtins["exch"] = function(myforf) {
var a = myforf.datastack.pop();
var b = myforf.datastack.pop();
var a = myforf.popData();
var b = myforf.popData();
myforf.datastack.push(a);
myforf.datastack.push(b);
};
this.builtins["if"] = function(myforf) {
var ifclause = myforf.datastack.pop();
var cond = myforf.datastack.pop();
var ifclause = myforf.popData();
var cond = myforf.popData();
if (cond) {
// TODO: make sure ifclause is a list
for (var i = 0; i < ifclause.length; i++) {
@ -143,9 +141,9 @@ var Forf = function() {
}
};
this.builtins["ifelse"] = function(myforf) {
var elseclause = myforf.datastack.pop();
var ifclause = myforf.datastack.pop();
var cond = myforf.datastack.pop();
var elseclause = myforf.popData();
var ifclause = myforf.popData();
var cond = myforf.popData();
if (!cond) {
ifclause = elseclause;
}
@ -155,15 +153,15 @@ var Forf = function() {
}
};
this.builtins["mset"] = function(myforf) {
var pos = myforf.datastack.pop();
var a = myforf.datastack.pop();
var pos = myforf.popData();
var a = myforf.popData();
if (pos < 0 || pos >= MEMORY_SIZE) {
throw "invalid memory location";
}
myforf.mem[pos] = a;
};
this.builtins["mget"] = function(myforf) {
var pos = myforf.datastack.pop();
var pos = myforf.popData();
if (pos < 0 || pos >= MEMORY_SIZE) {
throw "invalid memory location";
}
@ -171,11 +169,20 @@ var Forf = function() {
};
};
Forf.prototype.popData = function() {
if (this.datastack.length === 0) {
throw "tried to pop from empty stack";
}
return this.datastack.pop();
};
Forf.prototype.init = function(code) {
this.code = code;
};
Forf.prototype.parse = function() {
this.cmdstack = [];
// 'parse' the input
this.code = this.code.replace(/\([^)]*\)/g, "");
var splitCode = this.code.split(/([{}])/).join(" ");
@ -214,6 +221,8 @@ Forf.prototype.parse = function() {
};
Forf.prototype.run = function() {
this.datastack = [];
var running = true;
while (running && this.cmdstack.length) {
var val = this.cmdstack.pop();
@ -222,7 +231,7 @@ Forf.prototype.run = function() {
if (val in this.builtins) {
func(this);
} else {
throw "no such function " + val;
throw "no such function '" + val + "'";
}
} else {
this.datastack.push(val);
@ -258,12 +267,12 @@ var ForfTank = function() {
myforf.fire();
};
this.builtins["set-speed!"] = function(myforf) {
var right = myforf.datastack.pop();
var left = myforf.datastack.pop();
var right = myforf.popData();
var left = myforf.popData();
myforf.setSpeed(left, right);
};
this.builtins["set-turret!"] = function(myforf) {
var angle = myforf.datastack.pop();
var angle = myforf.popData();
myforf.setTurret(deg2rad(angle));
};
this.builtins["get-turret"] = function(myforf) {
@ -271,15 +280,15 @@ var ForfTank = function() {
myforf.datastack.push(rad2deg(angle));
};
this.builtins["sensor?"] = function(myforf) {
var sensor_num = myforf.datastack.pop();
var sensor_num = myforf.popData();
myforf.datastack.push(myforf.getSensor(sensor_num));
};
this.builtins["set-led!"] = function(myforf) {
var active = myforf.datastack.pop();
var active = myforf.popData();
myforf.setLed(active);
};
this.builtins["random"] = function(myforf) {
var max = myforf.datastack.pop();
var max = myforf.popData();
if (max < 1) {
myforf.datastack.push(0);
return;
@ -658,12 +667,25 @@ var updateTanks = function(tanks) {
}
/* Run programs */
var errors = [];
for (var i = 0; i < tanks.length; i++) {
if (tanks[i].killer) {
continue;
}
try {
tanks[i].parse(tanks[i].code);
tanks[i].run();
} catch (e) {
errors.push(e);
}
}
if (errors.length) {
if (interval) {
clearInterval(interval);
}
document.getElementById('debug').innerHTML = "Error: " + errors.join();
return;
}
/* Fire cannons and check for crashes */
@ -696,6 +718,8 @@ var resetTanks = function() {
clearInterval(interval);
}
document.getElementById('debug').innerHTML = "&nbsp;";
tanks = [];
ftanks = [];
var tank;

View File

@ -36,6 +36,9 @@ cat <<EOF >$fn
<html>
<head>
<title>Tanks Round $next</title>
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.0/themes/ui-darkness/jquery-ui.css" type="text/css">
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="//code.jquery.com/ui/1.11.0/jquery-ui.min.js"></script>
<script type="application/javascript" src="tanks.js"></script>
<link rel="stylesheet" href="style.css" type="text/css">
<script type="application/javascript">

View File

@ -191,3 +191,10 @@ table.pollster thead {
.swatch {
color: #000000;
}
.ui-slider-tick-mark {
display: inline-block;
width: 2px;
height: 100%;
position: absolute;
}

View File

@ -25,7 +25,7 @@ BEGIN {
print " <h2>Rankings</h2>";
print " <p>Over the last " ngames" games only.</p>";
print " <ol>";
for (i = rounds - ngames - 1; i < rounds; i += 1) {
for (i = rounds - ngames - 1; i > 0 && i < rounds; i += 1) {
fn = sprintf("round-%04d.html", i)
while (getline < fn) {
if ($2 == "score") {

View File

@ -62,11 +62,7 @@ function Tank(ctx, width, height, color, sensors) {
if (!this.dead) {
return;
}
if (this.fire == 5) {
// one frame of cannon fire
this.draw_cannon();
this.fire = 0;
}
var points = 7;
var angle = Math.PI / points;
@ -74,6 +70,15 @@ function Tank(ctx, width, height, color, sensors) {
ctx.translate(this.x, this.y);
ctx.rotate(this.rotation);
if (this.fire == 5) {
ctx.save();
ctx.rotate(this.turret);
// one frame of cannon fire
this.draw_cannon();
this.fire = 0;
ctx.restore();
}
ctx.lineWidth = 2;
ctx.strokeStyle = craterStroke;
ctx.fillStyle = craterFill;
@ -173,10 +178,21 @@ function Tank(ctx, width, height, color, sensors) {
}
}
var loop_id;
var updateFunc = null;
function togglePlayback() {
if ($("#playing").prop("checked")) {
loop_id = setInterval(updateFunc, 66);
} else {
clearInterval(loop_id);
loop_id = null;
}
$("#pauselabel").toggleClass("ui-icon-play ui-icon-pause");
}
function start(id, game) {
var canvas = document.getElementById(id);
var ctx = canvas.getContext('2d');
var loop_id;
canvas.width = game[0][0];
canvas.height = game[0][1];
@ -199,15 +215,7 @@ function start(id, game) {
lastframe = frame;
}
function update() {
var idx = frame % (turns.length + 20);
var turn;
frame += 1;
if (idx >= turns.length) {
return;
}
function drawFrame(idx) {
canvas.width = canvas.width;
turn = turns[idx];
@ -231,12 +239,72 @@ function start(id, game) {
for (i in turn) {
tanks[i].draw_tank()
}
document.getElementById('frameid').innerHTML = idx;
}
function update() {
var idx = frame % (turns.length + 20);
var turn;
frame += 1;
if (idx >= turns.length) {
return;
}
drawFrame(idx);
$('#seekslider').slider('value', idx);
}
function seekToFrame(newidx) {
var idx = frame % (turns.length + 20);
if (idx !== newidx) {
frame = newidx;
drawFrame(newidx);
}
// make sure we're paused
if ($("#playing").prop("checked")) {
$("#playing").prop("checked", false);
togglePlayback();
}
}
updateFunc = update;
loop_id = setInterval(update, 66);
//loop_id = setInterval(update, 400);
if (fps) {
setInterval(update_fps, 1000);
}
if (id === "battlefield") {
$("#game_box").append('<p><input type="checkbox" checked id="playing" onclick="togglePlayback();"><label for="playing"><span class="ui-icon ui-icon-pause" id="pauselabel"></class></label> <span id="frameid">0</span> <span id="seekslider" style="width: 75%; float: right;"></span></p>');
$('#playing').button();
var slider = $('#seekslider');
slider.slider({ max: turns.length-1, slide: function(event, ui) { seekToFrame(ui.value); } });
var spacing = 100 / turns.length;
var deaths = [];
for (i in turns[0]) {
deaths.push(false);
}
var percent = 0;
for (var f = 0; f < turns.length; f++) {
var turn = turns[f];
if (percent < (spacing * f)) {
percent = spacing * f;
}
for (var i = 0; i < turn.length; i++) {
if (deaths[i]) { continue; }
if (!turn[i] || (turn[i][4] & 4)) {
deaths[i] = true;
// http://stackoverflow.com/questions/8648963/add-tick-marks-to-jquery-slider
$('<span class="ui-slider-tick-mark"></span>').css('left', percent + '%').css('background-color', game[1][i][0]).appendTo(slider);
percent++;
break;
}
}
}
}
}