diff --git a/docs/TODO.md b/docs/TODO.md index e80c02b..6fd40ff 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -10,13 +10,5 @@ Requests ======== * Merge devdsp fixes (https://github.com/devdsp/tanks/commits/master) - -Done -==== - * Fix leaderboard - -Won't Fix -======= - * Read sensors from "sensors" and not "sensor[0-9]" diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000..199bf78 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,6 @@ +defaults: + - + scope: + path: "" + values: + layout: "default" diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html new file mode 100644 index 0000000..94e08b5 --- /dev/null +++ b/docs/_layouts/default.html @@ -0,0 +1,29 @@ + + + + + + + +{% if page.scripts %}{% for js_file in page.scripts %} + +{% endfor %}{% endif %} + {{ site.title | default: site.github.repository_name }} by {{ site.github.owner_name }} + + + +

{{ page.title | default: site.title }}

+ +{{ content }} + + + + diff --git a/docs/_site/TODO.html b/docs/_site/TODO.html new file mode 100644 index 0000000..af7313a --- /dev/null +++ b/docs/_site/TODO.html @@ -0,0 +1,36 @@ + + + + + + + + + by + + + +

To-Do List

+ +

BUGS

+ +

Requests

+ + + + + + + diff --git a/docs/_site/assets/css/dirtbags.css b/docs/_site/assets/css/dirtbags.css new file mode 100644 index 0000000..6a86e06 --- /dev/null +++ b/docs/_site/assets/css/dirtbags.css @@ -0,0 +1,151 @@ +/**** document ****/ + +html { + background: #eed url(/assets/images/grunge.png) repeat-x; +} + +body { + font-family: sans-serif; + color: #112; + padding: 10px; + max-width: 700px; +} + +/**** heading ****/ + +#title { + text-transform: lowercase; + font-size: 1.6em; + padding: 3px; + margin: 0 0 1em 2em; +} + +#title:before { + color: #999; + letter-spacing: -0.1em; + content: "Dirtbags: "; +} + +/*** left side bar ***/ + +nav h2 { + display: none; +} + +nav ul { + list-style: none; + text-align: center; +} + +nav li { + display: inline; +} + +nav li a { + text-transform: lowercase; + font-size: 0.9em; +} + +nav li + li:before { + content: " | "; +} + + +/**** body ****/ + +a img { + border: 0px; +} + +a { + text-decoration: none; + color: #2a4; + font-weight: bold; +} + +a:hover { + color: #ddc; + background: #2a4; +} + + +h1, h2, h3 { + color: #464; + letter-spacing: -0.05em; +} + +.readme { + background-color: #ccc; + margin: 1em; +} + +pre { + background-color: #ccc; + border: solid #888 2px; + padding: 0.25em; +} + + +th { + vertical-align: top; + text-align: center; +} +td { + vertical-align: top; + text-align: right; +} + +p { + line-height: 1.4em; + margin-bottom: 20px; +} + +hr { + border: 1px solid #444; +} + +dt { + white-space: pre; + background-color: #333; + padding: 5px; + border: 2px solid green; + border-bottom: none; + font-weight: bold; +} + +dd { + border: 2px solid green; + margin: 0px; + padding: 5px; + background-color: #282828; +} + + +/**** special cases ****/ + +.wide { + max-width: inherit; +} + +.figure { + margin: 0.5em 1em; + float: right; + font-size: small; + text-align: center; +} + +.scoreboard { + background: #222; +} + +.scoreboard td { + height: 400px; +} + +#battlefield { + border: 2px solid green; +} + +.solved { + text-decoration: line-through; +} diff --git a/docs/_site/assets/images/grunge.png b/docs/_site/assets/images/grunge.png new file mode 100644 index 0000000..9a8c41a Binary files /dev/null and b/docs/_site/assets/images/grunge.png differ diff --git a/docs/_site/assets/js/figures.js b/docs/_site/assets/js/figures.js new file mode 100644 index 0000000..27b40be --- /dev/null +++ b/docs/_site/assets/js/figures.js @@ -0,0 +1,5 @@ +default_ = [[300, 150, 50],[["#a08080",[[50, 0.00, 0.14, 1],[30, 0.00, 0.87, 0],[50, 0.00, 0.17, 0],[100, 5.50, 1.75, 1],[100, 0.79, 1.75, 1],[60, 3.14, 3.14, 0],]], ["#808080",[[50, 0.00, 0.12, 1],[30, 0.00, 1.57, 0],]],],[[[75,75,3.86,0.96,2,0], [225,75,4.26,0.49,0,0],], [[73,73,3.86,0.65,2,0], [223,72,4.26,0.68,0,0],], [[69,70,3.86,0.33,2,0], [222,70,4.24,0.87,0,0],], [[65,66,3.86,0.02,2,0], [221,67,4.23,1.06,0,0],], [[61,62,3.86,-0.00,2,0], [220,65,4.22,1.27,0,0],], [[56,59,3.86,0.00,2,0], [218,63,4.20,1.48,0,0],], [[52,55,3.86,-0.00,2,0], [217,60,4.19,1.68,0,0],], [[48,51,3.86,-0.00,2,0], [215,58,4.18,1.88,0,0],], [[44,48,3.86,0.00,2,0], [214,55,4.16,2.09,0,0],], [[39,44,3.86,-0.00,2,0], [213,53,4.15,2.30,0,0],], [[35,41,3.77,0.00,2,0], [211,51,4.13,2.51,0,0],], [[31,38,3.68,-0.00,2,0], [209,48,4.12,2.72,0,0],], [[26,36,3.60,-0.00,2,0], [208,46,4.11,2.93,0,0],], [[21,34,3.51,0.00,2,0], [206,44,4.09,3.14,0,0],], [[16,33,3.43,-0.00,2,0], [205,42,4.08,3.35,0,0],], [[11,32,3.34,-0.00,2,0], [203,39,4.06,3.56,0,0],], [[6,31,3.25,0.00,2,8], [201,37,4.05,3.77,0,0],], [[2,31,3.11,-0.31,2,16], [200,35,4.04,3.98,0,0],], [[299,31,3.25,0.00,2,24], [198,33,4.02,4.19,0,0],], [[293,29,3.39,-0.00,2,8], [196,31,4.01,4.40,0,0],], [[289,28,3.39,-0.31,2,24], [194,29,4.00,4.59,0,0],], [[283,27,3.39,-0.31,2,24], [192,27,3.98,4.80,0,0],], [[276,25,3.39,-0.31,2,24], [190,25,3.97,4.99,0,0],], [[269,23,3.39,-0.30,2,24], [189,23,3.95,5.18,0,0],], [[262,21,3.39,-0.28,2,24], [187,21,3.94,5.39,0,0],], [[255,20,3.39,-0.26,2,24], [185,19,3.93,5.59,0,0],], [[249,18,3.39,-0.24,2,24], [183,17,3.91,5.78,0,0],], [[242,16,3.39,-0.23,2,24], [181,15,3.90,5.99,0,0],], [[235,14,3.39,-0.21,3,25], 0,],]]; + +antlion = [[300, 150, 50],[["#808080",[[50, 0.00, 0.00, 1],[70, 0.00, 0.87, 0],]], ["#ff8844",[[50, 0.00, 0.09, 1],[100, 4.68, 3.09, 1],[100, 1.61, 3.11, 1],[60, 0.00, 2.09, 0],[60, 2.09, 2.09, 0],[60, 4.19, 2.09, 0],[100, 0.00, 0.09, 1],]],],[[[75,75,5.78,2.71,0,0], [225,75,3.28,1.95,0,0],], [[77,73,5.78,3.02,0,0], [225,75,3.28,2.06,0,0],], [[81,71,5.78,3.14,0,0], [225,75,3.28,2.16,0,0],], [[87,68,5.78,3.14,0,0], [225,75,3.28,2.25,0,0],], [[93,64,5.78,3.14,0,0], [225,75,3.28,2.34,0,0],], [[99,61,5.78,3.14,0,0], [225,75,3.28,2.44,0,0],], [[105,57,5.78,3.14,0,0], [225,75,3.28,2.53,0,0],], [[112,54,5.78,3.14,0,0], [225,75,3.28,2.62,0,0],], [[118,51,5.78,3.14,0,0], [225,75,3.28,2.71,0,0],], [[124,47,5.78,3.14,0,0], [225,75,3.28,2.79,0,2],], [[130,44,5.78,3.14,0,0], [225,75,3.28,2.48,0,2],], [[136,40,5.78,3.14,0,0], [225,75,3.28,2.16,0,2],], [[142,37,5.78,3.14,0,0], [225,75,3.28,1.85,0,2],], [[148,34,5.78,3.14,0,0], [225,75,3.28,1.54,0,2],], [[154,30,5.78,3.14,0,0], [225,75,3.28,1.22,0,2],], [[160,28,5.90,3.14,0,0], [225,75,3.28,0.91,0,2],], [[167,25,5.90,3.14,0,0], [225,75,3.28,0.59,0,70],], [[173,23,5.90,3.14,0,0], [225,75,3.28,0.28,0,4],], [[180,20,5.90,3.14,0,0], [225,75,3.28,0.59,0,68],], [[186,17,5.90,3.14,0,0], [225,75,3.28,0.28,0,4],], [[193,15,5.90,3.14,0,0], [225,75,3.28,0.59,0,4],], [[199,12,5.90,3.14,0,0], [225,75,3.28,0.91,0,92],], [[206,10,5.90,3.14,0,0], [222,74,3.24,0.59,0,20],], [[212,7,5.90,3.14,0,0], [218,74,3.15,0.91,0,20],], [[218,4,5.78,3.14,0,0], [212,75,2.96,1.22,0,4],], [[224,1,5.78,3.14,0,0], [208,77,2.77,1.54,0,2],], [[230,147,5.78,3.14,0,0], [207,78,2.65,1.22,0,2],], [[236,144,5.78,3.14,0,0], [207,78,2.65,0.91,0,2],], [[242,140,5.78,3.14,0,0], [207,78,2.65,0.59,0,2],], [[248,137,5.78,3.14,0,0], [207,78,2.65,0.28,0,2],], [[254,134,5.78,3.14,0,0], [207,78,2.65,-0.03,0,2],], [[260,130,5.78,3.14,0,0], [207,78,2.65,-0.35,0,2],], [[267,127,5.78,3.14,0,0], [207,78,2.65,-0.66,0,2],], [[273,123,5.78,3.14,0,0], [207,78,2.65,-0.98,0,2],], [[279,120,5.78,3.14,0,0], [207,78,2.65,-1.29,0,2],], [[285,117,5.78,3.14,0,0], [207,78,2.65,-1.61,0,2],], [[291,113,5.78,3.14,0,0], [207,78,2.65,-1.92,0,2],], [[297,110,5.78,3.14,0,0], [207,78,2.65,-2.23,0,66],], [[3,106,5.78,3.14,0,0], [207,78,2.65,-1.92,0,2],], [[9,103,5.78,3.14,0,0], [207,78,2.65,-2.23,0,2],], [[16,100,5.78,3.14,0,0], [207,78,2.65,-2.55,0,0],], [[22,96,5.78,3.14,0,0], [207,78,2.65,-2.44,0,0],], [[28,93,5.78,3.14,0,0], [207,78,2.65,-2.32,0,0],], [[34,90,5.78,3.14,0,0], [207,78,2.65,-2.20,0,0],], [[40,86,5.78,3.14,0,0], [207,78,2.65,-2.08,0,0],], [[46,84,5.90,3.14,0,0], [207,78,2.65,-1.95,0,0],], [[52,81,5.90,3.14,0,0], [207,78,2.65,-1.85,0,0],], [[59,79,5.90,3.14,0,0], [207,78,2.65,-1.75,0,0],], [[65,76,5.90,3.14,0,0], [207,78,2.65,-1.64,0,0],], [[72,73,5.90,3.14,0,0], [207,78,2.65,-1.54,0,0],], [[78,71,5.90,3.14,0,0], [207,78,2.65,-1.43,0,0],], [[85,68,5.90,3.14,0,0], [207,78,2.65,-1.33,0,0],], [[91,66,5.90,3.14,0,0], [207,78,2.65,-1.20,0,0],], [[98,63,5.90,3.14,0,0], [207,78,2.65,-1.08,0,0],], [[104,60,5.90,3.14,0,0], [207,78,2.65,-0.96,0,4],], [[111,58,5.90,3.14,0,0], [207,78,2.65,-0.65,0,4],], [[117,56,6.03,3.14,0,0], [207,78,2.65,-0.33,0,4],], [[124,54,6.03,3.14,0,0], [207,78,2.65,-0.02,0,4],], [[130,53,6.03,3.14,0,0], [207,78,2.65,0.30,0,4],], [[137,51,6.03,3.14,0,0], [207,78,2.65,0.61,0,4],], [[144,49,6.03,3.14,0,0], [207,78,2.65,0.93,0,70],], [[151,47,6.03,3.14,0,0], [207,78,2.65,0.61,0,28],], [[157,45,6.03,3.14,0,0], [205,79,2.65,0.93,0,28],], [0, [201,81,2.56,1.24,1,85],],]]; + +shortround = [[300, 300, 50],[["#80f0c0",[[50, 0.00, 0.17, 1],[35, 0.00, 1.57, 0],[100, 0.52, 1.03, 0],[100, 5.76, 1.03, 0],[70, 3.14, 3.14, 0],[100, 1.57, 1.03, 0],[100, 4.71, 1.03, 0],[100, 0.00, 0.09, 1],[55, 0.87, 1.55, 0],[55, 5.41, 1.55, 0],]], ["#ff8844",[[50, 0.00, 0.09, 1],[100, 4.68, 3.09, 1],[100, 1.61, 3.11, 1],[60, 0.00, 2.09, 0],[60, 2.09, 2.09, 0],[60, 4.19, 2.09, 0],[100, 0.00, 0.09, 1],]], ["#ff0033",[[50, 0.00, 0.17, 1],[100, 1.57, 2.62, 1],[100, 4.71, 2.62, 1],]], ["#a08080",[[50, 0.00, 0.14, 1],[30, 0.00, 0.87, 0],[50, 0.00, 0.17, 0],[100, 5.50, 1.75, 1],[100, 0.79, 1.75, 1],[60, 3.14, 3.14, 0],]],],[[[75,75,0.87,0.02,2,0], [225,75,0.24,1.41,0,0], [75,225,5.64,2.15,0,0], [225,225,0.35,-0.00,2,0],], [[76,76,0.87,-0.00,2,0], [225,75,0.24,1.50,0,0], [75,225,5.64,1.83,0,0], [227,225,0.35,0.00,2,0],], [[79,80,0.87,0.00,2,0], [225,75,0.24,1.61,0,0], [75,225,5.64,1.52,0,0], [231,227,0.35,-0.00,2,0],], [[83,85,0.87,-0.00,2,0], [225,75,0.24,1.71,0,0], [75,225,5.64,1.20,0,0], [237,229,0.35,-0.00,2,0],], [[87,90,0.87,-0.00,2,0], [225,75,0.24,1.82,0,0], [75,225,5.64,0.89,0,0], [242,231,0.35,0.00,2,0],], [[91,95,0.87,0.00,2,0], [225,75,0.24,1.92,0,0], [75,225,5.64,0.58,0,0], [247,233,0.35,-0.00,2,0],], [[95,100,0.96,-0.00,2,0], [225,75,0.24,2.02,0,0], [75,225,5.64,0.26,0,0], [252,235,0.35,0.00,2,0],], [[98,105,1.05,-0.00,2,0], [225,75,0.24,2.11,0,0], [75,225,5.64,0.00,0,0], [258,237,0.35,-0.00,2,0],], [[101,111,1.13,0.00,2,0], [225,75,0.24,2.20,0,0], [75,225,5.64,-0.00,0,0], [263,239,0.35,-0.00,2,0],], [[103,116,1.13,-0.00,2,0], [225,75,0.24,2.29,0,0], [75,225,5.64,0.00,0,4], [268,240,0.35,0.00,2,8],], [[105,122,1.22,0.00,2,4], [225,75,0.24,2.37,0,0], [75,225,5.64,-0.31,0,4], [272,242,0.28,-0.31,2,24],], [[106,127,1.38,-0.00,2,4], [225,75,0.24,2.46,0,0], [75,225,5.64,-0.63,0,4], [278,243,0.22,-0.30,2,24],], [[106,131,1.63,-0.00,2,4], [225,75,0.24,2.55,0,0], [75,225,5.64,-0.94,0,6], [285,244,0.22,-0.28,2,24],], [[105,134,1.93,0.00,2,140], [225,75,0.24,2.65,0,0], [75,225,5.64,-1.26,0,6], [292,246,0.22,-0.26,2,8],], [[102,138,2.22,-0.00,2,8], [225,75,0.24,2.74,0,0], [75,225,5.64,-1.57,0,6], [296,247,0.22,-0.58,2,24],], [[99,141,2.32,-0.00,2,8], [225,75,0.24,2.83,0,0], [75,225,5.64,-1.88,0,6], [3,248,0.22,-0.58,2,24],], [[97,144,2.15,0.00,2,8], [225,75,0.24,2.91,0,0], [75,225,5.64,-2.20,0,6], [10,250,0.22,-0.56,2,24],], [[96,148,1.88,-0.00,2,140], [225,75,0.24,3.00,0,0], [75,225,5.64,-2.51,0,6], [17,251,0.22,-0.54,2,24],], [[95,153,1.64,-0.00,2,4], [225,75,0.24,3.09,0,0], [75,225,5.64,-2.83,0,6], [24,253,0.22,-0.54,2,24],], [[95,158,1.64,0.00,2,4], [225,75,0.24,3.18,0,0], [75,225,5.64,-3.14,1,3], 0,], [[94,162,1.82,-0.00,2,140], [225,75,0.24,3.26,0,0], [75,225,5.64,-2.83,0,2], 0,], [[92,168,1.97,0.00,2,652], [225,75,0.24,3.37,0,0], [75,225,5.64,-2.51,0,2], 0,], [[89,175,1.97,-0.00,3,653], [225,75,0.24,3.46,0,0], 0, 0,], [[86,181,1.97,-0.00,0,0], [225,75,0.24,3.54,0,0], 0, 0,], [[84,187,1.97,0.00,0,0], [225,75,0.24,3.63,0,0], 0, 0,], [[81,193,1.97,-0.00,0,0], [225,75,0.24,3.72,0,0], 0, 0,], [[78,198,2.05,-0.00,0,0], [225,75,0.24,3.80,0,0], 0, 0,], [[76,204,2.05,0.00,0,0], [225,75,0.24,3.89,0,0], 0, 0,], [[73,209,2.05,-0.00,0,0], [225,75,0.24,3.98,0,0], 0, 0,], [[70,215,2.05,0.00,0,0], [225,75,0.24,4.08,0,0], 0, 0,], [[67,220,2.05,-0.00,0,0], [225,75,0.24,4.19,0,0], 0, 0,], [[64,226,2.05,-0.00,0,0], [225,75,0.24,4.29,0,0], 0, 0,], [[61,231,2.14,0.00,0,0], [225,75,0.24,4.40,0,0], 0, 0,], [[57,237,2.14,-0.00,0,0], [225,75,0.24,4.49,0,0], 0, 0,], [[54,242,2.14,-0.00,0,0], [225,75,0.24,4.57,0,0], 0, 0,], [[50,247,2.14,0.00,0,0], [225,75,0.24,4.66,0,0], 0, 0,], [[47,252,2.14,-0.00,0,0], [225,75,0.24,4.75,0,0], 0, 0,], [[44,258,2.14,-0.00,0,0], [225,75,0.24,4.83,0,0], 0, 0,], [[40,263,2.14,0.00,0,0], [225,75,0.24,4.92,0,0], 0, 0,], [[37,268,2.14,-0.00,0,0], [225,75,0.24,5.01,0,0], 0, 0,], [[33,274,2.14,0.00,0,0], [225,75,0.24,5.10,0,0], 0, 0,], [[30,279,2.23,-0.00,0,0], [225,75,0.24,5.20,0,0], 0, 0,], [[26,284,2.23,-0.00,2,0], [225,75,0.24,5.31,0,0], 0, 0,], [[22,289,2.23,0.00,2,0], [225,75,0.24,5.39,0,0], 0, 0,], [[18,294,2.23,-0.00,2,0], [225,75,0.24,5.48,0,0], 0, 0,], [[14,299,2.23,-0.00,2,0], [225,75,0.24,5.57,0,0], 0, 0,], [[10,3,2.31,0.00,2,0], [225,75,0.24,5.65,0,0], 0, 0,], [[6,8,2.31,-0.00,2,4], [225,75,0.24,5.74,0,2], 0, 0,], [[2,11,2.42,-0.00,2,140], [225,75,0.24,5.43,0,66], 0, 0,], [[297,15,2.46,0.00,2,140], [225,75,0.24,5.74,0,2], 0, 0,], [[291,20,2.46,-0.00,2,140], [225,75,0.24,5.43,0,66], 0, 0,], [[286,24,2.46,0.00,2,140], [225,75,0.24,5.74,0,2], 0, 0,], [[280,29,2.46,-0.00,2,140], [225,75,0.24,5.43,0,66], 0, 0,], [[275,33,2.46,-0.00,2,140], [225,75,0.24,5.74,0,10], 0, 0,], [[270,37,2.46,0.00,2,908], [222,74,0.24,5.43,0,78], 0, 0,], [[264,42,2.46,-0.00,3,397], 0, 0, 0,],]]; \ No newline at end of file diff --git a/docs/_site/assets/js/tanks.js b/docs/_site/assets/js/tanks.js new file mode 100644 index 0000000..45fb827 --- /dev/null +++ b/docs/_site/assets/js/tanks.js @@ -0,0 +1,310 @@ +function dbg(o) { + e = document.getElementById("debug"); + e.innerHTML = o; +} + +function torgba(color, alpha) { + var r = parseInt(color.substring(1,3), 16); + var g = parseInt(color.substring(3,5), 16); + var b = parseInt(color.substring(5,7), 16); + + return "rgba(" + r + "," + g + "," + b + "," + alpha + ")"; +} + +function Tank(ctx, width, height, color, sensors) { + var craterStroke = torgba(color, 0.5); + var craterFill = torgba(color, 0.2); + var sensorStroke = torgba(color, 0.4); + var maxlen = 0; + + this.x = 0; + this.y = 0; + this.rotation = 0; + this.turret = 0; + + this.dead = 0; + + // Do all the yucky math up front + this.sensors = new Array(); + for (i in sensors) { + var s = sensors[i]; + + if (! s) { + this.sensors[i] = [0,0,0,0]; + } else { + // r, angle, width, turret + this.sensors[i] = new Array(); + this.sensors[i][0] = s[0]; + this.sensors[i][1] = s[1] - s[2]/2; + this.sensors[i][2] = s[1] + s[2]/2; + this.sensors[i][3] = s[3]?1:0; + if (s[0] > maxlen) { + maxlen = s[0]; + } + } + } + + // Set up our state, for later interleaved draw requests + this.set_state = function(x, y, rotation, turret, flags, sensor_state) { + this.x = x; + this.y = y; + this.rotation = rotation; + this.turret = turret; + if (flags & 1) { + this.fire = 5; + } + this.led = flags & 2; + this.dead = flags & 4; + this.sensor_state = sensor_state; + } + + this.draw_crater = function() { + if (!this.dead) { + return; + } + + var points = 7; + var angle = Math.PI / points; + + ctx.save(); + 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; + ctx.beginPath(); + ctx.moveTo(12, 0); + for (i = 0; i < points; i += 1) { + ctx.rotate(angle); + ctx.lineTo(6, 0); + ctx.rotate(angle); + ctx.lineTo(12, 0); + } + ctx.closePath() + ctx.stroke(); + ctx.fill(); + + ctx.restore(); + } + + this.draw_sensors = function() { + if (this.dead) { + return; + } + ctx.save(); + ctx.translate(this.x, this.y); + ctx.rotate(this.rotation); + + ctx.lineWidth = 1; + for (i in this.sensors) { + var s = this.sensors[i]; + var adj = this.turret * s[3]; + + if (this.sensor_state & (1 << i)) { + // Sensor is triggered + ctx.strokeStyle = "#000"; + } else { + ctx.strokeStyle = sensorStroke; + } + ctx.beginPath(); + ctx.moveTo(0, 0); + ctx.arc(0, 0, s[0], s[1] + adj, s[2] + adj, false); + ctx.closePath(); + ctx.stroke(); + } + + ctx.restore(); + } + + this.draw_tank = function() { + if (this.dead) { + return; + } + ctx.save(); + ctx.translate(this.x, this.y); + ctx.rotate(this.rotation); + + ctx.fillStyle = color; + ctx.fillRect(-5, -4, 10, 8); + ctx.fillStyle = "#777"; + ctx.fillRect(-7, -9, 15, 5); + ctx.fillRect(-7, 4, 15, 5); + ctx.rotate(this.turret); + if (this.fire) { + this.draw_cannon(); + this.fire -= 1; + } else { + if (this.led) { + ctx.fillStyle = "#f00"; + } else { + ctx.fillStyle = "#000"; + } + ctx.fillRect(0, -1, 10, 2); + } + + ctx.restore(); + } + + this.draw_cannon = function() { + ctx.fillStyle = ("rgba(255,255,64," + this.fire/5 + ")"); + ctx.fillRect(0, -1, 45, 2); + } + + this.draw_wrap_sensors = function() { + var orig_x = this.x; + var orig_y = this.y; + for (x = this.x - width; x < width + maxlen; x += width) { + for (y = this.y - height; y < height + maxlen; y += height) { + if ((-maxlen < x) && (x < width + maxlen) && + (-maxlen < y) && (y < height + maxlen)) { + this.x = x; + this.y = y; + this.draw_sensors(); + } + } + } + this.x = orig_x; + this.y = orig_y; + } +} + +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'); + + canvas.width = game[0][0]; + canvas.height = game[0][1]; + // game[2] is tank descriptions + var turns = game[2]; + + // Set up tanks + var tanks = new Array(); + for (i in game[1]) { + var desc = game[1][i]; + tanks[i] = new Tank(ctx, game[0][0], game[0][1], desc[0], desc[1]); + } + + var frame = 0; + var lastframe = 0; + var fps = document.getElementById('fps'); + + function update_fps() { + fps.innerHTML = (frame - lastframe); + lastframe = frame; + } + + function drawFrame(idx) { + canvas.width = canvas.width; + turn = turns[idx]; + + // Update and draw craters first + for (i in turn) { + t = turn[i]; + if (!t) { + // old data, force-kill it + tanks[i].fire = 0; + tanks[i].dead = 5; + } else { + tanks[i].set_state(t[0], t[1], t[2], t[3], t[4], t[5]); + } + tanks[i].draw_crater(); + } + // Then sensors + for (i in turn) { + tanks[i].draw_wrap_sensors(); + } + // Then tanks + 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('

0

'); + $('#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 + $('').css('left', percent + '%').css('background-color', game[1][i][0]).appendTo(slider); + percent++; + break; + } + } + } + } +} + diff --git a/docs/_site/history.html b/docs/_site/history.html new file mode 100644 index 0000000..58284ab --- /dev/null +++ b/docs/_site/history.html @@ -0,0 +1,117 @@ + + + + + + + + + + + + + by + + + +

History

+ +

This is a port of the “Tanks” program written by Paul Ferrell +pflarr@clanspum.net in 2009-2010. Paul created the entire game based +off a brief description I provided him of +Crobots +and a vague desire to +“make something fun for high school kids to learn some programming.” We +ran Paul’s Tanks as part of a 100-attendee computer security contest in +February of 2010 and by all accounts it was a huge success. It even +made the nightly news.

+ +

Paul’s version was written in Python and provided a custom language +called “Bullet”, which looked like this:

+ +
>addsensor(50, 0, 5, 1);        # 0
+>addsensor(100, 90, 150, 1);    # 1
+>addsensor(100, 270, 150, 1);   # 2
+>addsensor(100, 0, 359, 0);     # 3
+
+# Default movement if nothing is detected
+            : move(70, 70) . turretccw();
+random(2, 3): move(40, 70) . turretccw();
+random(1, 3): move(70, 40) . turretccw();
+
+# We found something!!
+sense(3): move(0, 0);
+sense(1): turretcw();
+sense(2): turretccw();
+sense(0): fire();
+
+
+ + + + + + +
"Chashtank" cleans up.
+ + +
+ +

Nick Moffitt played with this original version and convinced me (Neale) +that something like Forth would be a better language. I added some code +to accept a scaled-down version of PostScript. The IRC channel we +frequent collectively agreed to give this new language the derisive name +“Forf”, which should ideally be followed by punching someone after it is +spoken aloud. I wrote a Python implementation of Forf, which was slow, +and then Adam Glasgall wrote a C implementation, which was quick.

+ +

I decided to take Tanks to Def Con in July 2010, and just for bragging +rights, to have it run on an Asus WL-500gU. This is a $50 device with a +240 MHz MIPS CPU, 16MB RAM, and a 4MB flash disk, along with an +802.11b/g radio, 4-port 10/100 switch, and an additional 10/100 “uplink” +port; it’s sold as a home wireless router. I had originally intended to +run it off a lantern battery just for fun, but eventually thought better +of it: doing so would be wasteful for no good reason.

+ +

Aaron McPhall amcphall@mcphall.org, my summer intern at the time, got +OpenWRT and Python onto the box and benchmarked it at about 60 seconds +for a 16-tank game, after he had profiled the code and optimized a lot +of the math. That wasn’t bad, it meant we could run a reasonably-sized +game at one turn per minute, which we knew from past experience was +about the right rate. But it required a USB thumb drive to hold Python, +and when we used the Python Forf implementation, the run-time shot up to +several minutes. I began this C port while Adam Glasgall, another fool +on the previously-mentioned IRC channel, started work on a C version of +a Forf interpreter.

+ +

This C version with Forf runs about 6 times faster than the Python +version with Bullet, on the WL-500gU. A 1GHz Intel Atom runs a 16-tank +game in about 0.2 seconds.

+ +

What’s so great about Forf?

+ +

Nothing’s great about Forf. It’s a crummy language that only does +integer math. For this application it’s a good choice, for the +following reasons:

+ + + + + + + diff --git a/docs/_site/index.html b/docs/_site/index.html new file mode 100644 index 0000000..5852315 --- /dev/null +++ b/docs/_site/index.html @@ -0,0 +1,70 @@ + + + + + + + + + + + + + by + + + +

Tanks

+ + + + +
"Ant Lion" nails "Rabbit With Gun".
+ + +
+ +

Dirtbags Tanks is a game in which you pit your coding abilities +against other hackers. You write a program for your tank, set it out +on the battlefield, and watch how your program fares against tanks +written by other players. Dirtbags Tanks is frequently a component of +Dirtbags Capture The Flag.

+ +

Each tank has a turret-mounted laser, two treads, up to ten sensors, +and a diagnostic LED. Sensors are used to detect when other tanks are +inside a given arc. In the examples on this page, “triggered” sensors +turn black. Most tanks will take some action if a sensor is +triggered, such as changing speed of the treads, turning the turret, +or firing.

+ +

Tanks are programmed in Forf, a stack-based language similar to +PostScript.

+ +

Other Versions

+ +

Everybody loves tanks! +If you’ve made a port or done something fun with it, +please let me know and I’ll link it here!

+ + + +

Author

+ +

Neale Pickett neale@woozle.org

+ + + + + diff --git a/docs/_site/running.html b/docs/_site/running.html new file mode 100644 index 0000000..67a9e6d --- /dev/null +++ b/docs/_site/running.html @@ -0,0 +1,89 @@ + + + + + + + + + by + + + +

Running Tanks

+ +

Unfortunately, it’s kind of a mess right now. +I know there are a few forks of this code, +and I would love it if someone proposed a merge to clearly illustrate how to run tanks.

+ +

When I spin up a new tanks game, +typically I run something like:

+ +
while sleep 60; do ./round.sh */; done
+
+
+ +

This assumes all your tanks directories are in the same place as round.sh.

+ +

Included programs

+ +

I tried to stick with the Unix philosophy of one program per task. I +also tried to avoid doing any string processing in C. The result is a +hodgepodge of C, Bourne shell, and awk, but at least each piece is +fairly simple to audit.

+ +

round.sh tank1 tank2 …

+ +

Runs a single round, awards points with rank.awk, and creates a new +summary.html with summary.awk. This is the main interface that you want +to run from cron or whatever.

+ +

forftanks tank1 tank2 …

+ +

A program to run a round of tanks and output a JSON description of the +game. This is what tanks.js uses to render a game graphically. +The object printed contains:

+ +
[[game-width, game-height],
+ [[tank1-color, 
+  [[sensor1range, sensor1angle, sensor1width, sensor1turret],
+   ...]],
+  ...],
+ [[
+  [tank1x, tank1y, tank1angle, tank1sensangle, 
+   tank1flags, tank1sensors],
+  ...],
+ ...]]
+
+
+ +

If file descriptor 3 is open for writes, it also outputs the results of +the round to fd3.

+ +

rank.awk

+ +

Processes the fd3 output of forftanks to award points and output an +HTML results table.

+ +

summary.awk tank1 tank2

+ +

Creates summary.html, linking to all rounds and showing overall +standing.

+ +

designer.cgi

+ +

Accepts form input and writes a tank.

+ + + + + + diff --git a/docs/_site/standie.svg b/docs/_site/standie.svg new file mode 100644 index 0000000..76e6875 --- /dev/null +++ b/docs/_site/standie.svg @@ -0,0 +1,260 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + dirtbags + + + + + + + + + + + + + + diff --git a/docs/_site/thanks.html b/docs/_site/thanks.html new file mode 100644 index 0000000..53d1beb --- /dev/null +++ b/docs/_site/thanks.html @@ -0,0 +1,37 @@ + + + + + + + + + by + + + +

thanks

+ + + + + + + diff --git a/docs/_site/token.svg b/docs/_site/token.svg new file mode 100644 index 0000000..4cb6bb4 --- /dev/null +++ b/docs/_site/token.svg @@ -0,0 +1,1897 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + dirtbags! + + + + + + + + + + + + + essid: tankshttp://192.168.1.1/password: + + + + + + + + + + + dirtbags! + + + + + + + + + + + + + essid: tankshttp://192.168.1.1/password: + + + + + + + + + + + dirtbags! + + + + + + + + + + + + + essid: tankshttp://192.168.1.1/password: + + + + + + + + + + + dirtbags! + + + + + + + + + + + + + essid: tankshttp://192.168.1.1/password: + + + + + + + + + + + dirtbags! + + + + + + + + + + + + + essid: tankshttp://192.168.1.1/password: + + + + + + + + + + + dirtbags! + + + + + + + + + + + + + essid: tankshttp://192.168.1.1/password: + + + + + + + + + + + dirtbags! + + + + + + + + + + + + + essid: tankshttp://192.168.1.1/password: + + + + + + + + + + + dirtbags! + + + + + + + + + + + + + essid: tankshttp://192.168.1.1/password: + + + + + + + + + + + dirtbags! + + + + + + + + + + + + + essid: tankshttp://192.168.1.1/password: + + + + + + + + + + + dirtbags! + + + + + + + + + + + + + essid: tankshttp://192.168.1.1/password: + + + diff --git a/docs/assets/css/dirtbags.css b/docs/assets/css/dirtbags.css new file mode 100644 index 0000000..6a86e06 --- /dev/null +++ b/docs/assets/css/dirtbags.css @@ -0,0 +1,151 @@ +/**** document ****/ + +html { + background: #eed url(/assets/images/grunge.png) repeat-x; +} + +body { + font-family: sans-serif; + color: #112; + padding: 10px; + max-width: 700px; +} + +/**** heading ****/ + +#title { + text-transform: lowercase; + font-size: 1.6em; + padding: 3px; + margin: 0 0 1em 2em; +} + +#title:before { + color: #999; + letter-spacing: -0.1em; + content: "Dirtbags: "; +} + +/*** left side bar ***/ + +nav h2 { + display: none; +} + +nav ul { + list-style: none; + text-align: center; +} + +nav li { + display: inline; +} + +nav li a { + text-transform: lowercase; + font-size: 0.9em; +} + +nav li + li:before { + content: " | "; +} + + +/**** body ****/ + +a img { + border: 0px; +} + +a { + text-decoration: none; + color: #2a4; + font-weight: bold; +} + +a:hover { + color: #ddc; + background: #2a4; +} + + +h1, h2, h3 { + color: #464; + letter-spacing: -0.05em; +} + +.readme { + background-color: #ccc; + margin: 1em; +} + +pre { + background-color: #ccc; + border: solid #888 2px; + padding: 0.25em; +} + + +th { + vertical-align: top; + text-align: center; +} +td { + vertical-align: top; + text-align: right; +} + +p { + line-height: 1.4em; + margin-bottom: 20px; +} + +hr { + border: 1px solid #444; +} + +dt { + white-space: pre; + background-color: #333; + padding: 5px; + border: 2px solid green; + border-bottom: none; + font-weight: bold; +} + +dd { + border: 2px solid green; + margin: 0px; + padding: 5px; + background-color: #282828; +} + + +/**** special cases ****/ + +.wide { + max-width: inherit; +} + +.figure { + margin: 0.5em 1em; + float: right; + font-size: small; + text-align: center; +} + +.scoreboard { + background: #222; +} + +.scoreboard td { + height: 400px; +} + +#battlefield { + border: 2px solid green; +} + +.solved { + text-decoration: line-through; +} diff --git a/docs/assets/images/grunge.png b/docs/assets/images/grunge.png new file mode 100644 index 0000000..9a8c41a Binary files /dev/null and b/docs/assets/images/grunge.png differ diff --git a/docs/assets/js/figures.js b/docs/assets/js/figures.js new file mode 100644 index 0000000..27b40be --- /dev/null +++ b/docs/assets/js/figures.js @@ -0,0 +1,5 @@ +default_ = [[300, 150, 50],[["#a08080",[[50, 0.00, 0.14, 1],[30, 0.00, 0.87, 0],[50, 0.00, 0.17, 0],[100, 5.50, 1.75, 1],[100, 0.79, 1.75, 1],[60, 3.14, 3.14, 0],]], ["#808080",[[50, 0.00, 0.12, 1],[30, 0.00, 1.57, 0],]],],[[[75,75,3.86,0.96,2,0], [225,75,4.26,0.49,0,0],], [[73,73,3.86,0.65,2,0], [223,72,4.26,0.68,0,0],], [[69,70,3.86,0.33,2,0], [222,70,4.24,0.87,0,0],], [[65,66,3.86,0.02,2,0], [221,67,4.23,1.06,0,0],], [[61,62,3.86,-0.00,2,0], [220,65,4.22,1.27,0,0],], [[56,59,3.86,0.00,2,0], [218,63,4.20,1.48,0,0],], [[52,55,3.86,-0.00,2,0], [217,60,4.19,1.68,0,0],], [[48,51,3.86,-0.00,2,0], [215,58,4.18,1.88,0,0],], [[44,48,3.86,0.00,2,0], [214,55,4.16,2.09,0,0],], [[39,44,3.86,-0.00,2,0], [213,53,4.15,2.30,0,0],], [[35,41,3.77,0.00,2,0], [211,51,4.13,2.51,0,0],], [[31,38,3.68,-0.00,2,0], [209,48,4.12,2.72,0,0],], [[26,36,3.60,-0.00,2,0], [208,46,4.11,2.93,0,0],], [[21,34,3.51,0.00,2,0], [206,44,4.09,3.14,0,0],], [[16,33,3.43,-0.00,2,0], [205,42,4.08,3.35,0,0],], [[11,32,3.34,-0.00,2,0], [203,39,4.06,3.56,0,0],], [[6,31,3.25,0.00,2,8], [201,37,4.05,3.77,0,0],], [[2,31,3.11,-0.31,2,16], [200,35,4.04,3.98,0,0],], [[299,31,3.25,0.00,2,24], [198,33,4.02,4.19,0,0],], [[293,29,3.39,-0.00,2,8], [196,31,4.01,4.40,0,0],], [[289,28,3.39,-0.31,2,24], [194,29,4.00,4.59,0,0],], [[283,27,3.39,-0.31,2,24], [192,27,3.98,4.80,0,0],], [[276,25,3.39,-0.31,2,24], [190,25,3.97,4.99,0,0],], [[269,23,3.39,-0.30,2,24], [189,23,3.95,5.18,0,0],], [[262,21,3.39,-0.28,2,24], [187,21,3.94,5.39,0,0],], [[255,20,3.39,-0.26,2,24], [185,19,3.93,5.59,0,0],], [[249,18,3.39,-0.24,2,24], [183,17,3.91,5.78,0,0],], [[242,16,3.39,-0.23,2,24], [181,15,3.90,5.99,0,0],], [[235,14,3.39,-0.21,3,25], 0,],]]; + +antlion = [[300, 150, 50],[["#808080",[[50, 0.00, 0.00, 1],[70, 0.00, 0.87, 0],]], ["#ff8844",[[50, 0.00, 0.09, 1],[100, 4.68, 3.09, 1],[100, 1.61, 3.11, 1],[60, 0.00, 2.09, 0],[60, 2.09, 2.09, 0],[60, 4.19, 2.09, 0],[100, 0.00, 0.09, 1],]],],[[[75,75,5.78,2.71,0,0], [225,75,3.28,1.95,0,0],], [[77,73,5.78,3.02,0,0], [225,75,3.28,2.06,0,0],], [[81,71,5.78,3.14,0,0], [225,75,3.28,2.16,0,0],], [[87,68,5.78,3.14,0,0], [225,75,3.28,2.25,0,0],], [[93,64,5.78,3.14,0,0], [225,75,3.28,2.34,0,0],], [[99,61,5.78,3.14,0,0], [225,75,3.28,2.44,0,0],], [[105,57,5.78,3.14,0,0], [225,75,3.28,2.53,0,0],], [[112,54,5.78,3.14,0,0], [225,75,3.28,2.62,0,0],], [[118,51,5.78,3.14,0,0], [225,75,3.28,2.71,0,0],], [[124,47,5.78,3.14,0,0], [225,75,3.28,2.79,0,2],], [[130,44,5.78,3.14,0,0], [225,75,3.28,2.48,0,2],], [[136,40,5.78,3.14,0,0], [225,75,3.28,2.16,0,2],], [[142,37,5.78,3.14,0,0], [225,75,3.28,1.85,0,2],], [[148,34,5.78,3.14,0,0], [225,75,3.28,1.54,0,2],], [[154,30,5.78,3.14,0,0], [225,75,3.28,1.22,0,2],], [[160,28,5.90,3.14,0,0], [225,75,3.28,0.91,0,2],], [[167,25,5.90,3.14,0,0], [225,75,3.28,0.59,0,70],], [[173,23,5.90,3.14,0,0], [225,75,3.28,0.28,0,4],], [[180,20,5.90,3.14,0,0], [225,75,3.28,0.59,0,68],], [[186,17,5.90,3.14,0,0], [225,75,3.28,0.28,0,4],], [[193,15,5.90,3.14,0,0], [225,75,3.28,0.59,0,4],], [[199,12,5.90,3.14,0,0], [225,75,3.28,0.91,0,92],], [[206,10,5.90,3.14,0,0], [222,74,3.24,0.59,0,20],], [[212,7,5.90,3.14,0,0], [218,74,3.15,0.91,0,20],], [[218,4,5.78,3.14,0,0], [212,75,2.96,1.22,0,4],], [[224,1,5.78,3.14,0,0], [208,77,2.77,1.54,0,2],], [[230,147,5.78,3.14,0,0], [207,78,2.65,1.22,0,2],], [[236,144,5.78,3.14,0,0], [207,78,2.65,0.91,0,2],], [[242,140,5.78,3.14,0,0], [207,78,2.65,0.59,0,2],], [[248,137,5.78,3.14,0,0], [207,78,2.65,0.28,0,2],], [[254,134,5.78,3.14,0,0], [207,78,2.65,-0.03,0,2],], [[260,130,5.78,3.14,0,0], [207,78,2.65,-0.35,0,2],], [[267,127,5.78,3.14,0,0], [207,78,2.65,-0.66,0,2],], [[273,123,5.78,3.14,0,0], [207,78,2.65,-0.98,0,2],], [[279,120,5.78,3.14,0,0], [207,78,2.65,-1.29,0,2],], [[285,117,5.78,3.14,0,0], [207,78,2.65,-1.61,0,2],], [[291,113,5.78,3.14,0,0], [207,78,2.65,-1.92,0,2],], [[297,110,5.78,3.14,0,0], [207,78,2.65,-2.23,0,66],], [[3,106,5.78,3.14,0,0], [207,78,2.65,-1.92,0,2],], [[9,103,5.78,3.14,0,0], [207,78,2.65,-2.23,0,2],], [[16,100,5.78,3.14,0,0], [207,78,2.65,-2.55,0,0],], [[22,96,5.78,3.14,0,0], [207,78,2.65,-2.44,0,0],], [[28,93,5.78,3.14,0,0], [207,78,2.65,-2.32,0,0],], [[34,90,5.78,3.14,0,0], [207,78,2.65,-2.20,0,0],], [[40,86,5.78,3.14,0,0], [207,78,2.65,-2.08,0,0],], [[46,84,5.90,3.14,0,0], [207,78,2.65,-1.95,0,0],], [[52,81,5.90,3.14,0,0], [207,78,2.65,-1.85,0,0],], [[59,79,5.90,3.14,0,0], [207,78,2.65,-1.75,0,0],], [[65,76,5.90,3.14,0,0], [207,78,2.65,-1.64,0,0],], [[72,73,5.90,3.14,0,0], [207,78,2.65,-1.54,0,0],], [[78,71,5.90,3.14,0,0], [207,78,2.65,-1.43,0,0],], [[85,68,5.90,3.14,0,0], [207,78,2.65,-1.33,0,0],], [[91,66,5.90,3.14,0,0], [207,78,2.65,-1.20,0,0],], [[98,63,5.90,3.14,0,0], [207,78,2.65,-1.08,0,0],], [[104,60,5.90,3.14,0,0], [207,78,2.65,-0.96,0,4],], [[111,58,5.90,3.14,0,0], [207,78,2.65,-0.65,0,4],], [[117,56,6.03,3.14,0,0], [207,78,2.65,-0.33,0,4],], [[124,54,6.03,3.14,0,0], [207,78,2.65,-0.02,0,4],], [[130,53,6.03,3.14,0,0], [207,78,2.65,0.30,0,4],], [[137,51,6.03,3.14,0,0], [207,78,2.65,0.61,0,4],], [[144,49,6.03,3.14,0,0], [207,78,2.65,0.93,0,70],], [[151,47,6.03,3.14,0,0], [207,78,2.65,0.61,0,28],], [[157,45,6.03,3.14,0,0], [205,79,2.65,0.93,0,28],], [0, [201,81,2.56,1.24,1,85],],]]; + +shortround = [[300, 300, 50],[["#80f0c0",[[50, 0.00, 0.17, 1],[35, 0.00, 1.57, 0],[100, 0.52, 1.03, 0],[100, 5.76, 1.03, 0],[70, 3.14, 3.14, 0],[100, 1.57, 1.03, 0],[100, 4.71, 1.03, 0],[100, 0.00, 0.09, 1],[55, 0.87, 1.55, 0],[55, 5.41, 1.55, 0],]], ["#ff8844",[[50, 0.00, 0.09, 1],[100, 4.68, 3.09, 1],[100, 1.61, 3.11, 1],[60, 0.00, 2.09, 0],[60, 2.09, 2.09, 0],[60, 4.19, 2.09, 0],[100, 0.00, 0.09, 1],]], ["#ff0033",[[50, 0.00, 0.17, 1],[100, 1.57, 2.62, 1],[100, 4.71, 2.62, 1],]], ["#a08080",[[50, 0.00, 0.14, 1],[30, 0.00, 0.87, 0],[50, 0.00, 0.17, 0],[100, 5.50, 1.75, 1],[100, 0.79, 1.75, 1],[60, 3.14, 3.14, 0],]],],[[[75,75,0.87,0.02,2,0], [225,75,0.24,1.41,0,0], [75,225,5.64,2.15,0,0], [225,225,0.35,-0.00,2,0],], [[76,76,0.87,-0.00,2,0], [225,75,0.24,1.50,0,0], [75,225,5.64,1.83,0,0], [227,225,0.35,0.00,2,0],], [[79,80,0.87,0.00,2,0], [225,75,0.24,1.61,0,0], [75,225,5.64,1.52,0,0], [231,227,0.35,-0.00,2,0],], [[83,85,0.87,-0.00,2,0], [225,75,0.24,1.71,0,0], [75,225,5.64,1.20,0,0], [237,229,0.35,-0.00,2,0],], [[87,90,0.87,-0.00,2,0], [225,75,0.24,1.82,0,0], [75,225,5.64,0.89,0,0], [242,231,0.35,0.00,2,0],], [[91,95,0.87,0.00,2,0], [225,75,0.24,1.92,0,0], [75,225,5.64,0.58,0,0], [247,233,0.35,-0.00,2,0],], [[95,100,0.96,-0.00,2,0], [225,75,0.24,2.02,0,0], [75,225,5.64,0.26,0,0], [252,235,0.35,0.00,2,0],], [[98,105,1.05,-0.00,2,0], [225,75,0.24,2.11,0,0], [75,225,5.64,0.00,0,0], [258,237,0.35,-0.00,2,0],], [[101,111,1.13,0.00,2,0], [225,75,0.24,2.20,0,0], [75,225,5.64,-0.00,0,0], [263,239,0.35,-0.00,2,0],], [[103,116,1.13,-0.00,2,0], [225,75,0.24,2.29,0,0], [75,225,5.64,0.00,0,4], [268,240,0.35,0.00,2,8],], [[105,122,1.22,0.00,2,4], [225,75,0.24,2.37,0,0], [75,225,5.64,-0.31,0,4], [272,242,0.28,-0.31,2,24],], [[106,127,1.38,-0.00,2,4], [225,75,0.24,2.46,0,0], [75,225,5.64,-0.63,0,4], [278,243,0.22,-0.30,2,24],], [[106,131,1.63,-0.00,2,4], [225,75,0.24,2.55,0,0], [75,225,5.64,-0.94,0,6], [285,244,0.22,-0.28,2,24],], [[105,134,1.93,0.00,2,140], [225,75,0.24,2.65,0,0], [75,225,5.64,-1.26,0,6], [292,246,0.22,-0.26,2,8],], [[102,138,2.22,-0.00,2,8], [225,75,0.24,2.74,0,0], [75,225,5.64,-1.57,0,6], [296,247,0.22,-0.58,2,24],], [[99,141,2.32,-0.00,2,8], [225,75,0.24,2.83,0,0], [75,225,5.64,-1.88,0,6], [3,248,0.22,-0.58,2,24],], [[97,144,2.15,0.00,2,8], [225,75,0.24,2.91,0,0], [75,225,5.64,-2.20,0,6], [10,250,0.22,-0.56,2,24],], [[96,148,1.88,-0.00,2,140], [225,75,0.24,3.00,0,0], [75,225,5.64,-2.51,0,6], [17,251,0.22,-0.54,2,24],], [[95,153,1.64,-0.00,2,4], [225,75,0.24,3.09,0,0], [75,225,5.64,-2.83,0,6], [24,253,0.22,-0.54,2,24],], [[95,158,1.64,0.00,2,4], [225,75,0.24,3.18,0,0], [75,225,5.64,-3.14,1,3], 0,], [[94,162,1.82,-0.00,2,140], [225,75,0.24,3.26,0,0], [75,225,5.64,-2.83,0,2], 0,], [[92,168,1.97,0.00,2,652], [225,75,0.24,3.37,0,0], [75,225,5.64,-2.51,0,2], 0,], [[89,175,1.97,-0.00,3,653], [225,75,0.24,3.46,0,0], 0, 0,], [[86,181,1.97,-0.00,0,0], [225,75,0.24,3.54,0,0], 0, 0,], [[84,187,1.97,0.00,0,0], [225,75,0.24,3.63,0,0], 0, 0,], [[81,193,1.97,-0.00,0,0], [225,75,0.24,3.72,0,0], 0, 0,], [[78,198,2.05,-0.00,0,0], [225,75,0.24,3.80,0,0], 0, 0,], [[76,204,2.05,0.00,0,0], [225,75,0.24,3.89,0,0], 0, 0,], [[73,209,2.05,-0.00,0,0], [225,75,0.24,3.98,0,0], 0, 0,], [[70,215,2.05,0.00,0,0], [225,75,0.24,4.08,0,0], 0, 0,], [[67,220,2.05,-0.00,0,0], [225,75,0.24,4.19,0,0], 0, 0,], [[64,226,2.05,-0.00,0,0], [225,75,0.24,4.29,0,0], 0, 0,], [[61,231,2.14,0.00,0,0], [225,75,0.24,4.40,0,0], 0, 0,], [[57,237,2.14,-0.00,0,0], [225,75,0.24,4.49,0,0], 0, 0,], [[54,242,2.14,-0.00,0,0], [225,75,0.24,4.57,0,0], 0, 0,], [[50,247,2.14,0.00,0,0], [225,75,0.24,4.66,0,0], 0, 0,], [[47,252,2.14,-0.00,0,0], [225,75,0.24,4.75,0,0], 0, 0,], [[44,258,2.14,-0.00,0,0], [225,75,0.24,4.83,0,0], 0, 0,], [[40,263,2.14,0.00,0,0], [225,75,0.24,4.92,0,0], 0, 0,], [[37,268,2.14,-0.00,0,0], [225,75,0.24,5.01,0,0], 0, 0,], [[33,274,2.14,0.00,0,0], [225,75,0.24,5.10,0,0], 0, 0,], [[30,279,2.23,-0.00,0,0], [225,75,0.24,5.20,0,0], 0, 0,], [[26,284,2.23,-0.00,2,0], [225,75,0.24,5.31,0,0], 0, 0,], [[22,289,2.23,0.00,2,0], [225,75,0.24,5.39,0,0], 0, 0,], [[18,294,2.23,-0.00,2,0], [225,75,0.24,5.48,0,0], 0, 0,], [[14,299,2.23,-0.00,2,0], [225,75,0.24,5.57,0,0], 0, 0,], [[10,3,2.31,0.00,2,0], [225,75,0.24,5.65,0,0], 0, 0,], [[6,8,2.31,-0.00,2,4], [225,75,0.24,5.74,0,2], 0, 0,], [[2,11,2.42,-0.00,2,140], [225,75,0.24,5.43,0,66], 0, 0,], [[297,15,2.46,0.00,2,140], [225,75,0.24,5.74,0,2], 0, 0,], [[291,20,2.46,-0.00,2,140], [225,75,0.24,5.43,0,66], 0, 0,], [[286,24,2.46,0.00,2,140], [225,75,0.24,5.74,0,2], 0, 0,], [[280,29,2.46,-0.00,2,140], [225,75,0.24,5.43,0,66], 0, 0,], [[275,33,2.46,-0.00,2,140], [225,75,0.24,5.74,0,10], 0, 0,], [[270,37,2.46,0.00,2,908], [222,74,0.24,5.43,0,78], 0, 0,], [[264,42,2.46,-0.00,3,397], 0, 0, 0,],]]; \ No newline at end of file diff --git a/docs/assets/js/tanks.js b/docs/assets/js/tanks.js new file mode 100644 index 0000000..45fb827 --- /dev/null +++ b/docs/assets/js/tanks.js @@ -0,0 +1,310 @@ +function dbg(o) { + e = document.getElementById("debug"); + e.innerHTML = o; +} + +function torgba(color, alpha) { + var r = parseInt(color.substring(1,3), 16); + var g = parseInt(color.substring(3,5), 16); + var b = parseInt(color.substring(5,7), 16); + + return "rgba(" + r + "," + g + "," + b + "," + alpha + ")"; +} + +function Tank(ctx, width, height, color, sensors) { + var craterStroke = torgba(color, 0.5); + var craterFill = torgba(color, 0.2); + var sensorStroke = torgba(color, 0.4); + var maxlen = 0; + + this.x = 0; + this.y = 0; + this.rotation = 0; + this.turret = 0; + + this.dead = 0; + + // Do all the yucky math up front + this.sensors = new Array(); + for (i in sensors) { + var s = sensors[i]; + + if (! s) { + this.sensors[i] = [0,0,0,0]; + } else { + // r, angle, width, turret + this.sensors[i] = new Array(); + this.sensors[i][0] = s[0]; + this.sensors[i][1] = s[1] - s[2]/2; + this.sensors[i][2] = s[1] + s[2]/2; + this.sensors[i][3] = s[3]?1:0; + if (s[0] > maxlen) { + maxlen = s[0]; + } + } + } + + // Set up our state, for later interleaved draw requests + this.set_state = function(x, y, rotation, turret, flags, sensor_state) { + this.x = x; + this.y = y; + this.rotation = rotation; + this.turret = turret; + if (flags & 1) { + this.fire = 5; + } + this.led = flags & 2; + this.dead = flags & 4; + this.sensor_state = sensor_state; + } + + this.draw_crater = function() { + if (!this.dead) { + return; + } + + var points = 7; + var angle = Math.PI / points; + + ctx.save(); + 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; + ctx.beginPath(); + ctx.moveTo(12, 0); + for (i = 0; i < points; i += 1) { + ctx.rotate(angle); + ctx.lineTo(6, 0); + ctx.rotate(angle); + ctx.lineTo(12, 0); + } + ctx.closePath() + ctx.stroke(); + ctx.fill(); + + ctx.restore(); + } + + this.draw_sensors = function() { + if (this.dead) { + return; + } + ctx.save(); + ctx.translate(this.x, this.y); + ctx.rotate(this.rotation); + + ctx.lineWidth = 1; + for (i in this.sensors) { + var s = this.sensors[i]; + var adj = this.turret * s[3]; + + if (this.sensor_state & (1 << i)) { + // Sensor is triggered + ctx.strokeStyle = "#000"; + } else { + ctx.strokeStyle = sensorStroke; + } + ctx.beginPath(); + ctx.moveTo(0, 0); + ctx.arc(0, 0, s[0], s[1] + adj, s[2] + adj, false); + ctx.closePath(); + ctx.stroke(); + } + + ctx.restore(); + } + + this.draw_tank = function() { + if (this.dead) { + return; + } + ctx.save(); + ctx.translate(this.x, this.y); + ctx.rotate(this.rotation); + + ctx.fillStyle = color; + ctx.fillRect(-5, -4, 10, 8); + ctx.fillStyle = "#777"; + ctx.fillRect(-7, -9, 15, 5); + ctx.fillRect(-7, 4, 15, 5); + ctx.rotate(this.turret); + if (this.fire) { + this.draw_cannon(); + this.fire -= 1; + } else { + if (this.led) { + ctx.fillStyle = "#f00"; + } else { + ctx.fillStyle = "#000"; + } + ctx.fillRect(0, -1, 10, 2); + } + + ctx.restore(); + } + + this.draw_cannon = function() { + ctx.fillStyle = ("rgba(255,255,64," + this.fire/5 + ")"); + ctx.fillRect(0, -1, 45, 2); + } + + this.draw_wrap_sensors = function() { + var orig_x = this.x; + var orig_y = this.y; + for (x = this.x - width; x < width + maxlen; x += width) { + for (y = this.y - height; y < height + maxlen; y += height) { + if ((-maxlen < x) && (x < width + maxlen) && + (-maxlen < y) && (y < height + maxlen)) { + this.x = x; + this.y = y; + this.draw_sensors(); + } + } + } + this.x = orig_x; + this.y = orig_y; + } +} + +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'); + + canvas.width = game[0][0]; + canvas.height = game[0][1]; + // game[2] is tank descriptions + var turns = game[2]; + + // Set up tanks + var tanks = new Array(); + for (i in game[1]) { + var desc = game[1][i]; + tanks[i] = new Tank(ctx, game[0][0], game[0][1], desc[0], desc[1]); + } + + var frame = 0; + var lastframe = 0; + var fps = document.getElementById('fps'); + + function update_fps() { + fps.innerHTML = (frame - lastframe); + lastframe = frame; + } + + function drawFrame(idx) { + canvas.width = canvas.width; + turn = turns[idx]; + + // Update and draw craters first + for (i in turn) { + t = turn[i]; + if (!t) { + // old data, force-kill it + tanks[i].fire = 0; + tanks[i].dead = 5; + } else { + tanks[i].set_state(t[0], t[1], t[2], t[3], t[4], t[5]); + } + tanks[i].draw_crater(); + } + // Then sensors + for (i in turn) { + tanks[i].draw_wrap_sensors(); + } + // Then tanks + 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('

0

'); + $('#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 + $('').css('left', percent + '%').css('background-color', game[1][i][0]).appendTo(slider); + percent++; + break; + } + } + } + } +} + diff --git a/docs/forf.html.m4 b/docs/forf.html.m4 new file mode 100644 index 0000000..65a4de5 --- /dev/null +++ b/docs/forf.html.m4 @@ -0,0 +1,13 @@ + + + + Forf Manual + + + + +syscmd(markdown forf.txt) +include(nav.html.inc) + + + diff --git a/docs/history.md b/docs/history.md index 3873dbf..d94efc3 100644 --- a/docs/history.md +++ b/docs/history.md @@ -1,4 +1,9 @@ -# History +--- +title: History +scripts: + - assets/js/tanks.js + - assets/js/figures.js +--- This is a port of the "Tanks" program written by Paul Ferrell in 2009-2010. Paul created the entire game based @@ -29,6 +34,18 @@ called "Bullet", which looked like this: sense(2): turretccw(); sense(0): fire(); + + + + + +
"Chashtank" cleans up.
+ + +
+ Nick Moffitt played with this original version and convinced me (Neale) that something like Forth would be a better language. I added some code to accept a scaled-down version of PostScript. The IRC channel we diff --git a/docs/intro.html.m4 b/docs/intro.html.m4 new file mode 100644 index 0000000..6d31e1f --- /dev/null +++ b/docs/intro.html.m4 @@ -0,0 +1,147 @@ + + + + Tanks Introduction + + + + + + +

Tanks Introduction

+ + + + + + +
"ChashTank" dominates this short round.
+ + +
+ +

+ Tanks is a game in which you pit your coding abilities against + other hackers. You write a program for your tank, set it out on + the battlefield, and watch how it fares against other tanks while + running your program. +

+ +

+ Each tank has a turret-mounted laser, two treads, up to ten + sensors, and a diagnostic LED. Sensors are used to detect when + other tanks are inside a given arc. In the examples on this page, + "triggered" sensors turn black. Most tanks will take some action + if a sensor is triggered, such as changing speed of the treads, + turning the turret, or firing. +

+ +

+ Tanks are programmed in Forf, a stack-based language similar to + PostScript. Please read the Forf manual + to learn more about forf, and the Tanks + procedure reference for a description of Tanks extensions. +

+ +

Quick Start for the Impatient

+ + + + + + +
"Crashmaster" pwns the lame default tank provided in this + section.
+ + +
+ +

+ To get started, head over to the Tank + Debugger and enter the following example tank. This tank will + move around, turn the turret, and fire if there's something in + front of it. +

+ +
+Sensor 0: 50 0 7 ☑
+Sensor 1: 30 0 90 ☐
+
+get-turret 12 + set-turret!         ( Rotate turret )
+37 40 set-speed!                    ( Go in circles )
+0 sensor? { fire! } if              ( Fire if turret sensor triggered )
+1 sensor? { -50 50 set-speed! } if  ( Turn if collision sensor triggered )
+    
+ +

+ Obviously, this tank could be improved. Studying the examples on + this page should give you ideas about how to make a better tank. + Don't forget the Forf manual and the + Tank procedure reference. +

+ +

Tank Specifications

+ + + + + + +
"Ant Lion" nails "Rabbit With Gun".
+ + +
+ +

+ Your PF-255 autonomous tank is built to the exacting + specifications sent to our factory in New Khavistan. All + distances are in meters, angles in degrees. +

+ +
+
Tank size
+
+ The targettable area of the tank—the part which can be hit by a + cannon—is a circle about 7½ meters in radius. +
+ +
Speed
+
+ Each tread can have a speed between -100 and 100. This is in + percentage of total speed for that tread, where total speed is + roughly 7 meters per turn. +
+ +
Sensors
+
+ Each sensor has a maximum range of 100 meters. Of course, you + don't have to use the full range. Sensors may be attached to + the turret (they turn along with the turret), or left fixed to + the tank. +
+ +
Turret
+
+ Turret angle can be set between -359° and 359°, with 0° directly + in front of the tank. Be aware that it takes time for the + turret to swing around: the turret can swing about 45° per turn. +
+ +
Cannon range and recharging
+
+ When the cannon is fired, it obliterates everything for 50 + meters in front of it. It takes around 20 turns for your cannon + to recharge after it's been fired, so only shoot when you feel + like you're going to hit something. +
+
+ + Good luck blowing everybody up! +include(nav.html.inc) + diff --git a/docs/intro.md b/docs/intro.md deleted file mode 100644 index add5033..0000000 --- a/docs/intro.md +++ /dev/null @@ -1,72 +0,0 @@ -# Tanks Introduction - -Tanks is a game in which you pit your coding abilities against -other hackers. You write a program for your tank, set it out on -the battlefield, and watch how it fares against other tanks while -running your program. - -Each tank has a turret-mounted laser, two treads, up to ten -sensors, and a diagnostic LED. Sensors are used to detect when -other tanks are inside a given arc. In the examples on this page, -"triggered" sensors turn black. Most tanks will take some action -if a sensor is triggered, such as changing speed of the treads, -turning the turret, or firing. - -Tanks are programmed in Forf, a stack-based language similar to -PostScript. Please read the [Forf manual](forf.md) to learn more -about forf, and the [Tanks procedure reference](procs.html) for a -description of Tanks extensions. - -## Quick Start for the Impatient - -To get started, head over to the designer for your game, -and use the following example tank. This tank will -move around, turn the turret, and fire if there's something in -front of it. - - Sensor 0: 50 0 7 ☑ - Sensor 1: 30 0 90 ☐ - - get-turret 12 + set-turret! ( Rotate turret ) - 37 40 set-speed! ( Go in circles ) - 0 sensor? { fire! } if ( Fire if turret sensor triggered ) - 1 sensor? { -50 50 set-speed! } if ( Turn if collision sensor triggered ) - -Obviously, this tank could be improved. -Watch other tanks in your game to get ideas about how to improve yours. -Don't forget the [Forf manual](forf.md) and the -[Tank procedure reference](procs.html). - -## Tank Specifications - -Your PF-255 autonomous tank is built to the exacting -specifications sent to our factory in New Khavistan. All -distances are in meters, angles in degrees. - - -Tank size -: The targettable area of the tank—the part which can be hit by a cannon—is a circle about 7½ meters in radius. - -Speed -: Each tread can have a speed between -100 and 100. This is in - percentage of total speed for that tread, where total speed is - roughly 7 meters per turn. - -Sensors -: Each sensor has a maximum range of 100 meters. Of course, you - don't have to use the full range. Sensors may be attached to - the turret (they turn along with the turret), or left fixed to - the tank. - -Turret -: Turret angle can be set between -359° and 359°, with 0° directly - in front of the tank. Be aware that it takes time for the - turret to swing around: the turret can swing about 45° per turn. - -Cannon range and recharging -: When the cannon is fired, it obliterates everything for 50 - meters in front of it. It takes around 20 turns for your cannon - to recharge after it's been fired, so only shoot when you feel - like you're going to hit something. - -Good luck blowing everybody up! diff --git a/docs/nav.html.inc b/docs/nav.html.inc new file mode 100644 index 0000000..b2ea44f --- /dev/null +++ b/docs/nav.html.inc @@ -0,0 +1,10 @@ + diff --git a/docs/procs.html.m4 b/docs/procs.html.m4 new file mode 100644 index 0000000..2510df0 --- /dev/null +++ b/docs/procs.html.m4 @@ -0,0 +1,74 @@ + + + + Tanks Procedure Reference + + + + +

Tanks Procedure Reference

+ +

+ Each tank's program is run once per turn. The data and command + stacks are reset at the beginning of each turn, but memory is not, + so you can carry data over in memory registers if you want. See + the Forf manual for more information about + the base language. +

+ +

+ For tank specifications (sensor range, maximum speeds, etc.), see + the introduction. +

+ + +

Limits

+ +

+ Forf Tanks has a data stack size of 200, and a command stack size + of 500. This means your program cannot have more than 200 data + items, or 500 instructions, including 2 instructions for each + substack. +

+ +

+ Forf Tanks provides 10 memory registers (0-9) which persist across + invocations of your tank's program. +

+ + +

Additional Procedures

+ +
+
fire-ready?
+
Returns 1 if the tank can fire, 0 if not.
+ +
fire!
+
Fires the cannon.
+ +
l r set-speed!
+
Sets the speed of the left and right treads (range: -100 to + 100).
+ +
get-turret
+
Returns the current angle of the turret.
+ +
a set-turret!
+
Set the turret to a degrees.
+ +
n sensor?
+
Returns 1 if sensor n is triggered, 0 if not.
+ +
s set-led!
+
Turns off the LED if s is 0, on for any other value.
+ +
n random
+
Returns a random number in the range [0, n). That is, between + 0 and n-1, inclusive.
+
+ +include(nav.html.inc) + + + + diff --git a/docs/procs.md b/docs/procs.md deleted file mode 100644 index c003cb5..0000000 --- a/docs/procs.md +++ /dev/null @@ -1,47 +0,0 @@ -# Tanks Procedure Reference - -Each tank's program is run once per turn. The data and command -stacks are reset at the beginning of each turn, but memory is not, -so you can carry data over in memory registers if you want. See -the [Forf manual](forf.md) for more information about -the base language. - -For tank specifications (sensor range, maximum speeds, etc.), see -the [introduction](intro.html). - -## Limits - -Forf Tanks has a data stack size of 200, and a command stack size -of 500. This means your program cannot have more than 200 data -items, or 500 instructions, including 2 instructions for each -substack. - -Forf Tanks provides 10 memory registers (0-9) which persist across -invocations of your tank's program. - - -## Additional Procedures - -fire-ready? -: Returns 1 if the tank can fire, 0 if not. - -fire! -: Fires the cannon. - -l r set-speed! -: Sets the speed of the left and right treads (range: -100 to 100). - -get-turret -: Returns the current angle of the turret, in degrees. - -a set-turret! -: Begin moving the turret to a degrees. - -n sensor? -: Returns 1 if sensor n is triggered, 0 if not. - -s set-led! -: Turns off the LED if s is 0, on for any other value. - -n random -: Returns a random number in the range [0, n). That is, between 0 and n-1, inclusive. diff --git a/docs/running.md b/docs/running.md new file mode 100644 index 0000000..66dd857 --- /dev/null +++ b/docs/running.md @@ -0,0 +1,73 @@ +--- +title: Running Tanks +--- + +Unfortunately, it's kind of a mess right now. +I know there are a few forks of this code, +and I would love it if someone proposed a merge to clearly illustrate how to run tanks. + +When I spin up a new tanks game, +typically I run something like: + + while sleep 60; do ./run-tanks */; done + +This assumes all your tanks directories are in the same place as `run-tanks`. + + + +Included programs +----------------- + +I tried to stick with the Unix philosophy of one program per task. I +also tried to avoid doing any string processing in C. The result is a +hodgepodge of C, Bourne shell, and awk, but at least each piece is +fairly simple to audit. + + +### run-tanks tank1 tank2 ... + +Runs a single round, awards points with rank.awk, and creates a new +summary.html with summary.awk. This is the main interface that you want +to run from cron or whatever. + + +### forftanks tank1 tank2 ... + +A program to run a round of tanks and output a JSON description of the +game. This is what tanks.js uses to render a game graphically. +The object printed contains: + + [[game-width, game-height], + [[tank1-color, + [[sensor1range, sensor1angle, sensor1width, sensor1turret], + ...]], + ...], + [[ + [tank1x, tank1y, tank1angle, tank1sensangle, + tank1flags, tank1sensors], + ...], + ...]] + +If file descriptor 3 is open for writes, it also outputs the results of +the round to fd3. + + +### rank.awk + +Processes the fd3 output of forftanks to award points and output an +HTML results table. + + +### summary.awk tank1 tank2 + +Creates summary.html, linking to all rounds and showing overall +standing. + + +### designer.cgi + +Accepts form input and writes a tank. + + + +