mirror of https://github.com/dirtbags/tanks.git
End-user documentation
This commit is contained in:
parent
7c7acc5ffe
commit
4e8934377e
|
@ -0,0 +1,3 @@
|
|||
*~
|
||||
*#
|
||||
*.o
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "forf"]
|
||||
path = forf
|
||||
url = woozle.org:projects/forf
|
23
Makefile
23
Makefile
|
@ -1,14 +1,23 @@
|
|||
CFLAGS = -Wall
|
||||
LDFLAGS = -lm
|
||||
|
||||
all: run-tanks
|
||||
all: html run-tanks designer.cgi
|
||||
html: forf.html
|
||||
|
||||
test: test-tanks
|
||||
./test-tanks | m4 round.html.m4 - > round.html
|
||||
run-tanks: run-tanks.o ctanks.o forf.o
|
||||
run-tanks: LDFLAGS = -lm
|
||||
|
||||
test-tanks: test-tanks.o ctanks.o
|
||||
run-tanks.o: forf.h ctanks.h
|
||||
forf.o: forf.c forf.h
|
||||
ctanks.o: ctanks.h
|
||||
|
||||
run-tanks: run-tanks.o ctanks.o cforf.o
|
||||
forf.html: forf.html.sh forf/forf.txt
|
||||
./forf.html.sh > $@
|
||||
|
||||
forf.%: forf/forf.%
|
||||
cp forf/$@ $@
|
||||
forf/%:
|
||||
git submodule update --init
|
||||
|
||||
clean:
|
||||
rm -f test-tanks run-tanks *.o
|
||||
rm -f run-tanks designer.cgi *.o forf.c forf.h
|
||||
rm -f next-round round-*.html summary.html forf.html
|
||||
|
|
752
cforf.c
752
cforf.c
|
@ -1,752 +0,0 @@
|
|||
/* forf: a crappy Forth implementation
|
||||
* Copyright (C) 2010 Adam Glasgall
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Notes
|
||||
* -------------------------------------------------------
|
||||
*
|
||||
* This is intended to be implemented as a library. As such, it doesn't
|
||||
* use the libc memory allocation functions. This may be a different
|
||||
* programming style than you're used to.
|
||||
*
|
||||
* There are two data types: numbers and stacks. Because we can't
|
||||
* allocate memory, stacks are implemented with begin and end markers
|
||||
* and not new stack types.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cforf.h"
|
||||
#include "dump.h"
|
||||
|
||||
#ifndef max
|
||||
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
char *forf_error_str[] = {
|
||||
"None",
|
||||
"Runtime",
|
||||
"Parse",
|
||||
"Underflow",
|
||||
"Overflow",
|
||||
"Type",
|
||||
"No such procedure",
|
||||
"Divide by zero",
|
||||
};
|
||||
|
||||
/*
|
||||
*
|
||||
* Memory manipulation
|
||||
*
|
||||
*/
|
||||
void
|
||||
forf_memory_init(struct forf_memory *m,
|
||||
long *values,
|
||||
size_t size)
|
||||
{
|
||||
m->mem = values;
|
||||
m->size = size;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Stack manipulation
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
forf_stack_init(struct forf_stack *s,
|
||||
struct forf_value *values,
|
||||
size_t size)
|
||||
{
|
||||
s->stack = values;
|
||||
s->size = size;
|
||||
s->top = 0;
|
||||
}
|
||||
|
||||
void
|
||||
forf_stack_reset(struct forf_stack *s)
|
||||
{
|
||||
s->top = 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
forf_stack_len(struct forf_stack *s)
|
||||
{
|
||||
return s->top;
|
||||
}
|
||||
|
||||
int
|
||||
forf_stack_push(struct forf_stack *s, struct forf_value *v)
|
||||
{
|
||||
if (s->top == s->size) {
|
||||
return 0;
|
||||
}
|
||||
s->stack[(s->top)++] = *v;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
forf_stack_pop(struct forf_stack *s, struct forf_value *v)
|
||||
{
|
||||
if (0 == s->top) {
|
||||
return 0;
|
||||
}
|
||||
*v = s->stack[--(s->top)];
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
forf_stack_copy(struct forf_stack *dst, struct forf_stack *src)
|
||||
{
|
||||
int top = min(dst->size, src->top);
|
||||
|
||||
dst->top = top;
|
||||
memcpy(dst->stack, src->stack, sizeof(*dst->stack) * top);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
forf_stack_reverse(struct forf_stack *s)
|
||||
{
|
||||
struct forf_value val;
|
||||
size_t pos;
|
||||
|
||||
for (pos = 0; pos < (s->top)/2; pos += 1) {
|
||||
size_t qos = s->top - pos - 1;
|
||||
|
||||
val = s->stack[pos];
|
||||
s->stack[pos] = s->stack[qos];
|
||||
s->stack[qos] = val;
|
||||
}
|
||||
}
|
||||
|
||||
long
|
||||
forf_pop_num(struct forf_env *env)
|
||||
{
|
||||
struct forf_value val;
|
||||
|
||||
if (! forf_stack_pop(env->data, &val)) {
|
||||
env->error = forf_error_underflow;
|
||||
return 0;
|
||||
}
|
||||
if (forf_type_number != val.type) {
|
||||
forf_stack_push(env->data, &val);
|
||||
env->error = forf_error_type;
|
||||
return 0;
|
||||
}
|
||||
return val.v.i;
|
||||
}
|
||||
|
||||
void
|
||||
forf_push_num(struct forf_env *env, long i)
|
||||
{
|
||||
struct forf_value val;
|
||||
|
||||
val.type = forf_type_number;
|
||||
val.v.i = i;
|
||||
if (! forf_stack_push(env->data, &val)) {
|
||||
env->error = forf_error_overflow;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Pop an entire stack
|
||||
*
|
||||
* DANGER WILL ROBINSON
|
||||
*
|
||||
* This returned stack points to values on the data stack. You must be
|
||||
* finished with this stack before you push anything onto the data
|
||||
* stack, otherwise your returned stack will be corrupted.
|
||||
*/
|
||||
struct forf_stack
|
||||
forf_pop_stack(struct forf_env *env)
|
||||
{
|
||||
struct forf_stack s = { 0, 0, NULL };
|
||||
struct forf_value val;
|
||||
size_t depth = 1;
|
||||
|
||||
if (! forf_stack_pop(env->data, &val)) {
|
||||
env->error = forf_error_underflow;
|
||||
return s;
|
||||
}
|
||||
if (forf_type_stack_end != val.type) {
|
||||
forf_stack_push(env->data, &val);
|
||||
env->error = forf_error_type;
|
||||
return s;
|
||||
}
|
||||
/* Duplicate just the stack onto s. Begin with -1 to account for the
|
||||
end of list marker. */
|
||||
s.size = -1;
|
||||
while (depth) {
|
||||
s.size += 1;
|
||||
if (! forf_stack_pop(env->data, &val)) {
|
||||
/* You should never underflow here, there should at least be a
|
||||
stack begin marker. */
|
||||
env->error = forf_error_runtime;
|
||||
s.size = 0;
|
||||
return s;
|
||||
}
|
||||
switch (val.type) {
|
||||
case forf_type_stack_end:
|
||||
depth += 1;
|
||||
break;
|
||||
case forf_type_stack_begin:
|
||||
depth -= 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
s.top = s.size;
|
||||
s.stack = (env->data->stack) + (env->data->top + 1);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Push an entire stack onto another stack.
|
||||
*/
|
||||
int
|
||||
forf_push_stack(struct forf_stack *dst, struct forf_stack *src)
|
||||
{
|
||||
struct forf_value val;
|
||||
|
||||
while (forf_stack_pop(src, &val)) {
|
||||
if (! forf_stack_push(dst, &val)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Push an entire stack onto the command stack.
|
||||
*
|
||||
* This is meant to work with the return value from forf_pop_stack.
|
||||
*/
|
||||
int
|
||||
forf_push_to_command_stack(struct forf_env *env, struct forf_stack *src)
|
||||
{
|
||||
if (! forf_push_stack(env->command, src)) {
|
||||
env->error = forf_error_overflow;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Move one value from src to dst. Note that one value could mean a
|
||||
* whole substack, in which case dst gets the stack in reverse! dst can
|
||||
* also be NULL, in which case a value is just discarded.
|
||||
*
|
||||
* Because of the reversing thing, it's important to make sure that the
|
||||
* data stack is either src or dst. This way, the data stack will
|
||||
* always have "reversed" substacks, and everything else will have them
|
||||
* in the right order.
|
||||
*/
|
||||
int
|
||||
forf_stack_move_value(struct forf_env *env,
|
||||
struct forf_stack *dst,
|
||||
struct forf_stack *src)
|
||||
{
|
||||
struct forf_value val;
|
||||
size_t depth = 0;
|
||||
|
||||
do {
|
||||
/* Pop from src */
|
||||
if (! forf_stack_pop(env->command, &val)) {
|
||||
env->error = forf_error_underflow;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Push to dst (or discard if dst is NULL) */
|
||||
if (dst) {
|
||||
if (! forf_stack_push(env->data, &val)) {
|
||||
env->error = forf_error_overflow;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Deal with it being a substack marker */
|
||||
switch (val.type) {
|
||||
case forf_type_stack_begin:
|
||||
depth += 1;
|
||||
break;
|
||||
case forf_type_stack_end:
|
||||
depth -= 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while (depth > 0);
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Procedures
|
||||
*
|
||||
*/
|
||||
|
||||
#define unproc(name, op) \
|
||||
static void \
|
||||
forf_proc_ ## name(struct forf_env *env) \
|
||||
{ \
|
||||
long a = forf_pop_num(env); \
|
||||
\
|
||||
forf_push_num(env, op a); \
|
||||
}
|
||||
|
||||
unproc(inv, ~)
|
||||
unproc(not, !)
|
||||
|
||||
#define binproc(name, op) \
|
||||
static void \
|
||||
forf_proc_ ## name(struct forf_env *env) \
|
||||
{ \
|
||||
long a = forf_pop_num(env); \
|
||||
long b = forf_pop_num(env); \
|
||||
\
|
||||
forf_push_num(env, b op a); \
|
||||
}
|
||||
|
||||
binproc(add, +)
|
||||
binproc(sub, -)
|
||||
binproc(mul, *)
|
||||
binproc(and, &)
|
||||
binproc(or, |)
|
||||
binproc(xor, ^)
|
||||
binproc(lshift, <<)
|
||||
binproc(rshift, >>)
|
||||
binproc(gt, >)
|
||||
binproc(ge, >=)
|
||||
binproc(lt, <)
|
||||
binproc(le, <=)
|
||||
binproc(eq, ==)
|
||||
binproc(ne, !=)
|
||||
|
||||
static void
|
||||
forf_proc_div(struct forf_env *env)
|
||||
{
|
||||
long a = forf_pop_num(env);
|
||||
long b = forf_pop_num(env);
|
||||
|
||||
if (0 == a) {
|
||||
env->error = forf_error_divzero;
|
||||
return;
|
||||
}
|
||||
forf_push_num(env, b / a);
|
||||
}
|
||||
|
||||
static void
|
||||
forf_proc_mod(struct forf_env *env)
|
||||
{
|
||||
long a = forf_pop_num(env);
|
||||
long b = forf_pop_num(env);
|
||||
|
||||
if (0 == a) {
|
||||
env->error = forf_error_divzero;
|
||||
return;
|
||||
}
|
||||
forf_push_num(env, b % a);
|
||||
}
|
||||
|
||||
static void
|
||||
forf_proc_abs(struct forf_env *env)
|
||||
{
|
||||
forf_push_num(env, abs(forf_pop_num(env)));
|
||||
}
|
||||
|
||||
static void
|
||||
forf_proc_dup(struct forf_env *env)
|
||||
{
|
||||
long a = forf_pop_num(env);
|
||||
|
||||
forf_push_num(env, a);
|
||||
forf_push_num(env, a);
|
||||
}
|
||||
|
||||
static void
|
||||
forf_proc_pop(struct forf_env *env)
|
||||
{
|
||||
forf_pop_num(env);
|
||||
}
|
||||
|
||||
static void
|
||||
forf_proc_exch(struct forf_env *env)
|
||||
{
|
||||
long a = forf_pop_num(env);
|
||||
long b = forf_pop_num(env);
|
||||
|
||||
forf_push_num(env, a);
|
||||
forf_push_num(env, b);
|
||||
}
|
||||
|
||||
static void
|
||||
forf_proc_if(struct forf_env *env)
|
||||
{
|
||||
struct forf_stack ifclause = forf_pop_stack(env);
|
||||
long cond = forf_pop_num(env);
|
||||
|
||||
if (cond) {
|
||||
forf_push_to_command_stack(env, &ifclause);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
forf_proc_ifelse(struct forf_env *env)
|
||||
{
|
||||
struct forf_stack elseclause = forf_pop_stack(env);
|
||||
struct forf_stack ifclause = forf_pop_stack(env);
|
||||
long cond = forf_pop_num(env);
|
||||
|
||||
if (cond) {
|
||||
forf_push_to_command_stack(env, &ifclause);
|
||||
} else {
|
||||
forf_push_to_command_stack(env, &elseclause);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
forf_proc_memset(struct forf_env *env)
|
||||
{
|
||||
long pos = forf_pop_num(env);
|
||||
long a = forf_pop_num(env);
|
||||
|
||||
if (pos >= env->memory->size) {
|
||||
env->error = forf_error_overflow;
|
||||
return;
|
||||
}
|
||||
|
||||
env->memory->mem[pos] = a;
|
||||
}
|
||||
|
||||
static void
|
||||
forf_proc_memget(struct forf_env *env)
|
||||
{
|
||||
long pos = forf_pop_num(env);
|
||||
|
||||
if (pos >= env->memory->size) {
|
||||
env->error = forf_error_overflow;
|
||||
return;
|
||||
}
|
||||
|
||||
forf_push_num(env, env->memory->mem[pos]);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Lexical environment
|
||||
*
|
||||
*/
|
||||
struct forf_lexical_env forf_base_lexical_env[] = {
|
||||
{"~", forf_proc_inv},
|
||||
{"!", forf_proc_not},
|
||||
{"+", forf_proc_add},
|
||||
{"-", forf_proc_sub},
|
||||
{"*", forf_proc_mul},
|
||||
{"/", forf_proc_div},
|
||||
{"%", forf_proc_mod},
|
||||
{"&", forf_proc_and},
|
||||
{"|", forf_proc_or},
|
||||
{"^", forf_proc_xor},
|
||||
{"<<", forf_proc_lshift},
|
||||
{">>", forf_proc_rshift},
|
||||
{">", forf_proc_gt},
|
||||
{">=", forf_proc_ge},
|
||||
{"<", forf_proc_lt},
|
||||
{"<=", forf_proc_le},
|
||||
{"=", forf_proc_eq},
|
||||
{"<>", forf_proc_ne},
|
||||
{"abs", forf_proc_abs},
|
||||
{"dup", forf_proc_dup},
|
||||
{"pop", forf_proc_pop},
|
||||
{"exch", forf_proc_exch},
|
||||
{"if", forf_proc_if},
|
||||
{"ifelse", forf_proc_ifelse},
|
||||
{"mset", forf_proc_memset},
|
||||
{"mget", forf_proc_memget},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/** Extend a lexical environment */
|
||||
int
|
||||
forf_extend_lexical_env(struct forf_lexical_env *dest,
|
||||
struct forf_lexical_env *src,
|
||||
size_t size)
|
||||
{
|
||||
int base, i;
|
||||
|
||||
for (base = 0; dest[base].name; base += 1);
|
||||
for (i = 0; (base+i < size) && (src[i].name); i += 1) {
|
||||
dest[base+i] = src[i];
|
||||
}
|
||||
if (base + i == size) {
|
||||
/* Not enough room */
|
||||
return 0;
|
||||
}
|
||||
dest[base+i].name = NULL;
|
||||
dest[base+i].proc = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Parsing
|
||||
*
|
||||
*/
|
||||
static int
|
||||
forf_push_token(struct forf_env *env, char *token, size_t tokenlen)
|
||||
{
|
||||
long i;
|
||||
char s[MAX_TOKEN_LEN + 1];
|
||||
char *endptr;
|
||||
struct forf_value val;
|
||||
|
||||
/* Zero-length token yields int:0 from strtol */
|
||||
|
||||
/* NUL-terminate it */
|
||||
memcpy(s, token, tokenlen);
|
||||
s[tokenlen] = '\0';
|
||||
|
||||
/* Try to make in an integer */
|
||||
i = strtol(s, &endptr, 0);
|
||||
if ('\0' == *endptr) {
|
||||
/* Was an int */
|
||||
val.type = forf_type_number;
|
||||
val.v.i = i;
|
||||
} else {
|
||||
/* If not an int, a procedure name */
|
||||
val.type = forf_type_proc;
|
||||
for (i = 0; NULL != env->lenv[i].name; i += 1) {
|
||||
if (0 == strcmp(s, env->lenv[i].name)) {
|
||||
val.v.p = env->lenv[i].proc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (NULL == env->lenv[i].name) {
|
||||
env->error = forf_error_noproc;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (! forf_stack_push(env->command, &val)) {
|
||||
env->error = forf_error_overflow;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Parse an input stream onto the command stack */
|
||||
int
|
||||
forf_parse_stream(struct forf_env *env,
|
||||
forf_getch_func *getch,
|
||||
void *datum)
|
||||
{
|
||||
int running = 1;
|
||||
long pos = 0;
|
||||
char token[MAX_TOKEN_LEN];
|
||||
size_t tokenlen = 0;
|
||||
struct forf_value val;
|
||||
size_t stack_depth = 0;
|
||||
int comment = 0;
|
||||
|
||||
#define _tokenize() \
|
||||
do { \
|
||||
if (tokenlen) { \
|
||||
if (! forf_push_token(env, token, tokenlen)) return pos; \
|
||||
tokenlen = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
while (running) {
|
||||
int c;
|
||||
|
||||
c = getch(datum);
|
||||
pos += 1;
|
||||
|
||||
/* Handle comments */
|
||||
if (comment) {
|
||||
if (')' == c) {
|
||||
comment = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case EOF:
|
||||
running = 0;
|
||||
break;
|
||||
case '(':
|
||||
comment = 1;
|
||||
break;
|
||||
case ' ':
|
||||
case '\f':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
case '\v':
|
||||
_tokenize();
|
||||
break;
|
||||
case '{':
|
||||
_tokenize();
|
||||
val.type = forf_type_stack_begin;
|
||||
if (! forf_stack_push(env->command, &val)) {
|
||||
env->error = forf_error_overflow;
|
||||
return pos;
|
||||
}
|
||||
stack_depth += 1;
|
||||
break;
|
||||
case '}':
|
||||
_tokenize();
|
||||
val.type = forf_type_stack_end;
|
||||
if (! forf_stack_push(env->command, &val)) {
|
||||
env->error = forf_error_overflow;
|
||||
return pos;
|
||||
}
|
||||
stack_depth -= 1;
|
||||
break;
|
||||
default:
|
||||
if (tokenlen < sizeof(token)) {
|
||||
token[tokenlen++] = c;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
_tokenize();
|
||||
|
||||
if (0 != stack_depth) {
|
||||
env->error = forf_error_parse;
|
||||
return pos;
|
||||
}
|
||||
|
||||
// The first thing we read should be the first thing we do
|
||||
forf_stack_reverse(env->command);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct forf_char_stream {
|
||||
char *buf;
|
||||
size_t len;
|
||||
size_t pos;
|
||||
};
|
||||
|
||||
static int
|
||||
forf_string_getch(struct forf_char_stream *stream)
|
||||
{
|
||||
if (stream->pos >= stream->len) {
|
||||
return EOF;
|
||||
}
|
||||
return stream->buf[stream->pos++];
|
||||
}
|
||||
|
||||
int
|
||||
forf_parse_buffer(struct forf_env *env,
|
||||
char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct forf_char_stream stream;
|
||||
|
||||
stream.buf = buf;
|
||||
stream.len = len;
|
||||
stream.pos = 0;
|
||||
|
||||
return forf_parse_stream(env, (forf_getch_func *)forf_string_getch, &stream);
|
||||
}
|
||||
|
||||
int
|
||||
forf_parse_string(struct forf_env *env,
|
||||
char *str)
|
||||
{
|
||||
return forf_parse_buffer(env, str, strlen(str));
|
||||
}
|
||||
|
||||
int
|
||||
forf_parse_file(struct forf_env *env,
|
||||
FILE *f)
|
||||
{
|
||||
return forf_parse_stream(env, (forf_getch_func *)fgetc, f);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Forf environment
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
forf_env_init(struct forf_env *env,
|
||||
struct forf_lexical_env *lenv,
|
||||
struct forf_stack *data,
|
||||
struct forf_stack *cmd,
|
||||
struct forf_memory *mem,
|
||||
void *udata)
|
||||
{
|
||||
env->lenv = lenv;
|
||||
env->data = data;
|
||||
env->command = cmd;
|
||||
env->memory = mem;
|
||||
env->udata = udata;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
forf_eval_once(struct forf_env *env)
|
||||
{
|
||||
struct forf_value val;
|
||||
|
||||
if (! forf_stack_pop(env->command, &val)) {
|
||||
env->error = forf_error_underflow;
|
||||
return 0;
|
||||
}
|
||||
switch (val.type) {
|
||||
case forf_type_number:
|
||||
case forf_type_stack_begin:
|
||||
// Push back on command stack, then move it
|
||||
forf_stack_push(env->command, &val);
|
||||
if (! forf_stack_move_value(env, env->data, env->command)) return 0;
|
||||
break;
|
||||
case forf_type_proc:
|
||||
(val.v.p)(env);
|
||||
break;
|
||||
default:
|
||||
env->error = forf_error_runtime;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
forf_eval(struct forf_env *env)
|
||||
{
|
||||
int ret;
|
||||
|
||||
while (env->command->top) {
|
||||
ret = forf_eval_once(env);
|
||||
if ((! ret) || (env->error)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
150
cforf.h
150
cforf.h
|
@ -1,150 +0,0 @@
|
|||
#ifndef __CFORF_H__
|
||||
#define __CFORF_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define MAX_TOKEN_LEN 20
|
||||
#define MAX_CMDSTACK 200
|
||||
|
||||
struct forf_env;
|
||||
|
||||
enum forf_value_type {
|
||||
forf_type_number,
|
||||
forf_type_proc,
|
||||
forf_type_stack_begin,
|
||||
forf_type_stack_end,
|
||||
};
|
||||
|
||||
enum forf_error_type {
|
||||
forf_error_none,
|
||||
forf_error_runtime,
|
||||
forf_error_parse,
|
||||
forf_error_underflow,
|
||||
forf_error_overflow,
|
||||
forf_error_type,
|
||||
forf_error_noproc,
|
||||
forf_error_divzero,
|
||||
};
|
||||
|
||||
extern char *forf_error_str[];
|
||||
|
||||
typedef void (forf_proc)(struct forf_env *);
|
||||
|
||||
struct forf_value {
|
||||
enum forf_value_type type;
|
||||
union {
|
||||
forf_proc *p;
|
||||
long i;
|
||||
} v;
|
||||
};
|
||||
|
||||
struct forf_stack {
|
||||
size_t size;
|
||||
size_t top;
|
||||
struct forf_value *stack;
|
||||
};
|
||||
|
||||
struct forf_memory {
|
||||
size_t size;
|
||||
long *mem;
|
||||
};
|
||||
|
||||
struct forf_lexical_env {
|
||||
char *name;
|
||||
forf_proc *proc;
|
||||
};
|
||||
|
||||
struct forf_env {
|
||||
enum forf_error_type error;
|
||||
struct forf_lexical_env *lenv;
|
||||
struct forf_stack *data;
|
||||
struct forf_stack *command;
|
||||
struct forf_memory *memory;
|
||||
void *udata;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Main entry points
|
||||
*
|
||||
*/
|
||||
|
||||
/** Initialize a memory structure, given an array of longs */
|
||||
void forf_memory_init(struct forf_memory *m,
|
||||
long *values,
|
||||
size_t size);
|
||||
|
||||
/** Initialize a stack, given an array of values */
|
||||
void forf_stack_init(struct forf_stack *s,
|
||||
struct forf_value *values,
|
||||
size_t size);
|
||||
|
||||
void forf_stack_reset(struct forf_stack *s);
|
||||
void forf_stack_copy(struct forf_stack *dst, struct forf_stack *src);
|
||||
int forf_stack_push(struct forf_stack *s, struct forf_value *v);
|
||||
int forf_stack_pop(struct forf_stack *s, struct forf_value *v);
|
||||
|
||||
/** Pop a number off the data stack */
|
||||
long forf_pop_num(struct forf_env *env);
|
||||
|
||||
/** Push a number onto the data stack */
|
||||
void forf_push_num(struct forf_env *env, long i);
|
||||
|
||||
/** Pop a whole stack */
|
||||
struct forf_stack forf_pop_stack(struct forf_env *env);
|
||||
|
||||
|
||||
/** The base lexical environment */
|
||||
extern struct forf_lexical_env forf_base_lexical_env[];
|
||||
|
||||
/** Extend a lexical environment */
|
||||
int
|
||||
forf_extend_lexical_env(struct forf_lexical_env *dest,
|
||||
struct forf_lexical_env *src,
|
||||
size_t size);
|
||||
|
||||
/** Initialize a forf runtime environment.
|
||||
*
|
||||
* data, cmd, and mem should have already been initialized
|
||||
*/
|
||||
void forf_env_init(struct forf_env *env,
|
||||
struct forf_lexical_env *lenv,
|
||||
struct forf_stack *data,
|
||||
struct forf_stack *cmd,
|
||||
struct forf_memory *mem,
|
||||
void *udata);
|
||||
|
||||
/** The type of a getch function (used for parsing) */
|
||||
typedef int (forf_getch_func)(void *);
|
||||
|
||||
/** Parse something by calling getch(datum)
|
||||
*
|
||||
* Returns the character at which an error was encountered, or
|
||||
* 0 for successful parse.
|
||||
*/
|
||||
int forf_parse_stream(struct forf_env *env,
|
||||
forf_getch_func *getch,
|
||||
void *datum);
|
||||
|
||||
/** Parse a buffer */
|
||||
int forf_parse_buffer(struct forf_env *env,
|
||||
char *buf,
|
||||
size_t len);
|
||||
|
||||
/** Parse a string */
|
||||
int forf_parse_string(struct forf_env *env,
|
||||
char *str);
|
||||
|
||||
/** Parse a FILE * */
|
||||
int forf_parse_file(struct forf_env *env,
|
||||
FILE *f);
|
||||
|
||||
/** Evaluate the topmost value on the command stack */
|
||||
int forf_eval_once(struct forf_env *env);
|
||||
|
||||
/** Evaluate the entire command stack */
|
||||
int forf_eval(struct forf_env *env);
|
||||
|
||||
#endif
|
|
@ -2,7 +2,22 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Tank Designer</title>
|
||||
<link rel="stylesheet" href="tanks.css" type="text/css">
|
||||
<link rel="stylesheet" href="dirtbags.css" type="text/css">
|
||||
<style type="text/css">
|
||||
#preview {
|
||||
float: right;
|
||||
}
|
||||
#sensors input {
|
||||
width: 5em;
|
||||
}
|
||||
#program textarea {
|
||||
width: 100%;
|
||||
min-height: 20em;
|
||||
}
|
||||
td {
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
<script type="application/javascript" src="tanks.js"></script>
|
||||
<script type="application/javascript" src="designer.js"></script>
|
||||
<script type="application/javascript">
|
||||
|
@ -10,6 +25,7 @@
|
|||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Tank Designer</h1>
|
||||
<div id="preview"><canvas id="design"></canvas><p id="debug"></p></div>
|
||||
<form>
|
||||
<fieldset id="metadata">
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
/**** document ****/
|
||||
|
||||
html {
|
||||
background: #222 url(grunge.png) repeat-x;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
color: #fff;
|
||||
margin: 50px 0 0 110px;
|
||||
padding: 10px;
|
||||
max-width: 700px;
|
||||
}
|
||||
|
||||
/**** heading ****/
|
||||
|
||||
h1:first-child {
|
||||
text-transform: lowercase;
|
||||
font-size: 1.6em;
|
||||
/* background-color: #222; */
|
||||
/* opacity: 0.9; */
|
||||
padding: 3px;
|
||||
color: #2a2;
|
||||
margin: 0 0 1em 70px;
|
||||
}
|
||||
|
||||
h1:first-child:before {
|
||||
color: #fff;
|
||||
letter-spacing: -0.1em;
|
||||
content: "Dirtbags: ";
|
||||
}
|
||||
|
||||
/*** left side bar ***/
|
||||
|
||||
#navigation {
|
||||
position: absolute;
|
||||
background: #222;
|
||||
opacity: 0.9;
|
||||
top: 80px;
|
||||
left: 0px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#navigation h3 {
|
||||
font-size: 100%;
|
||||
border-bottom: 2px solid #444;
|
||||
}
|
||||
|
||||
#navigation ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#navigation li a {
|
||||
display: block;
|
||||
height: 25px;
|
||||
width: 90px;
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
background: inherit;
|
||||
border-right: 4px solid #444;
|
||||
color: #999;
|
||||
text-transform: lowercase;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
#navigation li a:hover {
|
||||
color: #f4f4f4;
|
||||
background: #333;
|
||||
border-right: 4px solid #2a2;
|
||||
}
|
||||
|
||||
#navigation li .active {
|
||||
color: #999;
|
||||
background: #333;
|
||||
border-right: 4px solid #444;
|
||||
}
|
||||
|
||||
|
||||
/**** body ****/
|
||||
|
||||
a img {
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #2a2;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #fff;
|
||||
background: #2a2;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
h1, h2, h3 {
|
||||
color: #999;
|
||||
letter-spacing: -0.05em;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.readme {
|
||||
color: #fff;
|
||||
background-color: #555;
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
color: #fff;
|
||||
background-color: #222;
|
||||
border: solid #ccc 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;
|
||||
color: #f4f4f4;
|
||||
}
|
||||
|
||||
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;
|
||||
caption-side: bottom;
|
||||
}
|
||||
|
||||
.left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.scoreboard {
|
||||
background: #222;
|
||||
}
|
||||
|
||||
.scoreboard td {
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
#battlefield {
|
||||
border: 2px solid green;
|
||||
}
|
||||
|
||||
.solved {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
table.pollster {
|
||||
margin-left: 5em;
|
||||
}
|
||||
|
||||
table.pollster td {
|
||||
padding: 2px 1em 2px 5px;
|
||||
}
|
||||
|
||||
table.pollster thead {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
@ -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,],]];
|
|
@ -0,0 +1 @@
|
|||
Subproject commit fb482e222f4357553d717a0cb9daac1721973d23
|
|
@ -0,0 +1,16 @@
|
|||
#! /bin/sh
|
||||
|
||||
cat <<EOF
|
||||
<html>
|
||||
<head>
|
||||
<title>Forf Manual</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="dirtbags.css" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
EOF
|
||||
markdown forf/forf.txt
|
||||
cat <<EOF
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
Binary file not shown.
After Width: | Height: | Size: 6.6 KiB |
|
@ -0,0 +1,146 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Tanks Introduction</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="dirtbags.css" type="text/css">
|
||||
<script type="application/javascript" src="tanks.js"></script>
|
||||
<script type="application/javascript" src="figures.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Tanks Introduction</h1>
|
||||
|
||||
<table class="figure">
|
||||
<caption>"ChashTank" dominates this short round.</caption>
|
||||
<tr>
|
||||
<td>
|
||||
<canvas id="shortround"></canvas>
|
||||
<script type="text/javascript">
|
||||
start("shortround", shortround);
|
||||
</script>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Tanks are programmed in Forf, a stack-based language similar to
|
||||
PostScript. Please read the <a href="forf.html">Forf manual</a>
|
||||
to learn more about forf, and the <a href="procs.html">Tanks
|
||||
procedure reference</a> for a description of Tanks extensions.
|
||||
</p>
|
||||
|
||||
<h2>Quick Start for the Impatient</h2>
|
||||
|
||||
<table class="figure left">
|
||||
<caption>"Crashmaster" pwns the lame default tank provided in this
|
||||
section.</caption>
|
||||
<tr>
|
||||
<td>
|
||||
<canvas id="default"></canvas>
|
||||
<script type="text/javascript">
|
||||
start("default", default_);
|
||||
</script>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
To get started, head over to the <a href="design.html">Tank
|
||||
Designer</a> and enter the following example tank. This tank will
|
||||
move around, turn the turret, and fire if there's something in
|
||||
front of it.
|
||||
</p>
|
||||
|
||||
<pre style="clear: both;">
|
||||
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 )
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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 <a href="forf.html">Forf manual</a> and the
|
||||
<a href="procs.html">Tank procedure reference</a>.
|
||||
</p>
|
||||
|
||||
<h2>Tank Specifications</h2>
|
||||
|
||||
<table class="figure">
|
||||
<caption>"Ant Lion" nails "Rabbit With Gun".</caption>
|
||||
<tr>
|
||||
<td>
|
||||
<canvas id="antlion"></canvas>
|
||||
<script type="text/javascript">
|
||||
start("antlion", antlion);
|
||||
</script>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<dl style="clear: both;">
|
||||
<dt>Tank size</dt>
|
||||
<dd>
|
||||
The targettable area of the tank—the part which can be hit by a
|
||||
cannon—is a circle about 7½ meters in radius.
|
||||
</dd>
|
||||
|
||||
<dt>Speed</dt>
|
||||
<dd>
|
||||
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.
|
||||
</dd>
|
||||
|
||||
<dt>Sensors</dt>
|
||||
<dd>
|
||||
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.
|
||||
</dd>
|
||||
|
||||
<dt>Turret</dt>
|
||||
<dd>
|
||||
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 60° per turn.
|
||||
</dd>
|
||||
|
||||
<dt>Cannon range and recharging</dt>
|
||||
<dd>
|
||||
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.
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
Good luck blowing everybody up!
|
||||
</html>
|
|
@ -0,0 +1,72 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Tanks Procedure Reference</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="dirtbags.css" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Tanks Procedure Reference</h1>
|
||||
|
||||
<p>
|
||||
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 <a href="forf.html">Forf manual</a> for more information about
|
||||
the base language.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For tank specifications (sensor range, maximum speeds, etc.), see
|
||||
the <a href="intro.html">introduction</a>.
|
||||
</p>
|
||||
|
||||
|
||||
<h2>Limits</h2>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Forf Tanks provides 10 memory registers (0-9) which persist across
|
||||
invocations of your tank's program.
|
||||
</p>
|
||||
|
||||
|
||||
<h2>Additional Procedures</h2>
|
||||
|
||||
<dl>
|
||||
<dt>fire-ready?</dt>
|
||||
<dd>Returns 1 if the tank can fire, 0 if not.</dd>
|
||||
|
||||
<dt>fire!</dt>
|
||||
<dd>Fires the cannon.</dd>
|
||||
|
||||
<dt>l r set-speed!</dt>
|
||||
<dd>Sets the speed of the left and right treads (range: -100 to
|
||||
100).</dd>
|
||||
|
||||
<dt>get-turret</dt>
|
||||
<dd>Returns the current angle of the turret.</dd>
|
||||
|
||||
<dt>a set-turret!</dt>
|
||||
<dd>Set the turret to a degrees.</dd>
|
||||
|
||||
<dt>n sensor?</dt>
|
||||
<dd>Returns 1 if sensor n is triggered, 0 if not.</dd>
|
||||
|
||||
<dt>s set-led!</dt>
|
||||
<dd>Turns off the LED if s is 0, on for any other value.</dd>
|
||||
|
||||
<dt>n random</dt>
|
||||
<dd>Returns a random number in the range [0, n). That is, between
|
||||
0 and n-1, inclusive.</dd>
|
||||
</dl>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
2
round.sh
2
round.sh
|
@ -21,7 +21,7 @@ cat <<EOF >$fn
|
|||
<link rel="stylesheet" href="tanks.css" type="text/css">
|
||||
<script type="application/javascript">
|
||||
function go() {
|
||||
start(
|
||||
start("battlefield",
|
||||
// Start JSON data
|
||||
EOF
|
||||
./run-tanks players/* >>$fn 3>$rfn
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "ctanks.h"
|
||||
#include "cforf.h"
|
||||
#include "forf.h"
|
||||
#include "dump.h"
|
||||
|
||||
#define MAX_TANKS 50
|
||||
|
|
|
@ -19,8 +19,9 @@ BEGIN {
|
|||
|
||||
print " <h2>Resources</h2>";
|
||||
print " <ul>";
|
||||
print " <li><a href=\"intro.html\">Introduction</a></li>";
|
||||
print " <li><a href=\"forf.html\">Forf manual</a></li>";
|
||||
print " <li><a href=\"tanksprocs.html\">Tanks procedures</a></li>";
|
||||
print " <li><a href=\"procs.html\">Tanks procedures</a></li>";
|
||||
print " <li><a href=\"designer.html\">Tanks designer</a></li>";
|
||||
print " </ul>";
|
||||
|
||||
|
|
26
tanks.css
26
tanks.css
|
@ -1,26 +0,0 @@
|
|||
body {
|
||||
background-color: #444444;
|
||||
color: #c0c0c0;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
td {
|
||||
border: solid 1px #c0c0c0;
|
||||
}
|
||||
.swatch {
|
||||
color: #000000;
|
||||
}
|
||||
#preview {
|
||||
float: right;
|
||||
}
|
||||
#sensors input {
|
||||
width: 5em;
|
||||
}
|
||||
#program textarea {
|
||||
width: 100%;
|
||||
min-height: 20em;
|
||||
}
|
||||
a {
|
||||
color: #00c080;
|
||||
}
|
4
tanks.js
4
tanks.js
|
@ -147,8 +147,8 @@ function Tank(ctx, width, height, color, sensors) {
|
|||
}
|
||||
}
|
||||
|
||||
function start(game) {
|
||||
var canvas = document.getElementById('battlefield');
|
||||
function start(id, game) {
|
||||
var canvas = document.getElementById(id);
|
||||
var ctx = canvas.getContext('2d');
|
||||
var loop_id;
|
||||
|
||||
|
|
137
test-tanks.c
137
test-tanks.c
|
@ -1,137 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "ctanks.h"
|
||||
|
||||
#define NTANKS 2
|
||||
|
||||
void
|
||||
test_run(struct tank *tank, void *unused)
|
||||
{
|
||||
tank_set_speed(tank, -60, -61);
|
||||
tank_set_turret(tank, tank->turret.desired + PI/15);
|
||||
if (tank->sensors[0].triggered) {
|
||||
tank_fire(tank);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sitting_duck(struct tank *tank, void *unused)
|
||||
{
|
||||
tank_set_turret(tank, tank->turret.desired + PI/15);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct tanks_game game;
|
||||
struct tank mytanks[NTANKS];
|
||||
int i;
|
||||
|
||||
game.size[0] = 600;
|
||||
game.size[1] = 200;
|
||||
|
||||
printf("[\n");
|
||||
printf("[%d, %d, %d],\n",
|
||||
(int)game.size[0], (int)game.size[1], TANK_CANNON_RANGE);
|
||||
printf("[\n");
|
||||
for (i = 0; i < NTANKS; i += 1) {
|
||||
if (i == 1) {
|
||||
printf(" [\"#888888\",[");
|
||||
tank_init(&mytanks[i], sitting_duck, NULL);
|
||||
} else {
|
||||
int j;
|
||||
|
||||
printf(" [\"#ff4444\",[");
|
||||
tank_init(&mytanks[i], test_run, NULL);
|
||||
|
||||
mytanks[i].sensors[0].angle = 0;
|
||||
mytanks[i].sensors[0].width = PI/10;
|
||||
mytanks[i].sensors[0].range = 50;
|
||||
mytanks[i].sensors[0].turret = 1;
|
||||
|
||||
mytanks[i].sensors[1].angle = 0*PI/2;
|
||||
mytanks[i].sensors[1].width = PI/3;
|
||||
mytanks[i].sensors[1].range = 100;
|
||||
mytanks[i].sensors[1].turret = 1;
|
||||
|
||||
mytanks[i].sensors[2].angle = 1*PI/2;
|
||||
mytanks[i].sensors[2].width = PI/3;
|
||||
mytanks[i].sensors[2].range = 100;
|
||||
mytanks[i].sensors[2].turret = 1;
|
||||
|
||||
mytanks[i].sensors[3].angle = 2*PI/2;
|
||||
mytanks[i].sensors[3].width = PI/3;
|
||||
mytanks[i].sensors[3].range = 100;
|
||||
mytanks[i].sensors[3].turret = 1;
|
||||
|
||||
mytanks[i].sensors[4].angle = 3*PI/2;
|
||||
mytanks[i].sensors[4].width = PI/3;
|
||||
mytanks[i].sensors[4].range = 100;
|
||||
mytanks[i].sensors[4].turret = 1;
|
||||
|
||||
mytanks[i].sensors[5].angle = 0;
|
||||
mytanks[i].sensors[5].width = PI*1.99;
|
||||
mytanks[i].sensors[5].range = 80;
|
||||
mytanks[i].sensors[5].turret = 0;
|
||||
|
||||
for (j = 0; j < TANK_MAX_SENSORS; j += 1) {
|
||||
struct sensor *s = &(mytanks[i].sensors[j]);
|
||||
|
||||
if (s->range) {
|
||||
printf("[%d, %.2f, %.2f, %d],",
|
||||
(int)(s->range),
|
||||
s->angle,
|
||||
s->width,
|
||||
s->turret);
|
||||
}
|
||||
}
|
||||
}
|
||||
mytanks[i].position[0] = (game.size[0] / NTANKS) * i + 50;
|
||||
mytanks[i].position[1] = 50;
|
||||
/* XXX: print sensors */
|
||||
printf("]],\n");
|
||||
}
|
||||
printf("],\n");
|
||||
printf("// Rounds\n");
|
||||
printf("[\n");
|
||||
|
||||
for (i = 0; i < 100; i += 1) {
|
||||
int j;
|
||||
|
||||
tanks_run_turn(&game, mytanks, NTANKS);
|
||||
printf("[\n");
|
||||
for (j = 0; j < NTANKS; j += 1) {
|
||||
struct tank *t = &(mytanks[j]);
|
||||
|
||||
if (t->killer) {
|
||||
printf(" 0,\n");
|
||||
} else {
|
||||
int k;
|
||||
int flags = 0;
|
||||
int sensors = 0;
|
||||
|
||||
for (k = 0; k < TANK_MAX_SENSORS; k += 1) {
|
||||
if (t->sensors[k].triggered) {
|
||||
sensors |= (1 << k);
|
||||
}
|
||||
}
|
||||
if (t->turret.firing) {
|
||||
flags |= 1;
|
||||
}
|
||||
if (t->led) {
|
||||
flags |= 2;
|
||||
}
|
||||
printf(" [%d,%d,%.2f,%.2f,%d,%d],\n",
|
||||
(int)(t->position[0]),
|
||||
(int)(t->position[1]),
|
||||
t->angle,
|
||||
t->turret.current,
|
||||
flags,
|
||||
sensors);
|
||||
}
|
||||
}
|
||||
printf("],\n");
|
||||
}
|
||||
printf("]]\n");
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue