mirror of https://github.com/dirtbags/tanks.git
Simplify setup
This commit is contained in:
parent
4fd9aa541b
commit
144d988e5c
|
@ -0,0 +1,4 @@
|
||||||
|
contrib
|
||||||
|
docs
|
||||||
|
rounds
|
||||||
|
tanks
|
|
@ -0,0 +1,7 @@
|
||||||
|
FROM golang:1.22
|
||||||
|
WORKDIR /app
|
||||||
|
COPY *.go *.c *.h Makefile www /app
|
||||||
|
RUN make
|
||||||
|
RUN mkdir rounds
|
||||||
|
COPY examples /app/tanks
|
||||||
|
ENTRYPOINT [ "./tanksd" ]
|
108
README.md
108
README.md
|
@ -4,69 +4,63 @@ Tanks
|
||||||
Dirtbags Tanks is a game in which you pit your coding abilities
|
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
|
against other hackers. You write a program for your tank, set it out
|
||||||
on the battlefield, and watch how your program fares against tanks
|
on the battlefield, and watch how your program fares against tanks
|
||||||
written by other players. Dirtbags Tanks is frequently a component of
|
written by other players.
|
||||||
[Dirtbags Capture The Flag](https://dirtbags.github.io/contest/).
|
|
||||||
|
|
||||||
|
|
||||||
Running it
|
Running it
|
||||||
|
========
|
||||||
|
|
||||||
|
$ make # build source code
|
||||||
|
$ mkdir rounds # set up storage
|
||||||
|
$ cp -r examples tanks # install some tanks
|
||||||
|
$ mkdir tanks/mytank # provision your own tank
|
||||||
|
$ ./tanksd
|
||||||
|
|
||||||
|
At this point you can connect to http://localhost:8080/ and watch all the
|
||||||
|
built-in tanks destroy your motionless tank.
|
||||||
|
You can work on your tank with the token `mytank`.
|
||||||
|
|
||||||
|
|
||||||
|
Administering a server
|
||||||
|
==================
|
||||||
|
|
||||||
|
The `tanks` directory
|
||||||
|
----------------
|
||||||
|
The `tanks` directory has tank definitions.
|
||||||
|
Each subdirectory is a token that can be used to upload a tank.
|
||||||
|
Empty subdirectories are okay.
|
||||||
|
|
||||||
|
If you were running a 9-person event,
|
||||||
|
and had a Bash shell,
|
||||||
|
you could run something like this to set up `tanks` subdirectories:
|
||||||
|
|
||||||
|
$ cd tanks
|
||||||
|
$ for i in $(seq 9); do mkdir $(printf "%04x$04x" $RANDOM $RANDOM); done
|
||||||
|
|
||||||
|
`forftanks` uses the inode of each tank subdirectory
|
||||||
|
to uniquely identify the tank.
|
||||||
|
So if you want to change somebody's token,
|
||||||
|
you should `mv` the subdirectory.
|
||||||
|
If you `cp` it, or remove it and create a new one,
|
||||||
|
the scoreboard won't know it's the same tank.
|
||||||
|
|
||||||
|
|
||||||
|
The `rounds` directory
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The `rounds` directory has internal state,
|
||||||
|
containing an `index.json` file,
|
||||||
|
and a bunch of game files.
|
||||||
|
You can delete individual games if you need to, for some reason;
|
||||||
|
tanksd will notice your change when it runs the next game.
|
||||||
|
|
||||||
|
|
||||||
|
More Documentation
|
||||||
============
|
============
|
||||||
|
|
||||||
forftanks TANKDIR [TANKDIR...]
|
* [Homepage](https://dirtbags.net/tanks/)
|
||||||
|
|
||||||
`forftanks` will run a round with every tank provided as an argument.
|
|
||||||
It outputs a JSON object describing the round.
|
|
||||||
|
|
||||||
|
|
||||||
Output fields
|
|
||||||
------
|
|
||||||
|
|
||||||
`seed`
|
|
||||||
: Seed used by the random number generator.
|
|
||||||
You can specify your own seed with the environment variable `SEED.
|
|
||||||
If the same seed is used with the same tanks,
|
|
||||||
you will get the same output.
|
|
||||||
|
|
||||||
`field`
|
|
||||||
: Dimensions of the play field.
|
|
||||||
|
|
||||||
`tanks`
|
|
||||||
: Description of each tank.
|
|
||||||
|
|
||||||
`rounds`
|
|
||||||
: List of frames for each round.
|
|
||||||
Each frame is a list of tank state for each tank.
|
|
||||||
Tank state is described below.
|
|
||||||
|
|
||||||
|
|
||||||
Tank state
|
|
||||||
--------
|
|
||||||
|
|
||||||
Tank state is packed more tightly than most modern JSON APIs.
|
|
||||||
Tank state is a tuple of (x position, y position, orientation angle, turret angle, flags, sensor bits).
|
|
||||||
|
|
||||||
x position, y position
|
|
||||||
: Tank's position on the play field.
|
|
||||||
|
|
||||||
orientation angle
|
|
||||||
: Tank's orientation on the play field, in radians.
|
|
||||||
|
|
||||||
turret angle
|
|
||||||
: Turret angle, relative to the tank, in radians.
|
|
||||||
|
|
||||||
flags
|
|
||||||
: Logical or of 1 (firing), 2 (LED on), and 4 (dead)
|
|
||||||
|
|
||||||
sensor bits
|
|
||||||
: Bit field of sensor state (1 = triggered)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Documentation
|
|
||||||
============
|
|
||||||
|
|
||||||
* [Homepage](https://dirtbags.github.io/tanks/)
|
|
||||||
* [History](docs/history.md)
|
* [History](docs/history.md)
|
||||||
* [Running](docs/running.md)
|
* [Thanks](docs/thanks.md)
|
||||||
|
|
||||||
|
|
||||||
Current Maintainer
|
Current Maintainer
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
#ccffff
|
|
@ -0,0 +1 @@
|
||||||
|
( This tank just sits around! )
|
|
@ -0,0 +1 @@
|
||||||
|
#ffccff
|
|
@ -0,0 +1 @@
|
||||||
|
#ffffcc
|
|
@ -0,0 +1 @@
|
||||||
|
Twit
|
|
@ -1 +0,0 @@
|
||||||
berzerker
|
|
|
@ -1 +0,0 @@
|
||||||
( This program shouldn't even parse
|
|
|
@ -0,0 +1 @@
|
||||||
|
#ccccff
|
|
@ -0,0 +1 @@
|
||||||
|
#ffcccc
|
|
@ -0,0 +1 @@
|
||||||
|
#ccffcc
|
15
forftanks.c
15
forftanks.c
|
@ -275,6 +275,19 @@ void ft_read_sensors(struct tank *tank, char *path) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Crudely clean a string for json output
|
||||||
|
void clean(char *s) {
|
||||||
|
for (; *s; s++) {
|
||||||
|
switch (*s) {
|
||||||
|
case '\0' ... '\037':
|
||||||
|
case '"':
|
||||||
|
case '\\':
|
||||||
|
*s = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int ft_read_tank(struct forftank *ftank, struct tank *tank,
|
int ft_read_tank(struct forftank *ftank, struct tank *tank,
|
||||||
struct forf_lexical_env *lenv, char *path) {
|
struct forf_lexical_env *lenv, char *path) {
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -296,6 +309,7 @@ int ft_read_tank(struct forftank *ftank, struct tank *tank,
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
snprintf(ftank->name, sizeof(ftank->name), "i:%x", ftank->uid);
|
snprintf(ftank->name, sizeof(ftank->name), "i:%x", ftank->uid);
|
||||||
}
|
}
|
||||||
|
clean(ftank->name);
|
||||||
|
|
||||||
/* What is your quest? */
|
/* What is your quest? */
|
||||||
ft_tank_init(ftank, tank, lenv);
|
ft_tank_init(ftank, tank, lenv);
|
||||||
|
@ -312,6 +326,7 @@ int ft_read_tank(struct forftank *ftank, struct tank *tank,
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
strncpy(ftank->color, "#808080", sizeof(ftank->color));
|
strncpy(ftank->color, "#808080", sizeof(ftank->color));
|
||||||
}
|
}
|
||||||
|
clean(ftank->color);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,7 +122,6 @@ class Replay {
|
||||||
}
|
}
|
||||||
|
|
||||||
let tbody = this.stats.querySelector("tbody")
|
let tbody = this.stats.querySelector("tbody")
|
||||||
console.log(this.stats, tbody)
|
|
||||||
tbody.replaceChildren()
|
tbody.replaceChildren()
|
||||||
|
|
||||||
let byKills = Object.keys(TankNames)
|
let byKills = Object.keys(TankNames)
|
||||||
|
@ -177,7 +176,6 @@ class Replay {
|
||||||
let game = this.games[fn]
|
let game = this.games[fn]
|
||||||
|
|
||||||
this.player.load(game)
|
this.player.load(game)
|
||||||
console.log(fn)
|
|
||||||
|
|
||||||
this.dateOutput.value = dateOfFn(fn)
|
this.dateOutput.value = dateOfFn(fn)
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,8 @@ export class Tank {
|
||||||
this.ctx.translate(this.x, this.y)
|
this.ctx.translate(this.x, this.y)
|
||||||
this.ctx.rotate(this.rotation)
|
this.ctx.rotate(this.rotation)
|
||||||
|
|
||||||
|
// If the cannon was fired in the same turn we were shot,
|
||||||
|
// render the laser for one frame.
|
||||||
if (this.fire == 5) {
|
if (this.fire == 5) {
|
||||||
this.ctx.save()
|
this.ctx.save()
|
||||||
this.ctx.rotate(this.turret)
|
this.ctx.rotate(this.turret)
|
||||||
|
@ -145,7 +147,7 @@ export class Tank {
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_cannon() {
|
draw_cannon() {
|
||||||
this.ctx.fillStyle = ("hsl(0, 100%, 100%, " + this.fire/5 + ")")
|
this.ctx.fillStyle = ("hsl(0, 100%, 50%, " + this.fire/5 + ")")
|
||||||
this.ctx.fillRect(0, -1, 45, 2)
|
this.ctx.fillRect(0, -1, 45, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue