- commit
- 144d988
- parent
- 4fd9aa5
- author
- Neale Pickett
- date
- 2024-12-05 15:36:41 -0700 MST
Simplify setup
43 files changed,
+75,
-49
+4,
-0
1@@ -0,0 +1,4 @@
2+contrib
3+docs
4+rounds
5+tanks
+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" ]
+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
+1,
-0
1@@ -0,0 +1 @@
2+#ccffff
R examples/easy/brick/name =>
examples/easy-brick/name
+0,
-0
+1,
-0
1@@ -0,0 +1 @@
2+( This tank just sits around! )
+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
+1,
-0
1@@ -0,0 +1 @@
2+#ffffcc
+1,
-0
1@@ -0,0 +1 @@
2+Twit
R examples/easy/berzerker/program =>
examples/easy-twit/program
+0,
-0
+0,
-1
1@@ -1 +0,0 @@
2-berzerker
+0,
-1
1@@ -1 +0,0 @@
2-( This program shouldn't even parse
+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
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
+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
+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 }
+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
+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