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): def post_tank(headers, code, url):
token = os.environ.get('token') token = os.environ.get('token')
if not token: if not token:
raise RuntimeError("Must provide token in 'token' environment variable") token = open('token').readline().strip()
request = {} request = {}
request['token'] = token request['token'] = token
request['name'] = headers.get('Tank-Name', '') request['name'] = headers.get('Tank-Name', '')

View File

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

View File

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

View File

@ -36,6 +36,9 @@ cat <<EOF >$fn
<html> <html>
<head> <head>
<title>Tanks Round $next</title> <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> <script type="application/javascript" src="tanks.js"></script>
<link rel="stylesheet" href="style.css" type="text/css"> <link rel="stylesheet" href="style.css" type="text/css">
<script type="application/javascript"> <script type="application/javascript">

View File

@ -191,3 +191,10 @@ table.pollster thead {
.swatch { .swatch {
color: #000000; 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 " <h2>Rankings</h2>";
print " <p>Over the last " ngames" games only.</p>"; print " <p>Over the last " ngames" games only.</p>";
print " <ol>"; 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) fn = sprintf("round-%04d.html", i)
while (getline < fn) { while (getline < fn) {
if ($2 == "score") { if ($2 == "score") {

View File

@ -62,11 +62,7 @@ function Tank(ctx, width, height, color, sensors) {
if (!this.dead) { if (!this.dead) {
return; return;
} }
if (this.fire == 5) {
// one frame of cannon fire
this.draw_cannon();
this.fire = 0;
}
var points = 7; var points = 7;
var angle = Math.PI / points; var angle = Math.PI / points;
@ -74,6 +70,15 @@ function Tank(ctx, width, height, color, sensors) {
ctx.translate(this.x, this.y); ctx.translate(this.x, this.y);
ctx.rotate(this.rotation); 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.lineWidth = 2;
ctx.strokeStyle = craterStroke; ctx.strokeStyle = craterStroke;
ctx.fillStyle = craterFill; 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) { function start(id, game) {
var canvas = document.getElementById(id); var canvas = document.getElementById(id);
var ctx = canvas.getContext('2d'); var ctx = canvas.getContext('2d');
var loop_id;
canvas.width = game[0][0]; canvas.width = game[0][0];
canvas.height = game[0][1]; canvas.height = game[0][1];
@ -199,15 +215,7 @@ function start(id, game) {
lastframe = frame; lastframe = frame;
} }
function update() { function drawFrame(idx) {
var idx = frame % (turns.length + 20);
var turn;
frame += 1;
if (idx >= turns.length) {
return;
}
canvas.width = canvas.width; canvas.width = canvas.width;
turn = turns[idx]; turn = turns[idx];
@ -231,12 +239,72 @@ function start(id, game) {
for (i in turn) { for (i in turn) {
tanks[i].draw_tank() 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, 66);
//loop_id = setInterval(update, 400); //loop_id = setInterval(update, 400);
if (fps) { if (fps) {
setInterval(update_fps, 1000); 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;
}
}
}
}
} }