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
|
||||
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](https://dirtbags.github.io/contest/).
|
||||
written by other players.
|
||||
|
||||
|
||||
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...]
|
||||
|
||||
`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/)
|
||||
* [Homepage](https://dirtbags.net/tanks/)
|
||||
* [History](docs/history.md)
|
||||
* [Running](docs/running.md)
|
||||
* [Thanks](docs/thanks.md)
|
||||
|
||||
|
||||
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,
|
||||
struct forf_lexical_env *lenv, char *path) {
|
||||
int ret;
|
||||
|
@ -296,6 +309,7 @@ int ft_read_tank(struct forftank *ftank, struct tank *tank,
|
|||
if (!ret) {
|
||||
snprintf(ftank->name, sizeof(ftank->name), "i:%x", ftank->uid);
|
||||
}
|
||||
clean(ftank->name);
|
||||
|
||||
/* What is your quest? */
|
||||
ft_tank_init(ftank, tank, lenv);
|
||||
|
@ -312,6 +326,7 @@ int ft_read_tank(struct forftank *ftank, struct tank *tank,
|
|||
if (!ret) {
|
||||
strncpy(ftank->color, "#808080", sizeof(ftank->color));
|
||||
}
|
||||
clean(ftank->color);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -122,7 +122,6 @@ class Replay {
|
|||
}
|
||||
|
||||
let tbody = this.stats.querySelector("tbody")
|
||||
console.log(this.stats, tbody)
|
||||
tbody.replaceChildren()
|
||||
|
||||
let byKills = Object.keys(TankNames)
|
||||
|
@ -177,7 +176,6 @@ class Replay {
|
|||
let game = this.games[fn]
|
||||
|
||||
this.player.load(game)
|
||||
console.log(fn)
|
||||
|
||||
this.dateOutput.value = dateOfFn(fn)
|
||||
|
||||
|
|
|
@ -55,6 +55,8 @@ export class Tank {
|
|||
this.ctx.translate(this.x, this.y)
|
||||
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) {
|
||||
this.ctx.save()
|
||||
this.ctx.rotate(this.turret)
|
||||
|
@ -145,7 +147,7 @@ export class Tank {
|
|||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue