(Temporarily) set "animate" to "none" by default (broken feature).
[gf1.git] / gamelog2.cxx
blob8cda7c40c77aaa755a0a02c8e291fee951d0f2a4
1 /*
2 ** $Id$
3 **
4 ** a lot of things for dealing with the log from a gipf-game
5 **
6 ** the original of this file was gamelog.c
7 ** but because I had to add c++ code I had to rename it
8 */
9 /*
10 ** Copyright (C) 1998 Kurt Van den Branden
12 ** This program is free software; you can redistribute it and/or modify
13 ** it under the terms of the GNU General Public License as published by
14 ** the Free Software Foundation; either version 2 of the License, or
15 ** (at your option) any later version.
16 **
17 ** This program is distributed in the hope that it will be useful,
18 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ** GNU General Public License for more details.
21 **
22 ** You should have received a copy of the GNU General Public License
23 ** along with this program; if not, write to the Free Software
24 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include <stdio.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <malloc.h>
31 #include <string>
33 #include "gamelog.h"
36 ** create a new, empty log structure
38 ** parameters:
39 ** type: gametype (string)
40 ** wname: name of the player with white
41 ** bname: name of the player with black
43 gamelog * newlog (const char * type, const char * wname, const char * bname)
45 gamelog * log;
47 log = (gamelog *) malloc (sizeof (gamelog));
48 log->gametype = strdup (type);
49 log->whitename = strdup (wname);
50 log->blackname = strdup (bname);
52 log->moves = (listheader *) malloc (sizeof (listheader));
53 newlist (log->moves);
55 return (log);
60 ** delete a complete gamelog structure
62 void deletelog (gamelog * log)
64 logitem * item;
65 char * pos;
67 free (log->gametype);
68 free (log->whitename);
69 free (log->blackname);
71 while ((item = (logitem *) llrembynr (log->moves, 1)) != NULL)
73 if (item->plist != NULL)
75 while ((pos = (char *) llrembynr (item->plist, 1)) != NULL)
77 free (pos);
79 free (item->plist);
82 free (item);
84 free (log->moves);
86 return;
90 ** add to the gamelog
92 ** the contents of 'data' depend on 'type'
93 ** LOGMOVE: <piece>:<from>:<last moved piece>
94 ** LOGREMGIPF: <gipfowner>:<gipf position><piece>
95 ** LOGREMROW: <rowowner>:<rowstart>:<rowend>:[<piece position><piece>:]...
96 ** (remark: the data for LOGREMROW must end on ':')
98 int addtolog (gamelog * log, int type, char * data)
100 logitem * item;
101 char * kar,
102 piece,
103 start[10]=" ",
104 end[10]=" ",
105 pos[10]=" ";
107 item = (logitem *) malloc (sizeof (logitem));
108 item->plist = NULL;
109 item->type = type;
111 switch (type)
113 case LOGMOVE:
114 if (sscanf (data, "%c:%2s:%2s", &piece, start, end) != 3)
116 free (item);
117 return (-1);
119 break;
120 case LOGREMGIPF:
121 if (sscanf (data, "%c:%3s", &piece, pos) != 2)
123 free (item);
124 return (-1);
126 item->plist = (listheader *) malloc (sizeof (listheader));
127 newlist (item->plist);
128 pushll (item->plist, (void *) strdup (pos));
129 break;
130 case LOGREMROW:
131 if (sscanf (data, "%c:%2s:%2s:", &piece, start, end) != 3)
133 free (item);
134 return (-1);
136 item->plist = (listheader *) malloc (sizeof (listheader));
137 newlist (item->plist);
138 kar = data + 8;
139 while (kar[0] != '\0')
141 strncpy (pos, kar, 3);
142 pushll (item->plist, (void *) strdup (pos));
143 kar += 4;
145 break;
147 item->player = piece;
148 strcpy (item->start, start);
149 strcpy (item->end, end);
151 pushll (log->moves, (void *) item);
152 return (0);
155 xmlite_entity * logtoxml (gamelog * log)
157 xmlite_entity *x1, *x2, *x3;
158 char tempstr[100];
159 int counter = 1,
160 counter2;
161 logitem * item;
162 char * pos;
164 x1 = new xmlite_entity ("gamelog");
165 x1->addattribute ("gametype", log->gametype);
166 x1->addattribute ("whiteplayer", log->whitename);
167 x1->addattribute ("blackplayer", log->blackname);
169 while ((item = (logitem *) llitembynr (log->moves, counter)) != NULL)
171 counter++;
173 switch (item->type)
175 case LOGMOVE:
176 x2 = new xmlite_entity ("move");
177 x1->addcontent (x2);
178 x2->addattribute ("start", item->start);
179 x2->addattribute ("end", item->end);
180 sprintf (tempstr, "%c", item->player);
181 x2->addattribute ("piece", tempstr);
182 break;
183 case LOGREMGIPF:
184 x2 = new xmlite_entity ("removegipf");
185 x1->addcontent (x2);
186 sprintf (tempstr, "%c", item->player);
187 x2->addattribute ("owner", tempstr);
188 pos = (char *) llitembynr (item->plist, 1);
189 x2->setvalue (pos);
190 break;
191 case LOGREMROW:
192 x2 = new xmlite_entity ("removerow");
193 x1->addcontent (x2);
194 x2->addattribute ("start", item->start);
195 x2->addattribute ("end", item->end);
196 sprintf (tempstr, "%c", item->player);
197 x2->addattribute ("owner", tempstr);
199 counter2 = 1;
200 while ((pos = (char *) llitembynr (item->plist, counter2)) != NULL)
202 counter2++;
204 x3 = new xmlite_entity ("position");
205 x2->addcontent (x3);
206 x3->setvalue (pos);
208 break;
209 default: ;
213 return (x1);
216 gamelog * logfromxml (xmlite_entity * root)
218 gamelog * log;
219 int counter = 0,
220 counter2;
221 xmlite_entity * move,
222 * pos;
223 logitem * item;
225 if (root->getname () != "gamelog")
226 return (NULL);
228 log = newlog (root->getattribute ("gametype").c_str(),
229 root->getattribute ("whiteplayer").c_str(),
230 root->getattribute ("blackplayer").c_str());
232 while ((move = root->getcontentbynr (counter)) != NULL)
234 counter++;
236 item = (logitem *) malloc (sizeof (logitem));
237 item->plist = NULL;
238 pushll (log->moves, (void *) item);
240 if (move->getname () == "move")
242 item->type = LOGMOVE;
243 item->player = (move->getattribute("piece"))[0];
244 strcpy (item->start, move->getattribute("start").c_str());
245 strcpy (item->end, move->getattribute("end").c_str());
247 else if (move->getname() == "removerow")
249 item->type = LOGREMROW;
250 item->player = (move->getattribute("owner"))[0];
251 strcpy (item->start, move->getattribute("start").c_str());
252 strcpy (item->end, move->getattribute("end").c_str());
253 item->plist = (listheader *) malloc (sizeof (listheader));
254 newlist (item->plist);
255 counter2 = 0;
256 while ((pos = move->getcontentbynr (counter2)) != NULL)
258 counter2++;
260 pushll (item->plist,
261 (void *) strdup (pos->getvalue().c_str()));
264 else if (move->getname() == "removegipf")
266 item->type = LOGREMGIPF;
267 item->player = (move->getattribute("owner"))[0];
268 item->plist = (listheader *) malloc (sizeof (listheader));
269 newlist (item->plist);
270 pushll (item->plist, (void *) strdup (move->getvalue().c_str()));
272 else
274 printf ("\nERROR: not a valid move-entry\n\n");
278 return (log);
283 ** write contents of a gamelog-structure to a file
284 ** in the format appropriate for writing down a gipf-game
286 ** parameters:
287 ** log: gamelog structure
288 ** fp: pointer to an open file
290 int logtofile (gamelog * log, FILE * fp)
292 char player = 'o',
293 newplayer,
294 * tempstr;
295 logitem * item;
296 int count = 1,
297 movecounter = 0,
298 before = 1,
299 totallength = 0,
301 count2;
302 string move,
303 remove,
304 removerow,
305 removewhite = "",
306 removeblack = "";
308 fprintf (fp, " %s\n\n", log->gametype);
310 fprintf (fp, " %-37.37s %s\n\n01. ",
311 log->whitename, log->blackname);
313 while ((item = (logitem *) llitembynr (log->moves, count)) != NULL)
315 count++;
317 if ((item->type == LOGMOVE) ||
318 (item->type == LOGREMROW))
320 if ((removewhite.length() > 0) ||
321 (removeblack.length() > 0))
323 if (player == 'o')
324 remove = removewhite + removerow + removeblack;
325 else
326 remove = removeblack + removerow + removewhite;
328 if (before)
330 fprintf (fp, "%s; ", remove.c_str());
331 totallength += 2 + remove.length();
333 else
335 fprintf (fp, " ; %s", remove.c_str());
336 totallength += 3 + remove.length();
338 removewhite = "";
339 removeblack = "";
342 // check if the next action is for the other player
343 newplayer = tolower (item->player);
344 if (newplayer != player)
346 if (newplayer == 'o')
348 fprintf (fp, "\n%2.2d. ", movecounter/2 + 1);
350 else
352 for (i = totallength; i < 38; i++)
353 fprintf (fp, " ");
355 totallength = 0;
356 player = newplayer;
357 before = 1;
361 if (item->type == LOGMOVE)
363 movecounter++;
365 move = "";
366 if ((item->player == 'O') || (item->player == 'X'))
367 move += "G";
369 move += item->start;
370 move += "-";
371 move += item->end;
372 fprintf (fp, "%s", move.c_str());
374 totallength += move.length();
375 before = 0;
377 else if (item->type == LOGREMGIPF)
379 tempstr = (char *) llitembynr (item->plist, 1);
380 if (tolower (tempstr[2]) == 'o')
382 removewhite += 'G';
383 removewhite += tempstr[0];
384 removewhite += tempstr[1];
385 removewhite += ' ';
387 else
389 removeblack += 'G';
390 removeblack += tempstr[0];
391 removeblack += tempstr[1];
392 removeblack += ' ';
395 else /* must be LOGREMROW now */
397 removerow = "x(";
398 removerow += item->start;
399 removerow += "-";
400 removerow += item->end;
401 removerow += ") ";
403 count2 = 1;
404 while ((tempstr = (char *) llitembynr (item->plist, count2))
405 != NULL)
407 count2++;
408 if (tolower (tempstr[2]) == 'o')
410 removewhite += tempstr[0];
411 removewhite += tempstr[1];
412 removewhite += ' ';
414 else
416 removeblack += tempstr[0];
417 removeblack += tempstr[1];
418 removeblack += ' ';
424 if ((removewhite.length() > 0) ||
425 (removeblack.length() > 0))
427 if (player == 'o')
428 remove = removewhite + removerow + removeblack;
429 else
430 remove = removeblack + removerow + removewhite;
432 if (before)
433 fprintf (fp, "%s; ", remove.c_str());
434 else
435 fprintf (fp, " ; %s", remove.c_str());
437 fprintf (fp, "\n");
439 return (0);
444 ** read log from a file and put it in a gamelog-structure
445 ** (the layout must be the same as written by logtofile)
447 ** the inputfile must already be open and should be at the first
448 ** line from the gamelog
450 ** REMARK: this is only used to read logs in the old fileformat
451 ** (before version 1.02)
453 gamelog * logfromfile (FILE * fp)
455 gamelog * log;
456 char buffer[100],
457 type[100],
458 wname[100],
459 bname[100];
460 logitem * item;
461 char * kar,
462 piece,
463 start[10]=" ",
464 end[10]=" ",
465 pos[10]=" ";
467 if (fgets (buffer, 100, fp) == NULL)
468 return (NULL);
469 buffer[strlen(buffer)-1] = '\0';
470 if (strncmp (buffer, "game: ", 6) != 0)
471 return (NULL);
472 strcpy (type, buffer+6);
474 if (fgets (buffer, 100, fp) == NULL)
475 return (NULL);
476 buffer[strlen(buffer)-1] = '\0';
477 if (strncmp (buffer, "white player: ", 14) != 0)
478 return (NULL);
479 strcpy (wname, buffer+14);
481 if (fgets (buffer, 100, fp) == NULL)
482 return (NULL);
483 buffer[strlen(buffer)-1] = '\0';
484 if (strncmp (buffer, "black player: ", 14) != 0)
485 return (NULL);
486 strcpy (bname, buffer+14);
488 log = newlog (type, wname, bname);
490 fgets (buffer, 100, fp);
491 fgets (buffer, 100, fp);
493 while (1)
495 if (fgets (buffer, 100, fp) == NULL)
497 deletelog (log);
498 return (NULL);
500 if (strncmp (buffer, "end of gamelog", 14) == 0)
501 break;
503 item = (logitem *) malloc (sizeof (logitem));
504 item->plist = NULL;
506 if (sscanf (buffer, "%c: %2s-%2s", &piece, start, end) == 3)
508 item->type = LOGMOVE;
510 else if (sscanf (buffer, " %c removegipf: %3s", &piece, pos) == 2)
512 item->type = LOGREMGIPF;
513 item->plist = (listheader *) malloc (sizeof (listheader));
514 newlist (item->plist);
515 pushll (item->plist, (void *) strdup (pos));
517 else if (sscanf (buffer, " %c removerow (%2s-%2s):",
518 &piece, start, end) == 3)
520 item->type = LOGREMROW;
521 item->plist = (listheader *) malloc (sizeof (listheader));
522 newlist (item->plist);
524 /* find pieces */
525 kar = strchr (buffer, ':');
526 kar++;
527 while (1)
529 while (isspace ((int) kar[0]))
530 kar++;
531 if (sscanf (kar, "%3s", pos) != 1)
532 break;
533 pushll (item->plist, (void *) strdup (pos));
534 kar += 4;
537 item->player = piece;
538 strcpy (item->start, start);
539 strcpy (item->end, end);
541 pushll (log->moves, (void *) item);
544 return (log);
549 ** take the contents of a gamelog-structure and format it in
550 ** a nice way to show in an fltk browser-widget
552 ** this function returns a list of lines that can be sent to the
553 ** widget without change
555 ** !! don't forget to cleanup the list !!
557 listheader * logtobrowser (gamelog * log)
559 listheader * lines;
560 char * newline,
561 whitepieces[50] = "",
562 blackpieces[50] = "",
563 owner = ' ',
564 * tempstr;
565 int movecounter = 0,
566 count = 1,
567 count2;
568 logitem * item;
570 lines = (listheader *) malloc (sizeof (listheader));
571 newlist (lines);
573 newline = (char *) malloc (40); /* is 40 always enough ? */
574 sprintf (newline, "@b%s", log->gametype);
575 pushll (lines, newline);
576 newline = (char *) malloc (1);
577 newline[0] = '\0';
578 pushll (lines, newline);
580 newline = (char *) malloc (40); /* is 40 always enough ? */
581 sprintf (newline, "@iwhite: %s", log->whitename);
582 pushll (lines, newline);
583 newline = (char *) malloc (40); /* is 40 always enough ? */
584 sprintf (newline, "@iblack: %s", log->blackname);
585 pushll (lines, newline);
586 newline = (char *) malloc (1);
587 newline[0] = '\0';
588 pushll (lines, newline);
590 while ((item = (logitem *) llitembynr (log->moves, count)) != NULL)
592 count++;
594 if ((owner != ' ') &&
595 ((item->type == LOGMOVE) || (item->type == LOGREMROW)))
597 newline = (char *) malloc (50); /* is 50 enough ? */
598 if (owner == 'o')
599 sprintf (newline, "@s w: %sx %s",
600 whitepieces, blackpieces);
601 else
602 sprintf (newline, "@s b: %sx %s",
603 blackpieces, whitepieces);
605 pushll (lines, newline);
607 owner = ' ';
608 whitepieces[0] = '\0';
609 blackpieces[0] = '\0';
612 if (item->type == LOGMOVE)
614 if ((movecounter % 2) == 0)
615 { /* need to show the nr of the move here */
616 newline = (char *) malloc (40); /* is 40 always enough ? */
617 sprintf (newline, "@c@b%d", movecounter/2 + 1);
618 pushll (lines, newline);
620 movecounter++;
622 newline = (char *) malloc (40); /* is 40 always enough ? */
623 if (tolower (item->player) == 'o')
624 sprintf (newline, "white: ");
625 else
626 sprintf (newline, "black: ");
628 if ((item->player == 'O') || (item->player == 'X'))
629 sprintf (newline + 7, "G");
631 sprintf (newline + strlen (newline), "%2s-%2s",
632 item->start, item->end);
634 pushll (lines, newline);
636 else if (item->type == LOGREMGIPF)
638 tempstr = (char *) llitembynr (item->plist, 1);
639 if (tolower (tempstr[2]) == 'o')
640 sprintf (whitepieces + strlen (whitepieces), "G%2.2s ",
641 tempstr);
642 else
643 sprintf (blackpieces + strlen (blackpieces), "G%2.2s ",
644 tempstr);
646 else /* must be LOGREMROW now */
648 count2 = 1;
649 owner = tolower (item->player);
651 while ((tempstr = (char *) llitembynr (item->plist, count2))
652 != NULL)
654 count2++;
655 if (tolower (tempstr[2]) == 'o')
656 sprintf (whitepieces + strlen (whitepieces), "%2.2s ",
657 tempstr);
658 else
659 sprintf (blackpieces + strlen (blackpieces), "%2.2s ",
660 tempstr);
665 if (owner != ' ')
667 newline = (char *) malloc (50); /* is 50 enough ? */
668 if (owner == 'o')
669 sprintf (newline, "@s w: %sx %s",
670 whitepieces, blackpieces);
671 else
672 sprintf (newline, "@s b: %sx %s",
673 blackpieces, whitepieces);
675 pushll (lines, newline);
678 return (lines);
683 ** return 1 if this logitem represents a move
685 int isamove (void * data)
687 logitem * item = (logitem *) data;
689 if (item->type == LOGMOVE)
690 return (1);
692 return (0);
697 ** remove the last move from a gamelog
698 ** (include all the removerows and removegipfs)
700 ** returns:
701 ** -1: error
702 ** number of items removed from the log
704 int remlastmove (gamelog * log)
706 int nr,
707 counter = 0;
708 logitem * item;
709 char * pos;
711 if ((nr = findlastll (log->moves, isamove)) == 0)
713 return (-1);
716 /* delete everything from the last move to the end of the list */
717 while ((item = (logitem *) llrembynr (log->moves, nr)) != NULL)
719 if (item->plist != NULL)
721 while ((pos = (char *) llrembynr (item->plist, 1)) != NULL)
723 free (pos);
725 free (item->plist);
728 free (item);
729 counter++;
732 return (counter);