icfp11/src/control_parser.rl

215 rader
6.3 KiB
Ragel

#include "control_parser.h"
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
typedef control_parser_ctx context;
static void extract(context *ctx, char *fpc) {
gssize curpos = (fpc - ctx->buffer->str);
gssize len = curpos - ctx->mark;
g_string_truncate(ctx->tmp, 0);
g_string_append_len(ctx->tmp, ctx->buffer->str + ctx->mark, len);
ctx->mark = -1;
/* printf("Read chunk '%s'\n", ctx->tmp->str); */
}
static double extract_double(context *ctx, char *fpc) {
extract(ctx, fpc);
return strtod(ctx->tmp->str, NULL);
}
static timestamp extract_ts(context *ctx, char *fpc) {
extract(ctx, fpc);
return atoi(ctx->tmp->str);
}
%%{
machine control_parser;
variable cs ctx->cs;
action done {
t->alive = 0;
/* fprintf(stderr, "Run finished\n"); */
fbreak;
}
action mark { ctx->mark = fpc - ctx->buffer->str; }
action telemetrystart { ctx->tm = telemetry_new(); }
action telemetrystop {
g_queue_push_tail(&t->telemetry, ctx->tm);
if (!t->alive) {
t->vehicle.accel = ctx->tm->vehicle.accel;
t->vehicle.turn = ctx->tm->vehicle.turn;
gettimeofday(&t->started, NULL);
/* fprintf(stderr, "New run\n"); */
} else {
/* fprintf(stderr, "time difference [ms]: %i\n", getcurts(t) - ctx->tm->ts); */
fprintf(stderr, "Miss predict: dx=%f, dy=%f, ddir=%f, steps=%u\n",
t->sim.tm.vehicle.x - t->vehicle.x,
t->sim.tm.vehicle.y - t->vehicle.y,
t->sim.tm.vehicle.dir - t->vehicle.dir,
t->sim.steps);
}
/* Reset simulation */
t->sim.tm.ts = ctx->tm->ts;
t->sim.tm.vehicle = ctx->tm->vehicle;
g_array_set_size(t->sim.tm.objects, 0);
g_array_append_vals(t->sim.tm.objects, ctx->tm->objects->data, ctx->tm->objects->len);
t->sim.steps = 0;
t->last_ts = ctx->tm->ts;
ctx->tm = NULL;
t->alive = 1;
}
action vehicle {
ctx->tm->ts = ctx->ts;
ctx->tm->vehicle.x = ctx->x;
ctx->tm->vehicle.y = ctx->y;
ctx->tm->vehicle.dir = ctx->dir;
ctx->tm->vehicle.speed = ctx->speed;
t->vehicle.x = ctx->x;
t->vehicle.y = ctx->y;
t->vehicle.dir = ctx->dir;
t->vehicle.speed = ctx->speed;
/* printf("Vehicle at %f / %f\n", ctx->x, ctx->y); */
}
SP = " ";
double = '-'? (digit | '.')*;
dx = double >mark % { t->map.dx = extract_double(ctx, fpc); };
dy = double >mark % { t->map.dy = extract_double(ctx, fpc); };
min_sensor = double >mark % { t->map.min_sensor = extract_double(ctx, fpc); };
max_sensor = double >mark % { t->map.max_sensor = extract_double(ctx, fpc); };
max_speed = double >mark % { t->map.max_speed = extract_double(ctx, fpc); };
max_turn = double >mark % { t->map.max_turn = extract_double(ctx, fpc); };
max_hard_turn = double >mark % { t->map.max_hard_turn = extract_double(ctx, fpc); };
init = "I" SP dx SP dy SP double SP min_sensor SP max_sensor SP max_speed SP max_turn SP max_hard_turn SP ";";
x = double >mark % { ctx->x = extract_double(ctx, fpc); };
y = double >mark % { ctx->y = extract_double(ctx, fpc); };
r = double >mark % { ctx->r = extract_double(ctx, fpc); };
dir = double >mark % { ctx->dir = extract_double(ctx, fpc); };
speed = double >mark % { ctx->speed = extract_double(ctx, fpc); };
ctl = (
"a" @ { ctx->tm->vehicle.accel = ACCEL; }
| "-" @ { ctx->tm->vehicle.accel = ROLL; }
| "b" @ { ctx->tm->vehicle.accel = BRAKE; }
) (
"L" @ { ctx->tm->vehicle.turn = TURN_HARD_LEFT; }
| "l" @ { ctx->tm->vehicle.turn = TURN_LEFT; }
| "-" @ { ctx->tm->vehicle.turn = TURN_STRAIGHT; }
| "r" @ { ctx->tm->vehicle.turn = TURN_RIGHT; }
| "R" @ { ctx->tm->vehicle.turn = TURN_HARD_RIGHT; }
);
timestamp = (digit*) >mark % { ctx->ts = extract_ts(ctx, fpc); };
score = (digit*) >mark % { printf("Score %u\n", extract_ts(ctx, fpc)); };
boulder = "b" SP x SP y SP r SP % {
object *o = object_new(BOLDER, ctx->x, ctx->y, ctx->r, 0, 0);
/* g_array_append_vals(ctx->tm->objects, o, 1); */
g_hash_table_replace(t->map.solid_objects, o, o);
};
crater = "c" SP x SP y SP r SP % {
object *o = object_new(CRATER, ctx->x, ctx->y, ctx->r, 0, 0);
/* g_array_append_vals(ctx->tm->objects, o, 1); */
g_hash_table_replace(t->map.solid_objects, o, o);
};
homebase = "h" SP x SP y SP r SP; # ignore it
martian = "m" SP x SP y SP dir SP speed SP % {
object o = { MARTIAN, ctx->x, ctx->y, MARTIAN_RADIUS, ctx->dir, ctx->speed };
g_array_append_val(ctx->tm->objects, o);
};
object = boulder | crater | homebase | martian;
objects = object*;
telemetry = ( ("T" SP timestamp SP ctl SP x SP y SP dir SP speed SP) %vehicle objects) >telemetrystart ";" % telemetrystop;
# crash
Boulder = "B" SP timestamp SP ";";
# fell
Crater = "C" SP timestamp SP ";";
# killed by martian
Kill = "K" SP timestamp SP ";";
Success = "S" SP timestamp SP ";";
End = "E" SP timestamp SP score SP ";";
main := init? (telemetry | Boulder)* (Crater | Kill | Success)? End @ done;
}%%
%% write data;
static int control_parser_has_error(context *ctx) {
return ctx->cs == control_parser_error;
}
static int control_parser_is_finished(context *ctx) {
return ctx->cs >= control_parser_first_final;
}
void control_parser_new(trial *t) {
context *ctx = t->parse_ctx = g_slice_new(context);
%% write init;
ctx->buffer = g_string_sized_new(0);
ctx->tmp = g_string_sized_new(0);
ctx->mark = -1;
ctx->pos = 0;
}
void control_parser_reset(trial *t) {
context *ctx = t->parse_ctx;
%% write init;
g_string_truncate(ctx->tmp, 0);
ctx->mark = -1;
/* fprintf(stderr, "Parser reset\n"); */
}
void control_parser_free(trial *t) {
g_string_free(t->parse_ctx->buffer, TRUE);
g_string_free(t->parse_ctx->tmp, TRUE);
g_slice_free(context, t->parse_ctx);
}
run_t control_parse(trial *t) {
context *ctx = t->parse_ctx;
gsize wehave;
if (0 < (wehave = ctx->buffer->len - ctx->pos)) {
char *p, *pe;
p = ctx->buffer->str + ctx->pos;
pe = p + wehave;
/* fprintf(stderr, "Parsing '%s' (len=%zu)\n", p, wehave); */
%% write exec;
ctx->pos = p - ctx->buffer->str;
if (ctx->mark == -1) {
g_string_erase(ctx->buffer, 0, ctx->pos);
ctx->pos = 0;
} else if (ctx->mark) {
g_string_erase(ctx->buffer, 0, ctx->mark);
ctx->pos -= ctx->mark;
ctx->mark = 0;
}
} else {
fprintf(stderr, "No data to parse\n");
}
if (control_parser_has_error(ctx)) {
fprintf(stderr, "Parse error: '%s'\n", ctx->buffer->str + ctx->pos);
shutdown(t->socket, SHUT_RDWR);
close(t->socket);
exit(126);
return RUN_ERROR;
}
if (control_parser_is_finished(ctx)) return RUN_DONE;
return RUN_GO_ON;
}