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
;
165 x1
= new xmlite_entity ("gamelog");
166 x1
->addattribute ("gametype", log
->gametype
);
167 x1
->addattribute ("whiteplayer", log
->whitename
);
168 x1
->addattribute ("blackplayer", log
->blackname
);
170 while ((item
= (logitem
*) llitembynr (log
->moves
, counter
)) != NULL
)
177 x2
= new xmlite_entity ("move");
179 x2
->addattribute ("start", item
->start
);
180 x2
->addattribute ("end", item
->end
);
181 sprintf (tempstr
, "%c", item
->player
);
182 x2
->addattribute ("piece", tempstr
);
185 x2
= new xmlite_entity ("removegipf");
187 sprintf (tempstr
, "%c", item
->player
);
188 x2
->addattribute ("owner", tempstr
);
189 pos
= (char *) llitembynr (item
->plist
, 1);
193 x2
= new xmlite_entity ("removerow");
195 x2
->addattribute ("start", item
->start
);
196 x2
->addattribute ("end", item
->end
);
197 sprintf (tempstr
, "%c", item
->player
);
198 x2
->addattribute ("owner", tempstr
);
201 while ((pos
= (char *) llitembynr (item
->plist
, counter2
)) != NULL
)
205 x3
= new xmlite_entity ("position");
217 gamelog
* logfromxml (xmlite_entity
* root
)
222 xmlite_entity
* move
,
226 if (root
->getname () != "gamelog")
229 log
= newlog (root
->getattribute ("gametype").c_str(),
230 root
->getattribute ("whiteplayer").c_str(),
231 root
->getattribute ("blackplayer").c_str());
233 while ((move
= root
->getcontentbynr (counter
)) != NULL
)
237 item
= (logitem
*) malloc (sizeof (logitem
));
239 pushll (log
->moves
, (void *) item
);
241 if (move
->getname () == "move")
243 item
->type
= LOGMOVE
;
244 item
->player
= (move
->getattribute("piece"))[0];
245 strcpy (item
->start
, move
->getattribute("start").c_str());
246 strcpy (item
->end
, move
->getattribute("end").c_str());
248 else if (move
->getname() == "removerow")
250 item
->type
= LOGREMROW
;
251 item
->player
= (move
->getattribute("owner"))[0];
252 strcpy (item
->start
, move
->getattribute("start").c_str());
253 strcpy (item
->end
, move
->getattribute("end").c_str());
254 item
->plist
= (listheader
*) malloc (sizeof (listheader
));
255 newlist (item
->plist
);
257 while ((pos
= move
->getcontentbynr (counter2
)) != NULL
)
262 (void *) strdup (pos
->getvalue().c_str()));
265 else if (move
->getname() == "removegipf")
267 item
->type
= LOGREMGIPF
;
268 item
->player
= (move
->getattribute("owner"))[0];
269 item
->plist
= (listheader
*) malloc (sizeof (listheader
));
270 newlist (item
->plist
);
271 pushll (item
->plist
, (void *) strdup (move
->getvalue().c_str()));
275 printf ("\nERROR: not a valid move-entry\n\n");
284 ** write contents of a gamelog-structure to a file
285 ** in the format appropriate for writing down a gipf-game
288 ** log: gamelog structure
289 ** fp: pointer to an open file
291 int logtofile (gamelog
* log
, FILE * fp
)
310 fprintf (fp
, " %s\n\n", log
->gametype
);
312 fprintf (fp
, " %-37.37s %s\n\n01. ",
313 log
->whitename
, log
->blackname
);
315 while ((item
= (logitem
*) llitembynr (log
->moves
, count
)) != NULL
)
319 if ((item
->type
== LOGMOVE
) ||
320 (item
->type
== LOGREMROW
))
322 if ((removewhite
.length() > 0) ||
323 (removeblack
.length() > 0))
326 remove
= removewhite
+ removerow
+ removeblack
;
328 remove
= removeblack
+ removerow
+ removewhite
;
332 fprintf (fp
, "%s; ", remove
.c_str());
333 totallength
+= 2 + remove
.length();
337 fprintf (fp
, " ; %s", remove
.c_str());
338 totallength
+= 3 + remove
.length();
344 // check if the next action is for the other player
345 newplayer
= tolower (item
->player
);
346 if (newplayer
!= player
)
348 if (newplayer
== 'o')
350 fprintf (fp
, "\n%2.2d. ", movecounter
/2 + 1);
354 for (i
= totallength
; i
< 38; i
++)
363 if (item
->type
== LOGMOVE
)
368 if ((item
->player
== 'O') || (item
->player
== 'X'))
374 fprintf (fp
, "%s", move
.c_str());
376 totallength
+= move
.length();
379 else if (item
->type
== LOGREMGIPF
)
381 tempstr
= (char *) llitembynr (item
->plist
, 1);
382 if (tolower (tempstr
[2]) == 'o')
385 removewhite
+= tempstr
[0];
386 removewhite
+= tempstr
[1];
392 removeblack
+= tempstr
[0];
393 removeblack
+= tempstr
[1];
397 else /* must be LOGREMROW now */
400 removerow
+= item
->start
;
402 removerow
+= item
->end
;
406 while ((tempstr
= (char *) llitembynr (item
->plist
, count2
))
410 if (tolower (tempstr
[2]) == 'o')
412 removewhite
+= tempstr
[0];
413 removewhite
+= tempstr
[1];
418 removeblack
+= tempstr
[0];
419 removeblack
+= tempstr
[1];
426 if ((removewhite
.length() > 0) ||
427 (removeblack
.length() > 0))
430 remove
= removewhite
+ removerow
+ removeblack
;
432 remove
= removeblack
+ removerow
+ removewhite
;
435 fprintf (fp
, "%s; ", remove
.c_str());
437 fprintf (fp
, " ; %s", remove
.c_str());
446 ** read log from a file and put it in a gamelog-structure
447 ** (the layout must be the same as written by logtofile)
449 ** the inputfile must already be open and should be at the first
450 ** line from the gamelog
452 ** REMARK: this is only used to read logs in the old fileformat
453 ** (before version 1.02)
455 gamelog
* logfromfile (FILE * fp
)
469 if (fgets (buffer
, 100, fp
) == NULL
)
471 buffer
[strlen(buffer
)-1] = '\0';
472 if (strncmp (buffer
, "game: ", 6) != 0)
474 strcpy (type
, buffer
+6);
476 if (fgets (buffer
, 100, fp
) == NULL
)
478 buffer
[strlen(buffer
)-1] = '\0';
479 if (strncmp (buffer
, "white player: ", 14) != 0)
481 strcpy (wname
, buffer
+14);
483 if (fgets (buffer
, 100, fp
) == NULL
)
485 buffer
[strlen(buffer
)-1] = '\0';
486 if (strncmp (buffer
, "black player: ", 14) != 0)
488 strcpy (bname
, buffer
+14);
490 log
= newlog (type
, wname
, bname
);
492 fgets (buffer
, 100, fp
);
493 fgets (buffer
, 100, fp
);
497 if (fgets (buffer
, 100, fp
) == NULL
)
502 if (strncmp (buffer
, "end of gamelog", 14) == 0)
505 item
= (logitem
*) malloc (sizeof (logitem
));
508 if (sscanf (buffer
, "%c: %2s-%2s", &piece
, start
, end
) == 3)
510 item
->type
= LOGMOVE
;
512 else if (sscanf (buffer
, " %c removegipf: %3s", &piece
, pos
) == 2)
514 item
->type
= LOGREMGIPF
;
515 item
->plist
= (listheader
*) malloc (sizeof (listheader
));
516 newlist (item
->plist
);
517 pushll (item
->plist
, (void *) strdup (pos
));
519 else if (sscanf (buffer
, " %c removerow (%2s-%2s):",
520 &piece
, start
, end
) == 3)
522 item
->type
= LOGREMROW
;
523 item
->plist
= (listheader
*) malloc (sizeof (listheader
));
524 newlist (item
->plist
);
527 kar
= strchr (buffer
, ':');
531 while (isspace ((int) kar
[0]))
533 if (sscanf (kar
, "%3s", pos
) != 1)
535 pushll (item
->plist
, (void *) strdup (pos
));
539 item
->player
= piece
;
540 strcpy (item
->start
, start
);
541 strcpy (item
->end
, end
);
543 pushll (log
->moves
, (void *) item
);
551 ** take the contents of a gamelog-structure and format it in
552 ** a nice way to show in an fltk browser-widget
554 ** this function returns a list of lines that can be sent to the
555 ** widget without change
557 ** !! don't forget to cleanup the list !!
559 listheader
* logtobrowser (gamelog
* log
)
563 whitepieces
[50] = "",
564 blackpieces
[50] = "",
572 lines
= (listheader
*) malloc (sizeof (listheader
));
575 newline
= (char *) malloc (40); /* is 40 always enough ? */
576 sprintf (newline
, "@b%s", log
->gametype
);
577 pushll (lines
, newline
);
578 newline
= (char *) malloc (1);
580 pushll (lines
, newline
);
582 newline
= (char *) malloc (40); /* is 40 always enough ? */
583 sprintf (newline
, "@iwhite: %s", log
->whitename
);
584 pushll (lines
, newline
);
585 newline
= (char *) malloc (40); /* is 40 always enough ? */
586 sprintf (newline
, "@iblack: %s", log
->blackname
);
587 pushll (lines
, newline
);
588 newline
= (char *) malloc (1);
590 pushll (lines
, newline
);
592 while ((item
= (logitem
*) llitembynr (log
->moves
, count
)) != NULL
)
596 if ((owner
!= ' ') &&
597 ((item
->type
== LOGMOVE
) || (item
->type
== LOGREMROW
)))
599 newline
= (char *) malloc (50); /* is 50 enough ? */
601 sprintf (newline
, "@s w: %sx %s",
602 whitepieces
, blackpieces
);
604 sprintf (newline
, "@s b: %sx %s",
605 blackpieces
, whitepieces
);
607 pushll (lines
, newline
);
610 whitepieces
[0] = '\0';
611 blackpieces
[0] = '\0';
614 if (item
->type
== LOGMOVE
)
616 if ((movecounter
% 2) == 0)
617 { /* need to show the nr of the move here */
618 newline
= (char *) malloc (40); /* is 40 always enough ? */
619 sprintf (newline
, "@c@b%d", movecounter
/2 + 1);
620 pushll (lines
, newline
);
624 newline
= (char *) malloc (40); /* is 40 always enough ? */
625 if (tolower (item
->player
) == 'o')
626 sprintf (newline
, "white: ");
628 sprintf (newline
, "black: ");
630 if ((item
->player
== 'O') || (item
->player
== 'X'))
631 sprintf (newline
+ 7, "G");
633 sprintf (newline
+ strlen (newline
), "%2s-%2s",
634 item
->start
, item
->end
);
636 pushll (lines
, newline
);
638 else if (item
->type
== LOGREMGIPF
)
640 tempstr
= (char *) llitembynr (item
->plist
, 1);
641 if (tolower (tempstr
[2]) == 'o')
642 sprintf (whitepieces
+ strlen (whitepieces
), "G%2.2s ",
645 sprintf (blackpieces
+ strlen (blackpieces
), "G%2.2s ",
648 else /* must be LOGREMROW now */
651 owner
= tolower (item
->player
);
653 while ((tempstr
= (char *) llitembynr (item
->plist
, count2
))
657 if (tolower (tempstr
[2]) == 'o')
658 sprintf (whitepieces
+ strlen (whitepieces
), "%2.2s ",
661 sprintf (blackpieces
+ strlen (blackpieces
), "%2.2s ",
669 newline
= (char *) malloc (50); /* is 50 enough ? */
671 sprintf (newline
, "@s w: %sx %s",
672 whitepieces
, blackpieces
);
674 sprintf (newline
, "@s b: %sx %s",
675 blackpieces
, whitepieces
);
677 pushll (lines
, newline
);
685 ** return 1 if this logitem represents a move
687 int isamove (void * data
)
689 logitem
* item
= (logitem
*) data
;
691 if (item
->type
== LOGMOVE
)
699 ** remove the last move from a gamelog
700 ** (include all the removerows and removegipfs)
704 ** number of items removed from the log
706 int remlastmove (gamelog
* log
)
713 if ((nr
= findlastll (log
->moves
, isamove
)) == 0)
718 /* delete everything from the last move to the end of the list */
719 while ((item
= (logitem
*) llrembynr (log
->moves
, nr
)) != NULL
)
721 if (item
->plist
!= NULL
)
723 while ((pos
= (char *) llrembynr (item
->plist
, 1)) != NULL
)