From c831b7e4acda03203b23ed12fad25719153c6f95 Mon Sep 17 00:00:00 2001 From: Adam Thomas Date: Wed, 28 May 2014 10:44:06 +1000 Subject: [PATCH 1/7] fixed 'loaded first' bug in shot detection If two tanks would shoot each other in the turn, the tank that was first would always win the shootout. This patch changes it so they both die. --- ctanks.c | 54 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/ctanks.c b/ctanks.c index f7d1049..be7a165 100644 --- a/ctanks.c +++ b/ctanks.c @@ -105,17 +105,13 @@ rotate_point(float angle, float point[2]) point[1] = new[1]; } - static void -tanks_fire_cannon(struct tanks_game *game, - struct tank *this, - struct tank *that, - float vector[2], - float dist2) +tanks_collision_detect(struct tanks_game *game, + struct tank *this, + struct tank *that, + float vector[2], + float dist2) { - float theta = this->angle + this->turret.current; - float rpos[2]; - /* If someone's a crater, this is easy */ if (this->killer || that->killer) { return; @@ -128,18 +124,32 @@ tanks_fire_cannon(struct tanks_game *game, that->killer = this; that->cause_death = "collision"; + } +} - return; +static int +tanks_fire_cannon(struct tanks_game *game, + struct tank *this, + struct tank *that, + float vector[2], + float dist2) +{ + float theta = this->angle + this->turret.current; + float rpos[2]; + + /* If someone's a crater, this is easy */ + if (this->killer || that->killer) { + return 0; } /* No need to check if it's not even firing */ if (! this->turret.firing) { - return; + return 0; } /* Also no need to check if it's outside cannon range */ if (dist2 > TANK_CANNON_ADJ2) { - return; + return 0; } /* Did this shoot that? Rotate point by turret degrees, and if |y| < @@ -147,10 +157,7 @@ tanks_fire_cannon(struct tanks_game *game, rpos[0] = vector[0]; rpos[1] = vector[1]; rotate_point(-theta, rpos); - if ((rpos[0] > 0) && (fabsf(rpos[1]) < TANK_RADIUS)) { - that->killer = this; - that->cause_death = "shot"; - } + return ((rpos[0] > 0) && (fabsf(rpos[1]) < TANK_RADIUS)); } static void @@ -428,10 +435,21 @@ tanks_run_turn(struct tanks_game *game, struct tank *tanks, int ntanks) struct tank *that = &tanks[j]; compute_vector(game, vector, &dist2, this, that); - tanks_fire_cannon(game, this, that, vector, dist2); + tanks_collision_detect(game, that, this, vector, dist2); + int a,b; + a = tanks_fire_cannon(game, this, that, vector, dist2); vector[0] = -vector[0]; vector[1] = -vector[1]; - tanks_fire_cannon(game, that, this, vector, dist2); + b = tanks_fire_cannon(game, that, this, vector, dist2); + + if(a){ + that->killer = this; + that->cause_death = "shot"; + } + if(b){ + this->killer = that; + this->cause_death = "shot"; + } } } } From b2785f74969a4f7c7bfaafed5e79dfa62ceb3bf6 Mon Sep 17 00:00:00 2001 From: Adam Thomas Date: Fri, 30 May 2014 15:48:06 +1000 Subject: [PATCH 2/7] added chart of kills --- .gitignore | 4 ++ Makefile | 4 +- chord.html.m4 | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++ killmatrix.pl | 55 ++++++++++++++++++++++++ run-tanks | 7 +++- 5 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 chord.html.m4 create mode 100755 killmatrix.pl diff --git a/.gitignore b/.gitignore index ce47879..d5c648c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ *~ *# *.o +*.swp round-*.html +results-*.txt next-round points forftanks @@ -14,3 +16,5 @@ summary.html designer.html intro.html procs.html +chord.html +killmatrix.js diff --git a/Makefile b/Makefile index fded3c4..5826a3d 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ BINARIES = forftanks designer.cgi -HTML = forf.html procs.html intro.html designer.html +HTML = forf.html procs.html intro.html designer.html chord.html WWW = style.css grunge.png designer.js figures.js tanks.js nav.html.inc CFLAGS = -Wall @@ -28,5 +28,5 @@ ctanks.o: ctanks.h m4 $< > $@ clean: - rm -f *.o next-round round-*.html + rm -f *.o next-round round-*.html results-*.txt rm -f $(BINARIES) $(HTML) diff --git a/chord.html.m4 b/chord.html.m4 new file mode 100644 index 0000000..9118a5c --- /dev/null +++ b/chord.html.m4 @@ -0,0 +1,113 @@ + + + + + + + + + + +

Killer Chart

+include(nav.html.inc) + + + diff --git a/killmatrix.pl b/killmatrix.pl new file mode 100755 index 0000000..1f51db1 --- /dev/null +++ b/killmatrix.pl @@ -0,0 +1,55 @@ +#!/usr/bin/perl + +foreach $file (@ARGV) { + $tanks = {}; + open FH, "<$file"; + foreach () { + chomp; + @tank{"id","path","cause","killer","errorpos","error"} = split; + $tanks->{$tank{"id"}} = {%tank}; + $paths->{$tank{"path"}}++}; + foreach (values %$tanks) { + next if $_->{"killer"} eq "(nil)"; + next unless $_->{"cause"} eq "shot"; + $data->{$tanks->{$_->{"killer"}}->{"path"}}->{$_->{"path"}}++ + } + }; + @paths = keys %$paths; + print + "var names = [", + (join + ",", + map { + open NF, $_."/name"; + $name = ; + chomp $name;"\"$name\"" + } + @paths + ), + "];\n"; + + print "var colors = [", + (join + ",", + map { + open CF, $_."/color"; + $color = ; + $color ||= "#c0c0c0"; + chomp $color; + "\"$color\"" + } @paths + ), + "];\n"; + + print + "var matrix = [\n [", + (join + ("],\n [", + map { + join( + ",", + map{$_||=0} @{$data->{$_}}{@paths} + ) + } + @paths) + ),"]\n];\n"; diff --git a/run-tanks b/run-tanks index 854aec9..a7b7bb5 100755 --- a/run-tanks +++ b/run-tanks @@ -22,7 +22,7 @@ fi expr $next + 1 > next-round fn=$(printf "round-%04d.html" $next) -rfn=results$$.txt +rfn=$(printf "results-%04d.txt" $next) echo -n "Running round $next... " @@ -52,7 +52,6 @@ window.onload = go;

0 fps

EOF rank.awk $rfn >>$fn -rm -f $rfn cat $NAV_HTML_INC >>$fn cat <>$fn @@ -62,5 +61,9 @@ EOF summary.awk $tanks > summary.html.$$ mv summary.html.$$ summary.html +./killmatrix.pl results-*.txt > killmatrix$$.js + +mv killmatrix$$.js killmatrix.js + echo "done." From fb7e17bd6f6bd75512ea19f469d7822d28309b6c Mon Sep 17 00:00:00 2001 From: Adam Thomas Date: Fri, 30 May 2014 15:50:33 +1000 Subject: [PATCH 3/7] copy awk scripts on install --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 5826a3d..c865231 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,8 @@ install: install -d $(DESTDIR)/usr/bin install run-tanks $(DESTDIR)/usr/bin install forftanks $(DESTDIR)/usr/bin + install $(SCRIPTS) $(DESTDIR)/usr/bin + install -d $(DESTDIR)/usr/lib/tanks install designer.cgi $(DESTDIR)/usr/lib/tanks From e217298f1e2578f01b6b3079cf0b689431f318a0 Mon Sep 17 00:00:00 2001 From: Luke T Angove Date: Tue, 3 Jun 2014 21:57:08 +1000 Subject: [PATCH 4/7] Fixed bug in makefile. Would not compile because using LDFLAGS instead of LDLIBS. LDFLAGS for things like library directories, LDLIBS for libraries. --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c865231..8f89fd1 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ install: cp -r examples $(DESTDIR)/usr/lib/tanks/examples forftanks: forftanks.o ctanks.o forf.o -forftanks: LDFLAGS = -lm +forftanks: LDLIBS = -lm forftanks.o: forf.h ctanks.h forf.o: forf.c forf.h @@ -29,6 +29,7 @@ ctanks.o: ctanks.h %.html: %.html.m4 m4 $< > $@ +.PHONY: clean clean: rm -f *.o next-round round-*.html results-*.txt rm -f $(BINARIES) $(HTML) From 75e49a47060189f861212921e4085ae142f2b866 Mon Sep 17 00:00:00 2001 From: Adam Thomas Date: Wed, 4 Jun 2014 12:58:12 +1000 Subject: [PATCH 5/7] fix escaping in awk scripts --- rank.awk | 6 +++--- summary.awk | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rank.awk b/rank.awk index 1ad320a..f7e44ad 100755 --- a/rank.awk +++ b/rank.awk @@ -5,9 +5,9 @@ BEGIN { } function esc(s) { - gsub(/&/, "&", s); - gsub(//, ">", s); + gsub(/&/, "\\&", s); + gsub(//, "\\>", s); return s; } diff --git a/summary.awk b/summary.awk index fadcc3d..b8486f3 100755 --- a/summary.awk +++ b/summary.awk @@ -1,9 +1,9 @@ #! /usr/bin/awk -f function esc(s) { - gsub(/&/, "&", s); - gsub(//, ">", s); + gsub(/&/, "\\&", s); + gsub(//, "\\>", s); return s; } From d8827aebf6085b97a789982eb07b8cc77a504003 Mon Sep 17 00:00:00 2001 From: Adam Thomas Date: Thu, 5 Jun 2014 14:37:56 +1000 Subject: [PATCH 6/7] add current.html with just the canvas --- Makefile | 2 +- run-tanks | 45 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index c865231..70e435e 100644 --- a/Makefile +++ b/Makefile @@ -30,5 +30,5 @@ ctanks.o: ctanks.h m4 $< > $@ clean: - rm -f *.o next-round round-*.html results-*.txt + rm -f *.o next-round round-*.html round-*.json results-*.txt current.html rm -f $(BINARIES) $(HTML) diff --git a/run-tanks b/run-tanks index a7b7bb5..edc5a20 100755 --- a/run-tanks +++ b/run-tanks @@ -23,9 +23,12 @@ expr $next + 1 > next-round fn=$(printf "round-%04d.html" $next) rfn=$(printf "results-%04d.txt" $next) - +jfn=$(printf "round-%04d.json" $next) +cfn="current$$.html"; echo -n "Running round $next... " +$TANKS_GAME $tanks >>$jfn 3>$rfn + cat <$fn @@ -38,7 +41,7 @@ cat <$fn start("battlefield", // Start JSON data EOF -$TANKS_GAME $tanks >>$fn 3>$rfn +cat $jfn >> $fn cat <>$fn // end JSON data ); @@ -58,6 +61,44 @@ cat <>$fn EOF +cat <$cfn + + + + Tanks Round $next + + + + + + +
+EOF +cat <>$cfn + + +EOF + +mv "current$$.html" "current.html" + summary.awk $tanks > summary.html.$$ mv summary.html.$$ summary.html From 880bba12fdf66a171c8726c44bfc580470c94cb5 Mon Sep 17 00:00:00 2001 From: Luke T Angove Date: Sat, 21 Jun 2014 20:46:13 +1000 Subject: [PATCH 7/7] Major changes to structure. Moved file I/O out of forftanks.c into tankdir.c and tankjson.c. If no files are supplied to forftanks, it now waits for a JSON stream on stdin. Also changed make file to include required libraries (and compile in the right order). Install has been changed. --- Makefile | 56 ++++++++++----- README.txt | 2 +- forftanks.c | 194 +++++++++++++++++++++++++++------------------------- tankdef.h | 27 ++++++++ tankdir.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++ tankdir.h | 12 ++++ tankjson.c | 155 +++++++++++++++++++++++++++++++++++++++++ tankjson.h | 11 +++ 8 files changed, 533 insertions(+), 113 deletions(-) create mode 100644 tankdef.h create mode 100644 tankdir.c create mode 100644 tankdir.h create mode 100644 tankjson.c create mode 100644 tankjson.h diff --git a/Makefile b/Makefile index 8f89fd1..3bc761f 100644 --- a/Makefile +++ b/Makefile @@ -1,35 +1,55 @@ BINARIES = forftanks designer.cgi HTML = forf.html procs.html intro.html designer.html chord.html WWW = style.css grunge.png designer.js figures.js tanks.js nav.html.inc +SCRIPTS = killmatrix.pl rank.awk summary.awk winner.awk -CFLAGS = -Wall +CFLAGS = -Wall -std=gnu90 -g all: $(BINARIES) $(HTML) -install: - install -d $(DESTDIR)/usr/bin - install run-tanks $(DESTDIR)/usr/bin - install forftanks $(DESTDIR)/usr/bin - install $(SCRIPTS) $(DESTDIR)/usr/bin +forftanks: forftanks.o ctanks.o forf.o tankdir.o tankjson.o +forftanks: LDLIBS = -lm -ljansson - - install -d $(DESTDIR)/usr/lib/tanks - install designer.cgi $(DESTDIR)/usr/lib/tanks - install $(HTML) $(DESTDIR)/usr/lib/tanks - install $(WWW) $(DESTDIR)/usr/lib/tanks - cp -r examples $(DESTDIR)/usr/lib/tanks/examples - -forftanks: forftanks.o ctanks.o forf.o -forftanks: LDLIBS = -lm - -forftanks.o: forf.h ctanks.h +forftanks.o: forf.h ctanks.h tankdef.h tankdir.h tankjson.h forf.o: forf.c forf.h ctanks.o: ctanks.h +tankdir.o: tankdef.h tankdir.h +tankjson.o: tankdef.h tankjson.h %.html: %.html.m4 m4 $< > $@ -.PHONY: clean +.PHONY: install clean check-env +install: check-env + install -d $(DESTDIR)/bin + install run-tanks $(DESTDIR)/bin + install forftanks $(DESTDIR)/bin + install $(SCRIPTS) $(DESTDIR)/bin + install -d $(DOCROOT) + install designer.cgi $(CGIBIN) + install $(HTML) $(DOCROOT) + install $(WWW) $(DOCROOT) + cp -r examples $(DOCROOT)/examples + clean: rm -f *.o next-round round-*.html results-*.txt rm -f $(BINARIES) $(HTML) + +check-env: +ifndef DESTDIR + $(error DESTDIR is undefined) +endif +ifndef DOCROOT +ifndef DESTDIR + $(error DOCROOT is undefined) +else +DOCROOT = $(DESTDIR) +endif +endif +ifndef CGIBIN +ifndef DESTDIR + $(error CGIBIN is undefined) +else +CGIBIN = $(DESTDIR) +endif +endif diff --git a/README.txt b/README.txt index f446fcb..afaf3b5 100644 --- a/README.txt +++ b/README.txt @@ -18,7 +18,7 @@ hodgepodge of C, Bourne shell, and awk, but at least each piece is fairly simple to audit. -### round.sh tank1 tank2 ... +### run-tanks tank1 tank2 ... Runs a single round, awards points with rank.awk, and creates a new summary.html with summary.awk. This is the main interface that you want diff --git a/forftanks.c b/forftanks.c index 65205fc..497bc27 100644 --- a/forftanks.c +++ b/forftanks.c @@ -20,14 +20,20 @@ #include #include #include +#include #include "ctanks.h" #include "forf.h" #include "dump.h" +#include "tankdef.h" +#include "tankdir.h" +#include "tankjson.h" #define MAX_TANKS 50 #define ROUNDS 500 #define SPACING 150 +#define MAX_JSON_SIZE 10000 + #define LENV_SIZE 100 #define DSTACK_SIZE 200 @@ -194,34 +200,6 @@ struct forf_lexical_env tanks_lenv_addons[] = { * Filesystem stuff * */ - -int -ft_read_file(char *ptr, size_t size, char *dir, char *fn) -{ - char path[256]; - FILE *f = NULL; - int ret; - int success = 0; - - do { - snprintf(path, sizeof(path), "%s/%s", dir, fn); - f = fopen(path, "r"); - if (! f) break; - - ret = fread(ptr, 1, size - 1, f); - ptr[ret] = '\0'; - if (! ret) break; - - success = 1; - } while (0); - - if (f) fclose(f); - if (! success) { - return 0; - } - return 1; -} - void ft_bricked_tank(struct tank *tank, void *ignored) { @@ -244,33 +222,17 @@ ft_run_tank(struct tank *tank, struct forftank *ftank) } } -int +int //&L Added function ft_read_program(struct forftank *ftank, - struct tank *tank, - struct forf_lexical_env *lenv, - char *path) + struct tank *tank, + struct tankdef *tank_def) { - char progpath[256]; - FILE *f; - - /* Open program */ - snprintf(progpath, sizeof(progpath), "%s/program", path); - f = fopen(progpath, "r"); - if (! f) return 0; - - /* Parse program */ - ftank->error_pos = forf_parse_file(&ftank->env, f); - fclose(f); + ftank->error_pos = forf_parse_string(&ftank->env, tank_def->program); if (ftank->error_pos) { return 0; } - - /* Back up the program so we can run it over and over without - needing to re-parse */ forf_stack_copy(&ftank->_prog, &ftank->_cmd); - tank_init(tank, (tank_run_func *)ft_run_tank, ftank); - return 1; } @@ -292,71 +254,71 @@ ft_tank_init(struct forftank *ftank, tank); } -void -ft_read_sensors(struct tank *tank, - char *path) +void //&L Added function +ft_read_sensors(struct tank *tank, + struct tankdef *tankdef) { int i; for (i = 0; i < TANK_MAX_SENSORS; i += 1) { - int ret; - char fn[10]; - char s[20]; - char *p = s; long range; - long angle; - long width; + double angle; + double width; long turret; - snprintf(fn, sizeof(fn), "sensor%d", i); - ret = ft_read_file(s, sizeof(s), path, fn); - if (! ret) { - s[0] = 0; - } - range = strtol(p, &p, 0); - angle = strtol(p, &p, 0); - width = strtol(p, &p, 0); - turret = strtol(p, &p, 0); + range = tankdef->sensors[i].range; + angle = tankdef->sensors[i].angle; + width = tankdef->sensors[i].width; + turret = tankdef->sensors[i].turret; tank->sensors[i].range = min(range, TANK_SENSOR_RANGE); - tank->sensors[i].angle = deg2rad(angle % 360); - tank->sensors[i].width = deg2rad(width % 360); + tank->sensors[i].angle = deg2rad((long)angle % 360); + tank->sensors[i].width = deg2rad((long)width % 360); tank->sensors[i].turret = (0 != turret); } } -int +char* //&L Added function. +temp_parse_path(char* tankName) +{ + size_t inTankName; + size_t inPath; + char* retVal = (char*)malloc(strlen(tankName)*sizeof(char)); + for(inTankName=0, inPath=0; inTankNamepath = path; - + ftank->path = temp_parse_path(tank_def->name); // No path anymore. /* What is your name? */ - ret = ft_read_file(ftank->name, sizeof(ftank->name), path, "name"); - if (! ret) { - strncpy(ftank->name, path, sizeof(ftank->name)); - } - + strncpy(ftank->name, tank_def->name, sizeof(ftank->name)); /* What is your quest? */ ft_tank_init(ftank, tank, lenv); - ret = ft_read_program(ftank, tank, lenv, path); + ret = ft_read_program(ftank, tank, tank_def); if (ret) { - ft_read_sensors(tank, path); + ft_read_sensors(tank, tank_def); } else { /* Brick the tank */ tank_init(tank, ft_bricked_tank, NULL); } - /* What is your favorite color? */ - ret = ft_read_file(ftank->color, sizeof(ftank->color), path, "color"); - if (! ret) { - strncpy(ftank->color, "#808080", sizeof(ftank->color)); - } - + strncpy(ftank->color, tank_def->color, sizeof(ftank->color)); return 1; } @@ -469,10 +431,24 @@ print_standings(FILE *f, } } +void +delete_tank(struct forftank theTank) { + free(theTank.path); +} + +void +delete_tanks(struct forftank* myftanks, const int ntanks) { + int i; + for(i=0; i 1){ + /* Every argument is a tank directory */ + ntanks = argc-1; // argc[0] is program name, not a tank. + if(ntanks > MAX_TANKS) { + fprintf(stderr, "Too many tanks! Tried to load: %d, Max: %d", + ntanks, MAX_TANKS); + return 1; } + for (i = 0; i < ntanks; i++) { //&L changed loop. + mytankdefs[i] = readTankFromDir(argv[i+1]); + } + } else { // Expecting JSON on stdin. + char* jsonString = malloc(sizeof(char)*MAX_JSON_SIZE); + char c; + long size = 0; + while( (c=fgetc(stdin)) != EOF ) { + jsonString[size] = c; + size++; + if(size>=(MAX_JSON_SIZE-1)) { + fprintf(stderr,"Error: JSON text too large.\n"); + return 1; + } + } + jsonString[size] = '\0'; + ntanks = jsonArraySize(jsonString); // argc[0] is program name, not a tank. + if(ntanks > MAX_TANKS) { + fprintf(stderr, "Too many tanks! Tried to load: %d, Max: %d", + ntanks, MAX_TANKS); + return 1; + } + readTanksFromJSON(mytankdefs, ntanks, jsonString); } - if (0 == ntanks) { fprintf(stderr, "No usable tanks!\n"); return 1; } + for(i=0; i < ntanks; i++) { + ft_read_tank(&myftanks[i], + &mytanks[i], + lenv, + &mytankdefs[i]); + } /* Calculate the size of the game board */ { @@ -580,6 +584,8 @@ main(int argc, char *argv[]) print_standings(standings, myftanks, mytanks, ntanks); } } + + delete_tanks(myftanks, ntanks); return 0; } diff --git a/tankdef.h b/tankdef.h new file mode 100644 index 0000000..e4b6679 --- /dev/null +++ b/tankdef.h @@ -0,0 +1,27 @@ +#ifndef __TANKDEF_H__ +#define __TANKDEF_H__ + +#include "ctanks.h" + +#define MAX_PROGRAM_SIZE 10000 +#define MAX_NAME_SIZE 100 +#define MAX_AUTHOR_SIZE 200 +#define MAX_COLOR_SIZE 7 + +#define max_size(p) MAX_ ## p ## _SIZE + +struct tankdef { + struct sensor sensors[TANK_MAX_SENSORS]; /* Sensor array */ + char program[MAX_PROGRAM_SIZE]; + char name[MAX_NAME_SIZE]; + char author[MAX_AUTHOR_SIZE]; + char color[MAX_COLOR_SIZE]; +}; + +void +print_tank(struct tankdef); + +void +print_sensor(struct sensor); + +#endif /* __TANKDEF_H__ */ diff --git a/tankdir.c b/tankdir.c new file mode 100644 index 0000000..60c12d2 --- /dev/null +++ b/tankdir.c @@ -0,0 +1,189 @@ +#include +#include +#include +#include +#include +#include +#include "tankdef.h" +#include "tankdir.h" + +#define MATCH 0 + +int isSensor(char* string) { + char* s = "sensor"; + size_t len = strlen(s); + return ( strncmp(s, string, len) == MATCH ) && (strlen(string) > len); +} + +int isNotRealDir(struct dirent* file) { + return strcmp(file->d_name,".") == MATCH || + strcmp(file->d_name,"..") == MATCH; +} + +char* readFile(char* file, const int MAX_SIZE) { + char* buffer = NULL; + long length; + FILE* f = fopen(file, "r"); + if(f == NULL) { + perror(file); + exit(1); + } + fseek(f, 0, SEEK_END); + length = ftell(f); + if(length>MAX_SIZE) { + fprintf(stderr, "File %s to large for variable.\n", file); + exit(1); + } + fseek(f, 0, SEEK_SET); + buffer = (char*)malloc(length+1); // +1 for null terminator. + if(buffer == NULL) { + perror(file); + exit(1); + } + fread(buffer, sizeof(char), length, f); + buffer[length] = (char)'\0'; + fclose(f); + return buffer; +} + +void +sensorReadError(char* file) { + fprintf(stderr, "Malformed sensor file: %s\n", file); + exit(1); +} + +struct sensor +parseSensor(char* file) { + struct sensor theSensor; + char* content = readFile(file, 50); + char* token = strtok(content, " "); + if(token == NULL) { + sensorReadError(file); + } + theSensor.angle = atof(token); + token = strtok(NULL, " "); + if(token == NULL) { + sensorReadError(file); + } + theSensor.width = atof(token); + token = strtok(NULL, " "); + if(token == NULL) { + sensorReadError(file); + } + theSensor.range = atoi(token); + token = strtok(NULL, " "); + if(token == NULL) { + sensorReadError(file); + } + theSensor.turret = atoi(token); + free(content); + return theSensor; +} + +void +loadFileContent(char* dest, char* file, const int MAX_SIZE) { + char* content = readFile(file, MAX_SIZE); + strcpy(dest, content); + free(content); +} + +void +initSensor(struct sensor* theSensor) { + theSensor->turret = 0; + theSensor->width = 0.0; + theSensor->range = 0; + theSensor->angle = 0.0; + theSensor->triggered = 0; +} + +void +initTank(struct tankdef* theTank) { + int i; + strcpy(theTank->name, "noname"); + strcpy(theTank->author, "noauthor"); + strcpy(theTank->color, "#808080"); + strcpy(theTank->program, ""); + for(i=0; isensors[i]); + } +} + +struct tankdef +readTankFromDir(char* path) { + DIR* dp; + if( (dp=opendir(path))==NULL ) { + perror(path); + exit(1); + } + + struct tankdef theTank; + initTank(&theTank); + struct dirent* files; + while( (files=readdir(dp)) != NULL ) { + if( isNotRealDir(files) ) { + continue; + } + char file[1000]; + sprintf(file, "%s/%s", path, files->d_name); + if( isSensor(files->d_name) ) { + int sensorId = files->d_name[strlen("sensor")]-'0'; + theTank.sensors[sensorId] = parseSensor(file); + } else if( strcmp(files->d_name, "name") == MATCH ) { + loadFileContent( theTank.name, file, max_size(NAME) ); + } else if( strcmp(files->d_name, "author") == MATCH ) { + loadFileContent( theTank.author, file, max_size(AUTHOR) ); + } else if( strcmp(files->d_name, "program") == MATCH ) { + loadFileContent( theTank.program, file, max_size(PROGRAM) ); + } else if( strcmp(files->d_name, "color") == MATCH ) { + loadFileContent( theTank.color, file, max_size(COLOR) ); + } + } + closedir(dp); + return theTank; +} + +void +writeFile(char* path, char* fileName, char* text) { + char file[100] = ""; + strcat(file, path); + if(file[strlen(file)-1] != '/') { + strcat(file, "/"); + } + strcat(file, fileName); + FILE* pfile = fopen(file, "w"); + if(pfile == NULL) { + char errorString[100]; + sprintf(errorString, "Error opening file %s/%s\n", path, fileName); + perror(errorString); + exit(1); + } + fprintf(pfile, "%s", text); + fclose(pfile); +} + +void +writeSensorFile(char* path, int sensorIndex, struct sensor theSensor) { + char file[100] = ""; + strcat(file, path); + if(file[strlen(file)-1] != '/') { + strcat(file, "/"); + } + char fileName[] = "sensor0"; + fileName[6] = sensorIndex + '0'; + strcat(file, fileName); + FILE* pfile = fopen(file, "w"); + fprintf(pfile, "%.0f %.0f %d %d", theSensor.angle, theSensor.width, theSensor.range, theSensor.turret); + fclose(pfile); +} + +void +writeTankToDir(char* dir, struct tankdef theTank) { + int i = 0; + writeFile(dir, "name", theTank.name); + writeFile(dir, "color", theTank.color); + writeFile(dir, "author", theTank.author); + writeFile(dir, "program", theTank.program); + for(i=0; i +#include +#include +#include +#include "tankdef.h" +#include "tankjson.h" + +json_t* +tankToJSON(struct tankdef theTank); + +char* +writeTankToJSON(struct tankdef theTank) { + json_t* root = tankToJSON(theTank); + char* ret_string = json_dumps(root,0); + json_decref(root); + + return ret_string; +} + +json_t* +tankToJSON(struct tankdef theTank) { + json_t* root = json_object(); + json_t* sensors = json_array(); + int i; + for(i=0; i (size_t)MAX_LEN) ) { + fprintf(stderr, "%s field too large in JSON object.\n", name); + exit(1); + } else { + strcpy(dest, string); + } +} + +struct sensor +sensorFromJSON(json_t* sensor) { + struct sensor theSensor; + json_t* tmp = json_object_get(sensor, "angle"); + theSensor.angle = json_real_value(tmp); + tmp = json_object_get(sensor, "width"); + theSensor.width = json_real_value(tmp); + tmp = json_object_get(sensor, "range"); + theSensor.range = json_integer_value(tmp); + tmp = json_object_get(sensor, "turret"); + theSensor.turret = json_integer_value(tmp); + return theSensor; +} + +struct tankdef +tankFromJSON(json_t* root) { + size_t i; + if( !json_is_object(root) ) { + fprintf(stderr, "Error: root is not an object!\n"); + json_decref(root); + exit(1); + } + + struct tankdef theTank; + loadJSONString(theTank.name, max_size(NAME), root, "name"); + loadJSONString(theTank.author, max_size(AUTHOR), root, "author"); + loadJSONString(theTank.program, max_size(PROGRAM), root, "program"); + loadJSONString(theTank.color, max_size(COLOR), root, "color"); + + json_t* sensors = json_object_get(root, "sensors"); + if(!json_is_array(sensors)) { + fprintf(stderr, "Error: sensors object is not an array!\n"); + exit(1); + } + for(i=0; i (size_t)MAX_TANKS) { + fprintf(stderr,"Error: Too many tanks! Tried to load %d, Max: %d\n", + (int)json_array_size(root), MAX_TANKS); + } + for(i=0; i