tanks

Blow up enemy tanks using code
git clone https://git.woozle.org/neale/tanks.git

commit
144d988
parent
4fd9aa5
author
Neale Pickett
date
2024-12-05 15:36:41 -0700 MST
Simplify setup
43 files changed,  +75, -49
A .dockerignore
+4, -0
1@@ -0,0 +1,4 @@
2+contrib
3+docs
4+rounds
5+tanks
A Dockerfile
+7, -0
1@@ -0,0 +1,7 @@
2+FROM golang:1.22
3+WORKDIR /app
4+COPY *.go *.c *.h Makefile www /app
5+RUN make
6+RUN mkdir rounds
7+COPY examples /app/tanks
8+ENTRYPOINT [ "./tanksd" ]
M README.md
+38, -44
  1@@ -4,69 +4,63 @@ Tanks
  2 Dirtbags Tanks is a game in which you pit your coding abilities
  3 against other hackers.  You write a program for your tank, set it out
  4 on the battlefield, and watch how your program fares against tanks
  5-written by other players.  Dirtbags Tanks is frequently a component of
  6-[Dirtbags Capture The Flag](https://dirtbags.github.io/contest/).
  7+written by other players.
  8 
  9 
 10 Running it
 11-============
 12-
 13-    forftanks TANKDIR [TANKDIR...]
 14-    
 15-`forftanks` will run a round with every tank provided as an argument.
 16-It outputs a JSON object describing the round.
 17-
 18-
 19-Output fields
 20-------
 21-
 22-`seed`
 23-: Seed used by the random number generator.
 24-  You can specify your own seed with the environment variable `SEED.
 25-  If the same seed is used with the same tanks,
 26-  you will get the same output.
 27+========
 28 
 29-`field`
 30-: Dimensions of the play field.
 31+    $ make                    # build source code
 32+    $ mkdir rounds            # set up storage
 33+    $ cp -r examples tanks    # install some tanks
 34+    $ mkdir tanks/mytank      # provision your own tank
 35+    $ ./tanksd
 36 
 37-`tanks`
 38-: Description of each tank.
 39+At this point you can connect to http://localhost:8080/ and watch all the
 40+built-in tanks destroy your motionless tank.
 41+You can work on your tank with the token `mytank`.
 42 
 43-`rounds`
 44-: List of frames for each round.
 45-  Each frame is a list of tank state for each tank.
 46-  Tank state is described below.
 47-  
 48 
 49-Tank state
 50---------
 51+Administering a server
 52+==================
 53 
 54-Tank state is packed more tightly than most modern JSON APIs.
 55-Tank state is a tuple of (x position, y position, orientation angle, turret angle, flags, sensor bits).
 56+The `tanks` directory
 57+----------------
 58+The `tanks` directory has tank definitions.
 59+Each subdirectory is a token that can be used to upload a tank.
 60+Empty subdirectories are okay.
 61 
 62-x position, y position
 63-: Tank's position on the play field.
 64+If you were running a 9-person event,
 65+and had a Bash shell,
 66+you could run something like this to set up `tanks` subdirectories:
 67 
 68-orientation angle
 69-: Tank's orientation on the play field, in radians.
 70+    $ cd tanks
 71+    $ for i in $(seq 9); do mkdir $(printf "%04x$04x" $RANDOM $RANDOM); done
 72 
 73-turret angle
 74-: Turret angle, relative to the tank, in radians.
 75+`forftanks` uses the inode of each tank subdirectory
 76+to uniquely identify the tank.
 77+So if you want to change somebody's token,
 78+you should `mv` the subdirectory.
 79+If you `cp` it, or remove it and create a new one,
 80+the scoreboard won't know it's the same tank.
 81 
 82-flags
 83-: Logical or of 1 (firing), 2 (LED on), and 4 (dead)
 84 
 85-sensor bits
 86-: Bit field of sensor state (1 = triggered)
 87+The `rounds` directory
 88+-----------------
 89 
 90+The `rounds` directory has internal state,
 91+containing an `index.json` file,
 92+and a bunch of game files.
 93+You can delete individual games if you need to, for some reason;
 94+tanksd will notice your change when it runs the next game.
 95 
 96 
 97-Documentation
 98+More Documentation
 99 ============
100 
101-* [Homepage](https://dirtbags.github.io/tanks/)
102+* [Homepage](https://dirtbags.net/tanks/)
103 * [History](docs/history.md)
104-* [Running](docs/running.md)
105+* [Thanks](docs/thanks.md)
106 
107 
108 Current Maintainer
R examples/easy/berzerker/author => examples/easy-brick/author
+0, -0
A examples/easy-brick/color
+1, -0
1@@ -0,0 +1 @@
2+#ccffff
R examples/easy/brick/name => examples/easy-brick/name
+0, -0
A examples/easy-brick/program
+1, -0
1@@ -0,0 +1 @@
2+( This tank just sits around! )
R examples/easy/brick/author => examples/easy-rabbitwithgun/author
+0, -0
A examples/easy-rabbitwithgun/color
+1, -0
1@@ -0,0 +1 @@
2+#ffccff
R examples/easy/rabbitwithgun/name => examples/easy-rabbitwithgun/name
+0, -0
R examples/easy/rabbitwithgun/program => examples/easy-rabbitwithgun/program
+0, -0
R examples/easy/rabbitwithgun/sensor0 => examples/easy-rabbitwithgun/sensor0
+0, -0
R examples/easy/rabbitwithgun/sensor1 => examples/easy-rabbitwithgun/sensor1
+0, -0
R examples/easy/rabbitwithgun/author => examples/easy-twit/author
+0, -0
A examples/easy-twit/color
+1, -0
1@@ -0,0 +1 @@
2+#ffffcc
A examples/easy-twit/name
+1, -0
1@@ -0,0 +1 @@
2+Twit
R examples/easy/berzerker/program => examples/easy-twit/program
+0, -0
D examples/easy/berzerker/name
+0, -1
1@@ -1 +0,0 @@
2-berzerker
D examples/easy/brick/program
+0, -1
1@@ -1 +0,0 @@
2-( This program shouldn't even parse
R examples/medium/simpleton/author => examples/medium-simpleton/author
+0, -0
A examples/medium-simpleton/color
+1, -0
1@@ -0,0 +1 @@
2+#ccccff
R examples/medium/simpleton/name => examples/medium-simpleton/name
+0, -0
R examples/medium/simpleton/program => examples/medium-simpleton/program
+0, -0
R examples/medium/simpleton/sensor0 => examples/medium-simpleton/sensor0
+0, -0
R examples/medium/simpleton/sensor1 => examples/medium-simpleton/sensor1
+0, -0
R examples/medium/sittingduckwithteeth/author => examples/medium-sittingduckwithteeth/author
+0, -0
A examples/medium-sittingduckwithteeth/color
+1, -0
1@@ -0,0 +1 @@
2+#ffcccc
R examples/medium/sittingduckwithteeth/name => examples/medium-sittingduckwithteeth/name
+0, -0
R examples/medium/sittingduckwithteeth/program => examples/medium-sittingduckwithteeth/program
+0, -0
R examples/medium/sittingduckwithteeth/sensor0 => examples/medium-sittingduckwithteeth/sensor0
+0, -0
R examples/medium/sittingduckwithteeth/sensor1 => examples/medium-sittingduckwithteeth/sensor1
+0, -0
R examples/medium/sittingduckwithteeth/sensor2 => examples/medium-sittingduckwithteeth/sensor2
+0, -0
R examples/medium/sweeper/author => examples/medium-sweeper/author
+0, -0
A examples/medium-sweeper/color
+1, -0
1@@ -0,0 +1 @@
2+#ccffcc
R examples/medium/sweeper/name => examples/medium-sweeper/name
+0, -0
R examples/medium/sweeper/program => examples/medium-sweeper/program
+0, -0
R examples/medium/sweeper/sensor0 => examples/medium-sweeper/sensor0
+0, -0
R examples/medium/sweeper/sensor1 => examples/medium-sweeper/sensor1
+0, -0
R examples/medium/sweeper/sensor2 => examples/medium-sweeper/sensor2
+0, -0
R examples/medium/sweeper/sensor3 => examples/medium-sweeper/sensor3
+0, -0
M forftanks.c
+15, -0
 1@@ -275,6 +275,19 @@ void ft_read_sensors(struct tank *tank, char *path) {
 2   }
 3 }
 4 
 5+// Crudely clean a string for json output
 6+void clean(char *s) {
 7+  for (; *s; s++) {
 8+    switch (*s) {
 9+    case '\0' ... '\037':
10+    case '"':
11+    case '\\':
12+      *s = '\0';
13+      return;
14+    }
15+  }
16+}
17+
18 int ft_read_tank(struct forftank *ftank, struct tank *tank,
19                  struct forf_lexical_env *lenv, char *path) {
20   int ret;
21@@ -296,6 +309,7 @@ int ft_read_tank(struct forftank *ftank, struct tank *tank,
22   if (!ret) {
23     snprintf(ftank->name, sizeof(ftank->name), "i:%x", ftank->uid);
24   }
25+  clean(ftank->name);
26 
27   /* What is your quest? */
28   ft_tank_init(ftank, tank, lenv);
29@@ -312,6 +326,7 @@ int ft_read_tank(struct forftank *ftank, struct tank *tank,
30   if (!ret) {
31     strncpy(ftank->color, "#808080", sizeof(ftank->color));
32   }
33+  clean(ftank->color);
34 
35   return 1;
36 }
M www/replay.mjs
+0, -2
 1@@ -122,7 +122,6 @@ class Replay {
 2         }
 3 
 4         let tbody = this.stats.querySelector("tbody")
 5-        console.log(this.stats, tbody)
 6         tbody.replaceChildren()
 7 
 8         let byKills = Object.keys(TankNames)
 9@@ -177,7 +176,6 @@ class Replay {
10         let game = this.games[fn]
11 
12         this.player.load(game)
13-        console.log(fn)
14 
15         this.dateOutput.value = dateOfFn(fn)
16 
M www/tank.mjs
+3, -1
 1@@ -55,6 +55,8 @@ export class Tank {
 2         this.ctx.translate(this.x, this.y)
 3         this.ctx.rotate(this.rotation)
 4 
 5+        // If the cannon was fired in the same turn we were shot,
 6+        // render the laser for one frame.
 7         if (this.fire == 5) {
 8             this.ctx.save()
 9             this.ctx.rotate(this.turret)
10@@ -145,7 +147,7 @@ export class Tank {
11     }
12 
13     draw_cannon() {
14-        this.ctx.fillStyle = ("hsl(0, 100%, 100%, " + this.fire/5 + ")")
15+        this.ctx.fillStyle = ("hsl(0, 100%, 50%, " + this.fire/5 + ")")
16         this.ctx.fillRect(0, -1, 45, 2)
17     }
18