4 ** a lot of things for dealing with the log from a gipf-game
6 ** the original of this file was gamelog.c
7 ** but because I had to add c++ code I had to rename it
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.
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.
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.
36 ** create a new, empty log structure
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
)
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
));
60 ** delete a complete gamelog structure
62 void deletelog (gamelog
* log
)
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
)
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
)
107 item
= (logitem
*) malloc (sizeof (logitem
));
114 if (sscanf (data
, "%c:%2s:%2s", &piece
, start
, end
) != 3)
121 if (sscanf (data
, "%c:%3s", &piece
, pos
) != 2)
126 item
->plist
= (listheader
*) malloc (sizeof (listheader
));
127 newlist (item
->plist
);
128 pushll (item
->plist
, (void *) strdup (pos
));
131 if (sscanf (data
, "%c:%2s:%2s:", &piece
, start
, end
) != 3)
136 item
->plist
= (listheader
*) malloc (sizeof (listheader
));
137 newlist (item
->plist
);
139 while (kar
[0] != '\0')
141 strncpy (pos
, kar
, 3);
142 pushll (item
->plist
, (void *) strdup (pos
));
147 item
->player
= piece
;
148 strcpy (item
->start
, start
);
149 strcpy (item
->end
, end
);
151 pushll (log
->moves
, (void *) item
);
155 xmlite_entity
* logtoxml (gamelog
* log
)
157 xmlite_entity
*x1
, *x2
, *x3
;
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
)
176 x2
= new xmlite_entity ("move");
178 x2
->addattribute ("start", item
->start
);
179 x2
->addattribute ("end", item
->end
);
180 sprintf (tempstr
, "%c", item
->player
);
181 x2
->addattribute ("piece", tempstr
);
184 x2
= new xmlite_entity ("removegipf");
186 sprintf (tempstr
, "%c", item
->player
);
187 x2
->addattribute ("owner", tempstr
);
188 pos
= (char *) llitembynr (item
->plist
, 1);
192 x2
= new xmlite_entity ("removerow");
194 x2
->addattribute ("start", item
->start
);
195 x2
->addattribute ("end", item
->end
);
196 sprintf (tempstr
, "%c", item
->player
);
197 x2
->addattribute ("owner", tempstr
);
200 while ((pos
= (char *) llitembynr (item
->plist
, counter2
)) != NULL
)
204 x3
= new xmlite_entity ("position");
216 gamelog
* logfromxml (xmlite_entity
* root
)
221 xmlite_entity
* move
,
225 if (root
->getname () != "gamelog")
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
)
236 item
= (logitem
*) malloc (sizeof (logitem
));
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
);
256 while ((pos
= move
->getcontentbynr (counter2
)) != NULL
)
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()));
274 printf ("\nERROR: not a valid move-entry\n\n");
283 ** write contents of a gamelog-structure to a file
284 ** in the format appropriate for writing down a gipf-game
287 ** log: gamelog structure
288 ** fp: pointer to an open file
290 int logtofile (gamelog
* log
, FILE * fp
)
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
)
317 if ((item
->type
== LOGMOVE
) ||
318 (item
->type
== LOGREMROW
))
320 if ((removewhite
.length() > 0) ||
321 (removeblack
.length() > 0))
324 remove
= removewhite
+ removerow
+ removeblack
;
326 remove
= removeblack
+ removerow
+ removewhite
;
330 fprintf (fp
, "%s; ", remove
.c_str());
331 totallength
+= 2 + remove
.length();
335 fprintf (fp
, " ; %s", remove
.c_str());
336 totallength
+= 3 + remove
.length();
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);
352 for (i
= totallength
; i
< 38; i
++)
361 if (item
->type
== LOGMOVE
)
366 if ((item
->player
== 'O') || (item
->player
== 'X'))
372 fprintf (fp
, "%s", move
.c_str());
374 totallength
+= move
.length();
377 else if (item
->type
== LOGREMGIPF
)
379 tempstr
= (char *) llitembynr (item
->plist
, 1);
380 if (tolower (tempstr
[2]) == 'o')
383 removewhite
+= tempstr
[0];
384 removewhite
+= tempstr
[1];
390 removeblack
+= tempstr
[0];
391 removeblack
+= tempstr
[1];
395 else /* must be LOGREMROW now */
398 removerow
+= item
->start
;
400 removerow
+= item
->end
;
404 while ((tempstr
= (char *) llitembynr (item
->plist
, count2
))
408 if (tolower (tempstr
[2]) == 'o')
410 removewhite
+= tempstr
[0];
411 removewhite
+= tempstr
[1];
416 removeblack
+= tempstr
[0];
417 removeblack
+= tempstr
[1];
424 if ((removewhite
.length() > 0) ||
425 (removeblack
.length() > 0))
428 remove
= removewhite
+ removerow
+ removeblack
;
430 remove
= removeblack
+ removerow
+ removewhite
;
433 fprintf (fp
, "%s; ", remove
.c_str());
435 fprintf (fp
, " ; %s", remove
.c_str());
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
)
467 if (fgets (buffer
, 100, fp
) == NULL
)
469 buffer
[strlen(buffer
)-1] = '\0';
470 if (strncmp (buffer
, "game: ", 6) != 0)
472 strcpy (type
, buffer
+6);
474 if (fgets (buffer
, 100, fp
) == NULL
)
476 buffer
[strlen(buffer
)-1] = '\0';
477 if (strncmp (buffer
, "white player: ", 14) != 0)
479 strcpy (wname
, buffer
+14);
481 if (fgets (buffer
, 100, fp
) == NULL
)
483 buffer
[strlen(buffer
)-1] = '\0';
484 if (strncmp (buffer
, "black player: ", 14) != 0)
486 strcpy (bname
, buffer
+14);
488 log
= newlog (type
, wname
, bname
);
490 fgets (buffer
, 100, fp
);
491 fgets (buffer
, 100, fp
);
495 if (fgets (buffer
, 100, fp
) == NULL
)
500 if (strncmp (buffer
, "end of gamelog", 14) == 0)
503 item
= (logitem
*) malloc (sizeof (logitem
));
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
);
525 kar
= strchr (buffer
, ':');
529 while (isspace ((int) kar
[0]))
531 if (sscanf (kar
, "%3s", pos
) != 1)
533 pushll (item
->plist
, (void *) strdup (pos
));
537 item
->player
= piece
;
538 strcpy (item
->start
, start
);
539 strcpy (item
->end
, end
);
541 pushll (log
->moves
, (void *) item
);
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
)
561 whitepieces
[50] = "",
562 blackpieces
[50] = "",
570 lines
= (listheader
*) malloc (sizeof (listheader
));
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);
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);
588 pushll (lines
, newline
);
590 while ((item
= (logitem
*) llitembynr (log
->moves
, count
)) != NULL
)
594 if ((owner
!= ' ') &&
595 ((item
->type
== LOGMOVE
) || (item
->type
== LOGREMROW
)))
597 newline
= (char *) malloc (50); /* is 50 enough ? */
599 sprintf (newline
, "@s w: %sx %s",
600 whitepieces
, blackpieces
);
602 sprintf (newline
, "@s b: %sx %s",
603 blackpieces
, whitepieces
);
605 pushll (lines
, newline
);
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
);
622 newline
= (char *) malloc (40); /* is 40 always enough ? */
623 if (tolower (item
->player
) == 'o')
624 sprintf (newline
, "white: ");
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 ",
643 sprintf (blackpieces
+ strlen (blackpieces
), "G%2.2s ",
646 else /* must be LOGREMROW now */
649 owner
= tolower (item
->player
);
651 while ((tempstr
= (char *) llitembynr (item
->plist
, count2
))
655 if (tolower (tempstr
[2]) == 'o')
656 sprintf (whitepieces
+ strlen (whitepieces
), "%2.2s ",
659 sprintf (blackpieces
+ strlen (blackpieces
), "%2.2s ",
667 newline
= (char *) malloc (50); /* is 50 enough ? */
669 sprintf (newline
, "@s w: %sx %s",
670 whitepieces
, blackpieces
);
672 sprintf (newline
, "@s b: %sx %s",
673 blackpieces
, whitepieces
);
675 pushll (lines
, newline
);
683 ** return 1 if this logitem represents a move
685 int isamove (void * data
)
687 logitem
* item
= (logitem
*) data
;
689 if (item
->type
== LOGMOVE
)
697 ** remove the last move from a gamelog
698 ** (include all the removerows and removegipfs)
702 ** number of items removed from the log
704 int remlastmove (gamelog
* log
)
711 if ((nr
= findlastll (log
->moves
, isamove
)) == 0)
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
)