home *** CD-ROM | disk | FTP | other *** search
- /* #[info: */
- /************************************************************************
- * *
- * Jan van der Steen *
- * *
- * Centre for Mathematics and Computer Science *
- * Amsterdam, the Netherlands *
- * *
- *----------------------------------------------------------------------*
- * File : game2eps.c *
- * Purpose : Emit a Go Game Using PostScript directives *
- * Version : 1.23 *
- * Modified: 3/5/93 16:50:30 *
- * Author : Jan van der Steen (jansteen@cwi.nl) *
- ************************************************************************/
- /* #]info: */
- /* #[include: */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #include <time.h>
- #include "gogame.h"
- #include "game2eps.h"
- #include "sysdep.h"
-
- /* #]include: */
- /* #[extern: */
-
- extern int prn_dev;
- extern EPSFINFO epsf;
- extern int caching; /* Caching mode */
- extern int coords; /* Print coordinates */
- extern char * program;
-
- /* #]extern: */
- /* #[define: */
-
- #define NODE2EPSI(g,n) (NODE2I(g,n) - g->gm_size/2)
- #define NODE2EPSJ(g,n) (NODE2J(g,n) - g->gm_size/2)
- #define NODE2TEXI(g,n) (NODE2J(g,n) + 'a' + ((NODE2J(g,n) > 8) ? 1 : 0))
- #define NODE2TEXJ(g,n) (NODE2I(g,n) + 1)
- #define NODE2IGSI(g,n) (NODE2I(g,n) + 'a' + ((NODE2I(g,n) > 8) ? 1 : 0))
- #define NODE2IGSJ(g,n) (g->gm_size - NODE2J(g,n))
-
- /* #]define: */
- /* #[typedef: */
-
- #ifdef __STDC__
- # define PROTO(s) s
- #else
- # define PROTO(s) ()
- #endif
-
- typedef struct dev_info {
- int (*dev_init ) PROTO((GOGAME *g, int dianr, int min, int max));
- void (*dev_cadd ) PROTO((GOMOVE *m));
- void (*dev_cdel ) PROTO((GOGAME *g, GONODE *p));
- void (*dev_stone ) PROTO((GOGAME *g, GONODE *p));
- void (*dev_move ) PROTO((GOGAME *g, GOMOVE *m));
- void (*dev_onstone) PROTO((GOGAME *g, GONODE *p, int color, int nr));
- void (*dev_onmove ) PROTO((GOGAME *g, GONODE *p, int color, int nr));
- void (*dev_mark ) PROTO((GOGAME *g, GONODE *p, MARK m));
- void (*dev_char ) PROTO((GOGAME *g, GONODE *p, MARK m));
- void (*dev_exit ) PROTO((int d, int n1, int n2));
- } PRN_DEVICE;
-
- #undef PROTO
-
- /* #]typedef: */
- /* #[prototype: */
-
- #ifdef __STDC__
- # define PROTO(s) s
- #else
- # define PROTO(s) ()
- #endif
-
- /*
- * Encapsulated PostScript method
- */
- static int eps_init PROTO((GOGAME *g, int nr, int min, int max));
- static void eps_cadd PROTO((GOMOVE *m));
- static void eps_cdel PROTO((GOGAME *g, GONODE *p));
- static void eps_stone PROTO((GOGAME *g, GONODE *p));
- static void eps_move PROTO((GOGAME *g, GOMOVE *m));
- static void eps_onstone PROTO((GOGAME *g, GONODE *p, int c, int nr));
- static void eps_onmove PROTO((GOGAME *g, GONODE *p, int c, int nr));
- static void eps_mark PROTO((GOGAME *g, GONODE *p, MARK m));
- static void eps_char PROTO((GOGAME *g, GONODE *p, MARK m));
- static void eps_exit PROTO((int d, int n1, int n2));
-
- /*
- * Hanna Ko{\l}odziejska's TeX method
- */
- static int tex_init PROTO((GOGAME *g, int nr, int min, int max));
- static void tex_cadd PROTO((GOMOVE *m));
- static void tex_cdel PROTO((GOGAME *g, GONODE *p));
- static void tex_stone PROTO((GOGAME *g, GONODE *p));
- static void tex_move PROTO((GOGAME *g, GOMOVE *m));
- static void tex_onstone PROTO((GOGAME *g, GONODE *p, int c, int nr));
- static void tex_onmove PROTO((GOGAME *g, GONODE *p, int c, int nr));
- static void tex_mark PROTO((GOGAME *g, GONODE *p, MARK m));
- static void tex_char PROTO((GOGAME *g, GONODE *p, MARK m));
- static void tex_exit PROTO((int d, int n1, int n2));
-
- static void con_cat PROTO((char *s));
- static void con_printf PROTO((char *fmt, ...));
- static char * n2hanna PROTO((int n, int color));
-
-
- #undef PROTO
-
- /* #]prototype: */
- /* #[static: */
-
- PRN_DEVICE prn_devices[] = {
- {
- eps_init,
- eps_cadd,
- eps_cdel,
- eps_stone,
- eps_move,
- eps_onstone,
- eps_onmove,
- eps_mark,
- eps_char,
- eps_exit,
- },{
- tex_init,
- tex_cadd,
- tex_cdel,
- tex_stone,
- tex_move,
- tex_onstone,
- tex_onmove,
- tex_mark,
- tex_char,
- tex_exit,
- }
- };
-
- static FILE * fp; /* The created eps file */
-
- /* #]static: */
-
- /* #[con_cat: */
-
- /*
- * When we need more ko/connect message space we allocate
- * it in chunks of CONNECTCHUNK bytes
- */
- #define CONNECTCHUNK 1024
-
- static void
- con_cat(s)
- /*
- * s != (char *) 0 Append s to connect buffer
- * s == (char *) 0 Flush the connect buffer
- */
- char *s;
- {
- static char * con = (char *) 0;
- static char * con_p;
- static int n = 0;
-
- /*
- * Flush request ?!
- */
- if (s == (char *) 0) {
- if (con != (char *) 0 && *con) {
- fprintf(stdout, " \\connect{%s}\n", con);
- *con = 0;
- con_p = con;
- } else {
- fprintf(stdout, " \\connect{}\n");
- }
- return;
- }
-
- /*
- * Do we have enough space
- */
- if (con == (char *) 0 || (int)(con_p - con + strlen(s)) + 3 > n) {
- if (n == 0) {
- con = (char *) malloc(CONNECTCHUNK);
- *con = 0;
- } else con = (char *) realloc(con, n + CONNECTCHUNK);
- n += CONNECTCHUNK;
- }
- if (con == (char *) 0) {
- fprintf(stderr, "Out of memory in con_cat()\n");
- exit(1);
- }
-
- /*
- * Catenate the string
- */
- if (*con != 0) strcat(con, ", ");
- strcat(con, s);
- }
-
- /* #]con_cat: */
- /* #[con_printf: */
-
- #if defined (__STDC__)
- /*#[ANSI-C: */
-
- #include <stdarg.h>
-
- static void
- con_printf(char *fmt, ...)
- {
- va_list argpoint;
- char msg[1024];
-
- va_start(argpoint, fmt);
- vsprintf(msg, fmt, argpoint);
- va_end(argpoint);
- con_cat(msg);
- }
-
- /*#]ANSI-C: */
- #else
- /*#[not ANSI-C: */
-
- #include <varargs.h>
-
- /*VARARGS1*/
- static void
- con_printf(va_alist)
- va_dcl
- {
- va_list argpoint;
- char * fmt;
- char msg[256];
-
- va_start(argpoint);
- fmt = va_arg(argpoint, char *);
- vsprintf(msg, fmt, argpoint);
- va_end(argpoint);
- con_cat(msg);
- }
- /*#]not ANSI-C: */
- #endif
-
- /* #]con_printf: */
- /* #[n2hanna: */
-
- static char *
- n2hanna(n, color)
- /*
- * The Hanna fonts have numbered stones up to 252.
- * We want to use them in captions if possibly.
- */
- int n;
- int color;
- {
- static char texnum[128];
-
- if (n <= 252)
- sprintf(texnum,
- "\\mbox{\\text%s{%d}}",
- (color == BLACK) ? "black" : "white",
- n);
- else
- sprintf(texnum, "%d", n);
-
- return texnum;
- }
-
- /* #]n2hanna: */
-
- /* #[game2eps: */
-
- void
- game2eps(gogame, n, min, max)
- /*
- * Print a diagram of the position at move max,
- * only numbering the stones in the interval:
- *
- * min <= numbered stones <= max.
- */
- GOGAME *gogame;
- int n;
- int min;
- int max;
- {
- PRN_DEVICE *device = prn_devices+prn_dev;
- GOMOVE *m;
- PLACE p;
-
- (device->dev_init)(gogame, n, min, max);
-
- /*
- * Print numbered stones between min and max while
- * maintaining the printable stone array (gn_print in GONODE)
- */
- for (m = gogame->gm_move; m && m->mv_nr <= max; m = m->mv_next) {
- assert(m->mv_place != (GONODE *) 0);
-
- if (m->mv_nr >= min) {
- /*
- #[numbered stones:
- */
- if (m->mv_place->gn_print == 0) {
- (device->dev_move)(gogame, m);
- (device->dev_cadd)(m);
- m->mv_place->gn_print = m->mv_nr;
- }
- else {
- ((m->mv_place->gn_print > 0)
- ? (device->dev_onmove) /* On a numbered stone */
- : (device->dev_onstone)) /* On an unnumbered stone */
- (gogame, m->mv_place, m->mv_side, m->mv_nr);
- }
- /*
- #]numbered stones:
- */
- } else {
- /*
- #[unnumbered stones:
- */
- CHAIN *c;
- /*
- * First we remove the captured chains while preserving
- * stones played at a later stage (ishi-no-shita).
- */
- for (c = m->mv_captured; c != (CHAIN *) 0; c = c->ch_next) {
- GONODE *node = c->ch_stone->mv_place;
-
- assert(node != (GONODE *) 0);
- if (node->gn_print < 0) {
- node->gn_print = PRINT_NOTHING;
- (device->dev_cdel)(gogame, node);
- node->gn_cache = 0;
- }
- }
-
- /*
- * Account the unnumbered stones
- */
- if (m->mv_place->gn_print == 0) {
- m->mv_place->gn_print = (m->mv_side == BLACK)
- ? PRINT_BLACK
- : PRINT_WHITE;
- } else {
- fprintf(stderr, "[%d at occupied (%c,%d)]", m->mv_nr,
- NODE2IGSI(gogame, m->mv_place),
- NODE2IGSJ(gogame, m->mv_place));
- }
- /*
- #]unnumbered stones:
- */
- }
- }
-
- /* #[print unnumbered stones: */
-
- /*
- * Add the unnumbered stones
- */
- for (m = gogame->gm_move; m && m->mv_nr <= max; m = m->mv_next) {
- assert(m->mv_place != (GONODE *) 0);
- if (m->mv_nr < min && m->mv_place->gn_print < 0) {
- (device->dev_stone)(gogame, m->mv_place);
- }
- }
-
- /* #]print unnumbered stones: */
-
- (device->dev_exit)(n, min, max);
-
- /*
- * Clear the print status fields
- */
- for (p = 0; p < gogame->gm_size*gogame->gm_size; p++) {
- NODE(gogame,p)->gn_print = 0;
- }
-
- /*
- * Flush the ko/connect messages
- */
- con_cat((char *) 0);
- }
-
- /* #]game2eps: */
-
- /* #[eps_init: */
-
- static int
- eps_init(gogame, n, min, max)
- /*
- * Open the EPSF file and print the header
- */
- GOGAME *gogame;
- int n;
- int min;
- int max;
- {
- char epsffile[1024];
- char * thetime;
- long seconds;
- long tenth_mm = 250L*epsf.eps_size/72;
- int eps_width = epsf.eps_size;
-
- fprintf(stderr, "[");
-
- /*
- * Account the coordinates too
- */
- if (coords) eps_width += 2*eps_width/gogame->gm_size;
-
- /*
- * Get the creation time
- */
- time(&seconds);
- thetime = ctime(&seconds);
-
- /*
- * Construct the epsf filename
- */
- sprintf(epsffile, "%s%c%s.%03d",
- epsf.eps_dir,
- PATHSEP,
- epsf.eps_name,
- n);
- if ((fp = fopen(epsffile, "w")) == (FILE *) 0) {
- fprintf(stderr, "Couldn't create: \"%s\"\n", epsffile);
- exit(1);
- }
-
- fprintf(fp, "%%!PS-Adobe-2.0 EPSF-1.2\n");
- fprintf(fp, "%%%%Title: %s-%s (%d-%d)\n",
- (gogame->gm_white) ? gogame->gm_white : "unknown",
- (gogame->gm_black) ? gogame->gm_black : "unknown",
- min, max);
- fprintf(fp, "%%%%Creator: %s\n", program);
- fprintf(fp, "%%%%CreationDate: %s", thetime);
- fprintf(fp, "%%%%BoundingBox: 0 0 %d %d\n", eps_width, eps_width);
- fprintf(fp, "%%%%EndComments\n");
- fprintf(fp, "Liberty begin\n");
- fprintf(fp, "/caching %s def\n", (caching) ? "true" : "false");
- fprintf(fp, "/coords %s def\n", (coords ) ? "true" : "false");
- fprintf(fp, "%d %ld.%02ld boardinit\n", gogame->gm_size,
- tenth_mm/100, tenth_mm - 100*(tenth_mm/100));
- fprintf(fp, "board\n");
-
- return 1;
- }
-
- /* #]eps_init: */
- /* #[eps_cadd: */
-
- static void
- eps_cadd(move)
- GOMOVE *move;
- {
- move->mv_place->gn_cache = (move->mv_side == BLACK)
- ? PRINT_BLACK
- : PRINT_WHITE;
- }
-
- /* #]eps_cadd: */
- /* #[eps_cdel: */
-
- static void
- eps_cdel(gogame, node)
- GOGAME *gogame;
- GONODE *node;
- {
- if (caching)
- fprintf(fp, "%d %d cd\n",
- NODE2EPSI(gogame, node),
- NODE2EPSJ(gogame, node));
- }
-
- /* #]eps_cdel: */
- /* #[eps_stone: */
-
- static void
- eps_stone(gogame, node)
- GOGAME *gogame;
- GONODE *node;
- {
- if (caching && node->gn_cache == node->gn_print) return;
-
- fprintf(fp, "%d %d %cs\n",
- NODE2EPSI(gogame, node),
- NODE2EPSJ(gogame, node),
- (node->gn_print == PRINT_BLACK) ? 'b' : 'w');
- }
-
- /* #]eps_stone: */
- /* #[eps_move: */
-
- static void
- eps_move(gogame, move)
- GOGAME *gogame;
- GOMOVE *move;
- {
- fprintf(fp, "(%d) %d %d %cst\n",
- ((move->mv_nr - 1) % 100) + 1,
- NODE2EPSI(gogame, move->mv_place),
- NODE2EPSJ(gogame, move->mv_place),
- (move->mv_side == BLACK) ? 'b' : 'w');
- }
-
- /* #]eps_move: */
- /* #[eps_onstone: */
-
- static void
- eps_onstone(gogame, node, color, movenr)
- /*
- * We could try something more fancy here, like checking all neighbours,
- * or adding a mark on the stone (if any)...
- */
- GOGAME *gogame;
- GONODE *node;
- int color;
- int movenr;
- {
- con_printf("%d at (%c,%d)",
- movenr,
- NODE2IGSI(gogame, node),
- NODE2IGSJ(gogame, node));
- }
-
- /* #]eps_onstone: */
- /* #[eps_onmove: */
-
- static void
- eps_onmove(gogame, node, color, movenr)
- /*
- * A move on the same spot as a previous move
- */
- GOGAME *gogame;
- GONODE *node;
- int color;
- int movenr;
- {
- switch(node->gn_print) {
- case PRINT_BLACK :
- case PRINT_WHITE :
- case PRINT_NOTHING: con_printf("%d at (%c,%d)", movenr,
- NODE2IGSI(gogame, node),
- NODE2IGSJ(gogame, node));
- break;
- default : con_printf("%d at %d", movenr, node->gn_print);
- break;
- }
- }
-
- /* #]eps_onmove: */
- /* #[eps_mark: */
-
- static void
- eps_mark(gogame, node, mark)
- GOGAME *gogame;
- GONODE *node;
- MARK mark;
- {
- fprintf(stderr, "[MARK %d on (%c,%d) ignored]",
- mark,
- NODE2IGSI(gogame, node),
- NODE2IGSJ(gogame, node));
- }
-
- /* #]eps_mark: */
- /* #[eps_char: */
-
- static void
- eps_char(gogame, node, mark)
- GOGAME *gogame;
- GONODE *node;
- MARK mark;
- {
- fprintf(stderr, "[CHAR %d on (%c,%d) ignored]",
- mark,
- NODE2IGSI(gogame, node),
- NODE2IGSJ(gogame, node));
- }
-
- /* #]eps_char: */
- /* #[eps_exit: */
-
- static void
- eps_exit(n, min, max)
- /*
- * Print the EPSF trailer and close the file
- */
- int n;
- int min;
- int max;
- {
- fprintf(fp, "end\n");
- fprintf(fp, "%%%%Trailer\n");
- fclose (fp);
- fprintf(stderr, "%d (%d-%d)]", n, min, max);
- }
-
- /* #]eps_exit: */
-
- /* #[tex_init: */
-
- static int
- tex_init(gogame, n, min, max)
- GOGAME *gogame;
- int n;
- int min;
- int max;
- {
- fprintf(stderr, "[");
- fprintf(stdout, "%%%% #[diagram %03d (%d-%d):\n", n, min, max);
- fprintf(stdout, "\\inifulldiagram\n");
-
- return 1;
- }
-
- /* #]tex_init: */
- /* #[tex_cadd: */
-
- static void
- tex_cadd(move)
- GOMOVE *move;
- {
- move->mv_place->gn_cache = (move->mv_side == BLACK)
- ? PRINT_BLACK
- : PRINT_WHITE;
- }
-
- /* #]tex_cadd: */
- /* #[tex_cdel: */
-
- static void
- tex_cdel(gogame, node)
- GOGAME *gogame;
- GONODE *node;
- {
- if (caching)
- fprintf(stdout, "%% [DC(%c,%d)]\n",
- NODE2TEXI(gogame, node),
- NODE2TEXJ(gogame, node));
- }
-
- /* #]tex_cdel: */
- /* #[tex_stone: */
-
- static void
- tex_stone(gogame, node)
- GOGAME *gogame;
- GONODE *node;
- {
- fprintf(stdout, "\\p:%c-%d=\\%c.\n",
- NODE2TEXI(gogame, node),
- NODE2TEXJ(gogame, node),
- (node->gn_print == PRINT_BLACK) ? 'b' : 'w');
- }
-
- /* #]tex_stone: */
- /* #[tex_move: */
-
- static void
- tex_move(gogame, move)
- GOGAME *gogame;
- GOMOVE *move;
- {
- fprintf(stdout, "\\p:%c-%d=\\%c{%d}\n",
- NODE2TEXI(gogame, move->mv_place),
- NODE2TEXJ(gogame, move->mv_place),
- (move->mv_side == BLACK) ? 'b' : 'w',
- ((move->mv_nr - 1) % 100) + 1);
- }
-
- /* #]tex_move: */
- /* #[tex_onstone: */
-
- static void
- tex_onstone(gogame, node, color, movenr)
- /*
- * A move on the same spot as a previous move
- */
- GOGAME *gogame;
- GONODE *node;
- int color;
- int movenr;
- {
- con_printf("%s at (%c,%d)",
- n2hanna(movenr, color),
- NODE2IGSI(gogame, node),
- NODE2IGSJ(gogame, node));
- }
-
- /* #]tex_onstone: */
- /* #[tex_onmove: */
-
- static void
- tex_onmove(gogame, node, color, movenr)
- /*
- * A move at the same spot as another move
- */
- GOGAME *gogame;
- GONODE *node;
- int color;
- int movenr;
- {
- switch(node->gn_print) {
- case PRINT_BLACK :
- case PRINT_WHITE :
- case PRINT_NOTHING:
- con_printf("%s at (%c,%d)",
- n2hanna(movenr, color),
- NODE2IGSI(gogame, node),
- NODE2IGSJ(gogame, node));
- break;
- default:
- {
- char onmove[128];
-
- strcpy(onmove, n2hanna(movenr, color));
- strcat(onmove, " at ");
- strcat(onmove, n2hanna(node->gn_print,
- ((node->gn_print + movenr) & 0x01)
- ? (color == BLACK) ? WHITE : BLACK
- : color));
- con_printf(onmove);
- }
- break;
- }
- }
-
- /* #]tex_onmove: */
- /* #[tex_mark: */
-
- static void
- tex_mark(gogame, node, mark)
- GOGAME *gogame;
- GONODE *node;
- MARK mark;
- {
- fprintf(stderr, "[MARK %d on (%c,%d) ignored]",
- mark,
- NODE2IGSI(gogame, node),
- NODE2IGSJ(gogame, node));
- }
-
- /* #]tex_mark: */
- /* #[tex_char: */
-
- static void
- tex_char(gogame, node, mark)
- GOGAME *gogame;
- GONODE *node;
- MARK mark;
- {
- fprintf(stderr, "[CHAR %d on (%c,%d) ignored]",
- mark,
- NODE2IGSI(gogame, node),
- NODE2IGSJ(gogame, node));
- }
-
- /* #]tex_char: */
- /* #[tex_exit: */
-
- static void
- tex_exit(n, min, max)
- int n;
- int min;
- int max;
- {
- fprintf(stdout, "\\showfulldiagram\n");
- fprintf(stdout, "%%%% #]diagram %03d (%d-%d): \n", n, min, max);
- fprintf(stderr, "%d (%d-%d)]", n, min, max);
- }
-
- /* #]tex_exit: */
-
-