/* Core Wars. * Copyright (C) 1999 Walter Hofmann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define CMD_LINE #include "config.h" #ifdef HAVE_ARGP_H #include #include #include #include #include #include #include "options.h" #include "main.h" #include "program.h" #include "program-cw.h" #include "program-rc.h" #include "execute.h" #include "execute-cw.h" #include "execute-rc.h" #include "statistic.h" #include "pstatistic.h" const char *argp_program_version = "CoreWars " VERSION; const char *argp_program_bug_address = "Walter Hofmann "; int default_count = 1; int repeats = 1; int reproducible = 0; char *format = "%4r %7s %-25t %a"; int supress_header = 0; int score_old = 0; int dump = 0; int dump_internal = 0; static error_t parse_opt (int key, char *arg, struct argp_state *state) { char *p; switch (key) { case 'l': if (strcmp (arg, "COREWARS")==0) LANGUAGE = LANGUAGE_CW; else if (strcmp (arg, "REDCODE")==0) LANGUAGE = LANGUAGE_RC; else { printf ("Invalid argument for --language.\n"); argp_usage (state); } break; case 's': SIZE = atoi (arg); if (SIZESIZE_MAX) { printf ("Invalid argument for --memory-size.\n"); argp_usage (state); } DIMENSIONX = (int) sqrt (SIZE); DIMENSIONY = (SIZE+DIMENSIONX-1)/DIMENSIONX; break; case 'm': MAX_CYCLES = atoi (arg); if (MAX_CYCLES<1) { printf ("Invalid argument for --max-cycles.\n"); argp_usage (state); } break; case 't': MAX_THREADS = atoi (arg); if (MAX_THREADS<1) { printf ("Invalid argument for --max-threads.\n"); argp_usage (state); } break; case 'e': MAX_LENGTH = atoi (arg); if (MAX_LENGTH<1) { printf ("Invalid argument for --max-length.\n"); argp_usage (state); } break; case 'z': MIN_DISTANCE = strtol (arg, &p, 0); if (*arg=='\0' || *p!='\0') { printf ("Invalid argument for --min-distance.\n"); argp_usage (state); } break; case 'y': STOP_EARLY = 0; break; case 'd': default_count = atoi (arg); if (default_count<1) { printf ("Invalid argument for --default_count.\n"); argp_usage (state); } break; case 'r': repeats = atoi (arg); if (repeats<1) { printf ("Invalid argument for --repeats.\n"); argp_usage (state); } break; case 'i': ALLOW_SELF_MOVE = 0; break; case 'a': SCORE_ALIVE = strtol (arg, &p, 0); if (*arg=='\0' || *p!='\0') { printf ("Invalid argument for --score-alive.\n"); argp_usage (state); } break; case 'c': SCORE_CELLS = strtol (arg, &p, 0); if (*arg=='\0' || *p!='\0') { printf ("Invalid argument for --score-cells.\n"); argp_usage (state); } break; case 'k': SCORE_KILLS = strtol (arg, &p, 0); if (*arg=='\0' || *p!='\0') { printf ("Invalid argument for --score-kills.\n"); argp_usage (state); } break; case 'o': score_old = 1; break; case 'n': SCORE_RANK = 1; break; case 'b': SCORE_BEST = 1; break; case 'x': reproducible = 1; break; case 'f': format = arg; break; case 'h': supress_header = 1; break; case 'p': dump = 1; break; case 'g': dump_internal = 1; break; case ARGP_KEY_ARG: *((char***)state->input) = &state->argv[state->next-1]; state->next = state->argc; break; case ARGP_KEY_END: if (state->arg_num < 1) argp_usage (state); break; default: return ARGP_ERR_UNKNOWN; } return 0; } static struct argp_option options[] = { {"language", 'l', "LANGUAGE", 0, "Select language (COREWARS or REDCODE, default COREWARS)" }, { NULL, 0, 0, 0, "" }, {"core-size", 's', "SIZE", 0, "Set memory size (cells, 625<=SIZE<=1000000, default 6400)" }, {"max-cycles", 'm', "CYCLES", 0, "Set maximum number of cycles to execute (default 1000000)" }, {"max-threads", 't', "THREADS", 0, "Set maximum threads a process may have (default 1000)" }, {"max-length", 'e', "CELLS", 0, "Set maximum program size (default 200)" }, {"min-distance", 'z', "CELLS", 0, "Set minimum distance (default 100)" }, {"dont-stop-early", 'y', NULL, 0, "Don't stop when only one process left" }, { NULL, 0, 0, 0, "" }, {"default-copies", 'd', "NUMBER", 0, "Set number of copies to load per default (default 1)" }, {"repeats", 'r', "NUMBER", 0, "Set number of games to play (default 1)" }, { NULL, 0, 0, 0, "" }, {"forbid-self-move",'i', NULL, 0, "Forbid self move instruction (default off)" }, { NULL, 0, 0, 0, "" }, {"score-alive", 'a', "SCORE", 0, "Score for every step the process was alive (default 1)" }, {"score-cells", 'c', "SCORE", 0, "Score for every cell the process owns (default 1)" }, {"score-kills", 'k', "SCORE", 0, "Score for evey other process the process has killed (default 100)" }, {"score-old", 'o', NULL, 0, "Old-Style scoring, the only surviving process gets 3 points, a " "surviving process gets 1 point" }, { NULL, 0, 0, 0, "" }, {"use-rank", 'n', NULL, 0, "Use rank in each game to create final score (instead of the game score)" }, {"use-best", 'b', NULL, 0, "Use score from best copy (instead of summing the scores of all copies)" }, { NULL, 0, 0, 0, "" }, {"reproducible", 'x', NULL, 0, "Supress initialisation of the random number generator" }, {"format", 'f', "FORMAT", 0, "Set the format for the highscore table" }, {"supress-header", 'h', NULL, 0, "Supress highscore table header" }, {"dump", 'p', NULL, 0, "Dump the programs and exit" }, {"dump-internal", 'g', NULL, 0, "Dump the programs using an internal format and exit" }, { 0 } }; struct argp argp = { options: options, parser: parse_opt, args_doc: "filename[:copies] ...", doc: "Starts the CoreWars command line version.\v" "The format string for the highscore table can contain the following directives: " "%r and %R for the rank (%r prints nothing if two warriors have the same rank), " "%s for the score, %t for the title, %a for the author and %f for the filename. " "The default format string is '%4r %7s %-25t %a'.", }; int main(int argc,char *argv[]) { char **file_list; int i,j,n,m; struct program *p; char *c; int count; struct program **table; char *s; argp_parse (&argp, argc, argv,0 ,0 , &file_list); if (!reproducible) srandom (time (0)); for (i = 0; file_list[i]; i++) { c = strrchr (file_list[i], ':'); if (c) { *c = '\0'; c++; count = atoi(c); if (count<=0) { printf("Invalid copies count for %s.\n",file_list[i]); exit(1); } } else count = default_count; p = alloc_and_link_program (); p->language = LANGUAGE; if (LANGUAGE==LANGUAGE_CW) p->lang.cw.code = NULL; else p->lang.rc.obj = NULL; p->filename = malloc (strlen (file_list[i])+1); strcpy (p->filename, file_list[i]); if ((LANGUAGE==LANGUAGE_CW && cw_load_program (p)==FAIL) || (LANGUAGE==LANGUAGE_RC && rc_load_program (p)==FAIL)) { unlink_and_free_program (p); printf ("Cannot load %s.\n", file_list[i]); exit (1); } if (p->error) { printf ("%s\n", p->error); exit (1); } if (dump) if (p->language==LANGUAGE_CW) cw_dump_program (p); else rc_dump_program (p); if (dump_internal) if (p->language==LANGUAGE_CW) cw_dump_program_internal (p); else rc_dump_program_internal (p); p->load_count = count; } if (dump || dump_internal) exit (0); if (score_old) { /* Adjust score settings. */ SCORE_CELLS = SCORE_ALIVE = 0; SCORE_KILLS = 1; } for (i=0; i1)) if (LANGUAGE==LANGUAGE_CW) cw_execute_step (); else rc_execute_step (); execute_stop_cmd (); for (j=0; jcell_count++; if (score_old) { /* We need do adjust some things to make this work. */ if (thread_count==0) { /* No process lived till the end of the game. We put the ones that lived the longest time back to life. */ m = 0; for (j=1; jprocess_array[m].death_time) m = j; for (j=0; jnext; } table = malloc (sizeof (struct program *)*n); p = program_list_root; i = 0; while (p) { table[i++] = p; p = p->next; } qsort (table, n, sizeof (struct program *), &program_compare); if (!supress_header) { for (s=format; *s; s++) { if (*s=='%') { count = strtol(++s, &s, 0); switch (*s) { case 'r': case 'R': printf("%*s",count,"Rank"); break; case 's': printf("%*s",count,"Score"); break; case 't': printf("%*s",count,"Title"); break; case 'a': printf("%*s",count,"Author"); break; case 'f': printf("%*s",count,"Filename"); break; case '%': putchar('%'); break; } } else putchar(*s); } printf("\n"); } for (i=0; itournament_score!=table[i-1]->tournament_score) printf("%*d",count,i+1); else printf("%*s",count,""); break; case 'R': printf("%*d",count,i+1); break; case 's': printf("%*d",count,table[i]->tournament_score); break; case 't': printf("%*s",count,table[i]->title); break; case 'a': printf("%*s",count,table[i]->author); break; case 'f': printf("%*s",count,table[i]->filename); break; case '%': putchar('%'); break; } } else putchar(*s); } printf("\n"); } return 0; } #endif