#include #include #include #include #include #include #include #include #include #include "analyze.h" #include "games.h" #include "gospel.h" #include "utils.h" #include "xgospel.h" struct _Analyze { struct _Analyze *Next, *Previous; char *Name; int ReplayRate, ReplayCount; char *SgfFile, *PsFile; Gamelog *Log; int Level, BaseMove; size_t Size; Widget Model, TopWidget, BoardWidget, ScrollWidget, SgfOverwrite; Widget SgfFromStart, PsOverwrite, PsFromStart, Score; Widget MoveBeep, MoveRaise, ErrorBeep, ErrorRaise, Copy, Replay; Boolean scoring; float WhiteAdvantage; }; static Analyze *FindAnalyzeWidget(Widget w); static void CallScore(Widget w, XtPointer clientdata, XtPointer calldata); static char *BoardScore(Gamelog *Log, float WhiteAdvantage, Widget BoardWidget); static Analyze AnalyzeBase = { &AnalyzeBase, &AnalyzeBase }; static void CallDestroyAnalyze(Widget w, XtPointer clientdata, XtPointer calldata) { Analyze *Ana; Ana = (Analyze *) clientdata; if (Ana->Model) { XtRemoveCallback(Ana->Model, XtNdestroyCallback, CallDestroyWidgetReference, (XtPointer) &Ana->Model); XtRemoveCallback(Ana->Model, XtNdestroyCallback, CallDestroy, (XtPointer) Ana->Copy); } Ana->Previous->Next = Ana->Next; Ana->Next->Previous = Ana->Previous; FreeGamelog(Ana->Log); myfree(Ana->SgfFile); myfree(Ana->PsFile); myfree(Ana->Name); myfree(Ana); } static void GotoAnalyze(Analyze *analyze, int Pos) { Gamelog *log; int i, node, nodes; float Step; Widget w; log = analyze->Log; nodes = NumberNodes(log)-1; node = NodeNumber(log); if (Pos < 1) Pos = 1; else if (Pos > nodes) Pos = nodes; if (Pos > node) for (i=node; iPos; i--) UpGamelog(log); w = analyze->BoardWidget; if (w) { int x, y; DisplayScore(analyze->scoring, log, analyze->WhiteAdvantage, w, analyze->TopWidget); i = XTPOINTER_TO_INT(FindComment(log, &LastMoveFun)); if (i<0) x = y = -1; else { y = i / log->SizeX; x = i % log->SizeY; } LastMove(w, x, y); /* must be called after DisplayScore */ } if (analyze->ScrollWidget) { Step = 1.0 / nodes; MyScrollbarSetThumb(analyze->ScrollWidget, (Pos-1)*Step, Step); } } static void ResetAnalyze(Widget w, XtPointer clientdata, XtPointer calldata) { Analyze *Ana; Gamelog *log; int i, node, nodes; Ana = (Analyze *) clientdata; log = Ana->Log; node = NodeNumber(log)-1; nodes = NumberNodes(log)-2; for (i=node; i0; i--) { int uncaptured = DeleteNode(log); if (Ana->WhiteAdvantage != UNKNOWN_ADVANTAGE) { Ana->WhiteAdvantage -= uncaptured; } } if (Ana->scoring && Ana->Score) { CallScore(NULL, (XtPointer)Ana, NULL); /* toggle scoring */ } GotoAnalyze(Ana, 1); } static void UndoAnalyze(Widget w, XtPointer clientdata, XtPointer calldata) { Analyze *Ana; Gamelog *log; int i, node, nodes; int uncaptured; Ana = (Analyze *) clientdata; log = Ana->Log; node = NodeNumber(log)-1; nodes = NumberNodes(log)-2; if (nodes == 0) { IfBell(Ana->ErrorBeep); IfRaise(Ana->ErrorRaise, Ana->ErrorRaise); } else { for (i=node; iWhiteAdvantage != UNKNOWN_ADVANTAGE) { Ana->WhiteAdvantage -= uncaptured; } GotoAnalyze(Ana, nodes); } } static void ToggleReplay(Widget w, XtPointer clientdata, XtPointer calldata) { Analyze *analyze; Gamelog *log; int nodes; analyze = (Analyze *) clientdata; if (False == (Boolean) XTPOINTER_TO_INT(calldata)) analyze->ReplayRate = 0; else { analyze->ReplayRate = appdata.ReplayTimeout; log = analyze->Log; nodes = NumberNodes(log)-1; if (NodeNumber(log) == nodes) { GotoAnalyze(analyze, 1); analyze->ReplayCount = 0; } else analyze->ReplayCount = analyze->ReplayRate-1; } } static void AnalyzeAnalyze(Widget w, XtPointer clientdata, XtPointer calldata) { Analyze *Ana; Gamelog *log; int node; Ana = (Analyze *) clientdata; log = Ana->Log; node = NodeNumber(log)-1; OpenAnalyze(Ana->BoardWidget, Ana->Name, Ana->Level+1, Ana->Size, Ana->BaseMove+node, log->AllowSuicide, Ana->WhiteAdvantage); } static Exception NotEmpty = { "Position is not empty" }; static void AnalyzeButton(Widget w, XtPointer clientdata, XtPointer calldata) { Analyze *Ana; Gamelog *log; int i, node, nodes, move; float Step; GoButton *Button; char **Board; StoneList Stone; Boolean Beep; Button = (GoButton *) calldata; Ana = (Analyze *) clientdata; log = Ana->Log; node = NodeNumber(log)-1; nodes = NumberNodes(log)-2; for (i=node; iBoardWidget; if (Button->params != 1) { Warning("Invalid parameters to Button action\n"); return; } Board = GamelogToBoard(log); if (Button->x >= 0 && Button->x < log->SizeX && Button->y >= 0 && Button->y < log->SizeY) { WITH_HANDLING { int buttonNb = atoi(Button->str[0]); int captures = 0; /* number of captured black stones */ BWPiece oldColor = (BWPiece)Board[Button->y][Button->x]; move = Ana->BaseMove+nodes; switch(buttonNb) { case 0: if (oldColor == Empty) { /* add a stone */ captures = DoMove(log, Button->x, Button->y, move & 1 ? White : Black); LastMove(w, Button->x, Button->y); i = Button->y * log->SizeX + Button->x; AddComment(log, &LastMoveFun, INT_TO_XTPOINTER(i)); if (Ana->MoveBeep) { XtVaGetValues(Ana->MoveBeep, XtNstate, (XtArgVal) &Beep, NULL); if (Beep != False) StoneSound(Ana->BoardWidget); } } else if (!Ana->scoring) { /* remove a single stone */ captures = (oldColor == Black ? 1 : -1); Stone.x = Button->x; Stone.y = Button->y; Stone.Color = Empty; Stone.Next = NULL; SetStones(log, &Stone); LastMove(w, -1, -1); AddComment(log, &LastMoveFun, INT_TO_XTPOINTER(-1)); } else { /* in scoring mode, remove a stone group */ captures = RemoveGroupFromStone(log, Button->x, Button->y); LastMove(w, -1, -1); AddComment(log, &LastMoveFun, INT_TO_XTPOINTER(-1)); } if (Ana->WhiteAdvantage != UNKNOWN_ADVANTAGE) { Ana->WhiteAdvantage += captures; } break; case 1: /* set black stone */ case 2: /* set white stone */ Stone.Color = (buttonNb == 1 ? Black : White); if (Stone.Color != oldColor) { Stone.x = Button->x; Stone.y = Button->y; Stone.Next = NULL; SetStones(log, &Stone); /* WhiteAdvantage unchanged */ LastMove(w, -1, -1); AddComment(log, &LastMoveFun, INT_TO_XTPOINTER(-1)); } break; default: Warning("Invalid parameter '%s' to Button action\n", Button->str[0]); break; } IfRaise(Ana->MoveRaise, Ana->MoveRaise); } ON_EXCEPTION { IfBell(Ana->ErrorBeep); IfRaise(Ana->ErrorRaise, Ana->ErrorRaise); /* Warning(ExceptionName()); */ ClearException(); } END_HANDLING; } GotoAnalyze(Ana, NumberNodes(log)-1); /* display new board and score */ } static void ScrollAnalyze(Widget scrollbar, XtPointer client_data, XtPointer pos) { Analyze *Ana; int Pos, Pixels; Dimension Length; Ana = (Analyze *) client_data; Pos = XTPOINTER_TO_INT(pos); if (scrollbar) XtVaGetValues(scrollbar, XtNlength, (XtArgVal) &Length, NULL); Pixels = (int) Length / (NumberNodes(Ana->Log)-1); if (Pixels < appdata.ScrollUnit) Pixels = appdata.ScrollUnit; if (Pos < 0) Pos = Pos/Pixels-1; else Pos = Pos/Pixels+1; GotoAnalyze(Ana, NodeNumber(Ana->Log)+Pos); } static void JumpAnalyze(Widget scrollbar, XtPointer client_data, XtPointer per) { Analyze *analyze; int Pos; analyze = (Analyze *) client_data; Pos = * (float *) per * (NumberNodes(analyze->Log)-1); GotoAnalyze(analyze, Pos+1); } void AnalyzeGoto(Widget w, XEvent *event, String *string, Cardinal *n) /* used to scroll the board by forward (string > 0) or backward (string < 0). */ { Analyze *analyze = FindAnalyzeWidget(w); if (analyze) { int move = NodeNumber(analyze->Log) + ResourceStringToInt(string[0]); GotoAnalyze(analyze, move); } else { printf("AnalyzeGoto: analyze widget not found\n"); fflush(stdout); } } static void ToggleAllowSuicide(Widget w, XtPointer clientdata, XtPointer calldata) { Analyze *analyze; analyze = (Analyze *) clientdata; analyze->Log->AllowSuicide = False != (Boolean) XTPOINTER_TO_INT(calldata); } /* Toggle equal time blink */ void ToggleBlink(Widget w, XtPointer clientdata, XtPointer calldata) { Widget board; int timeout; board = (Widget) clientdata; if (False == (Boolean) XTPOINTER_TO_INT(calldata)) XtVaSetValues(board, XtNoffTimeout, (XtArgVal) 0, NULL); else { XtVaGetValues(board, XtNonTimeout, (XtArgVal) &timeout, NULL); XtVaSetValues(board, XtNoffTimeout, (XtArgVal) timeout, NULL); } } extern Observe *_FindBoardWidget(Widget w); static void CallCopy(Widget w, XtPointer clientdata, XtPointer calldata) { Widget board; Analyze *Ana, *Here; Gamelog *Log; char **Board; int move, AllowSuicide; size_t Size; Observe *observe; ResetAnalyze(w, clientdata, calldata); Ana = (Analyze *) clientdata; board = Ana->BoardWidget; if (board) { AllowSuicide = Ana->Log->AllowSuicide; FreeGamelog(Ana->Log); Size = Ana->Size; Ana->Log = Log = AllocGamelog(Size, Size, AllowSuicide); AddComment(Log, &LastMoveFun, INT_TO_XTPOINTER(Size-1)); w = Ana->Model; if (w) { observe = _FindBoardWidget(w); if (observe) { move = ObserveMove(observe); Ana->WhiteAdvantage = GetWhiteAdvantage(observe); } else { for (Here = AnalyzeBase.Next; Here != &AnalyzeBase; Here = Here->Next) if (Here->BoardWidget == w) { move = Here->BaseMove + NumberNodes(Here->Log)-2; Ana->WhiteAdvantage = Here->WhiteAdvantage; goto found; } Raise1(AssertException, "Could not find widget to copy from"); } found: if (Ana->WhiteAdvantage == UNKNOWN_ADVANTAGE) { XtUnmanageChild(Ana->Score); Ana->scoring = False; } else { XtManageChild(Ana->Score); } Board = AllocBoard(Size, Size); WITH_UNWIND { GetBoard(w, Board); PositionToNode(Log, Board, Empty); } ON_UNWIND { FreeBoard(Board, Size); } END_UNWIND; } else { SetStones(Log, NULL); move = 0; } AddComment(Log, &LastMoveFun, INT_TO_XTPOINTER(-Size-1)); ResetAnalyze(NULL, (XtPointer)Ana, NULL); Ana->BaseMove = move; } } static void CallScore(Widget w, XtPointer clientdata, XtPointer calldata) /* IN assertion: Ana->Score != NULL (the Score/Done button exists) */ { Analyze *Ana = (Analyze *) clientdata; Ana->scoring = !Ana->scoring; if (Ana->scoring) { XtVaSetValues(Ana->Score, XtNlabel, (XtArgVal) "Done", NULL); } else { XtVaSetValues(Ana->Score, XtNlabel, (XtArgVal) "Score", NULL); } DisplayScore(Ana->scoring, Ana->Log, Ana->WhiteAdvantage, Ana->BoardWidget, Ana->TopWidget); } /* Analyze should have pos in structure (share with observe ?) -Ton */ static void SaveGame(Widget w, XtPointer clientdata, XtPointer calldata) { Analyze *Ana; Gamelog *log; Boolean Overwrite, FromStart; int i, Now, node; Ana = (Analyze *) clientdata; log = Ana->Log; Now = NodeNumber(log)-1; w = Ana->SgfFromStart; if (w) XtVaGetValues(w, XtNstate, (XtArgVal) &FromStart, NULL); else FromStart = True; if (FromStart != False) { node = 0; if (Now > node) for (i = Now; i > node; i--) UpGamelog(log); } else node = Now; WITH_UNWIND { w = Ana->SgfOverwrite; if (w) XtVaGetValues(w, XtNstate, (XtArgVal) &Overwrite, NULL); else Overwrite = False; SaveWrite(Ana->SgfFile, Overwrite, Ana->ErrorBeep, Ana->ErrorRaise, "Sgf save error", WriteSgfFun, (XtPointer) log); } ON_UNWIND { if (Now > node) for (i = node; i < Now; i++) DownGamelog(log); } END_UNWIND; } static void SavePs(Widget w, XtPointer clientdata, XtPointer calldata) { Analyze *Ana; Gamelog *log; Boolean Overwrite, FromStart; int i, Now, node; Ana = (Analyze *) clientdata; log = Ana->Log; Now = NodeNumber(log)-1; w = Ana->PsFromStart; if (w) XtVaGetValues(w, XtNstate, (XtArgVal) &FromStart, NULL); else FromStart = True; if (FromStart != False) { node = 0; if (Now > node) for (i = Now; i > node; i--) UpGamelog(log); } else node = Now; WITH_UNWIND { w = Ana->PsOverwrite; if (w) XtVaGetValues(w, XtNstate, (XtArgVal) &Overwrite, NULL); else Overwrite = False; SaveWrite(Ana->PsFile, Overwrite, Ana->ErrorBeep, Ana->ErrorRaise, "Postscript save error", WritePsFun, (XtPointer) log); } ON_UNWIND { if (Now > node) for (i = node; i < Now; i++) DownGamelog(log); } END_UNWIND; } static Analyze *RealOpenAnalyze(Analyze *Ana) { const char *Name; char title[80], icon[80]; int Level, Size; Boolean state; Widget Root, Reset, Analyse, board, undo, Scroll, SgfSave, PsSave; Widget SgfFile, PsFile, AllowSuicide, Blink, Copy, Replay, Score; Level = Ana->Level; Name = Ana->Name; Size = Ana->Size; if (Level > 0) { sprintf(title, "%d", Ana->Level+1); Ana->SgfFile = StringToFilename(appdata.AnalyzeFilename, (int) 'T', SGFEXTENSION, (int) 't', ".", (int) 'N', "Analyzing", (int) 'n', "_", (int) 'B', "", (int) 'b', "", (int) 'W', "", (int) 'w', "", (int) 'U', "", (int) 'V', "", (int) 'L', title, (int) 'l', "_", 0); Ana->PsFile = StringToFilename(appdata.AnalyzeFilename, (int) 'T', PSEXTENSION, (int) 't', ".", (int) 'N', "Analyzing", (int) 'n', "_", (int) 'B', "", (int) 'b', "", (int) 'W', "", (int) 'w', "", (int) 'U', "", (int) 'V', "", (int) 'L', title, (int) 'l', "_", 0); sprintf(title, "Analyzing**%d %s", Ana->Level+1, Name); sprintf(icon, "Analyzing**%d %s", Ana->Level+1, Name); } else { Ana->SgfFile = StringToFilename(appdata.AnalyzeFilename, (int) 'T', SGFEXTENSION, (int) 't', ".", (int) 'N', "Analyzing", (int) 'n', "_", (int) 'B', "", (int) 'b', "", (int) 'W', "", (int) 'w', "", (int) 'U', "", (int) 'V', "", (int) 'L', "", (int) 'l', "", 0); Ana->PsFile = StringToFilename(appdata.AnalyzeFilename, (int) 'T', PSEXTENSION, (int) 't', ".", (int) 'N', "Analyzing", (int) 'n', "_", (int) 'B', "", (int) 'b', "", (int) 'W', "", (int) 'w', "", (int) 'U', "", (int) 'V', "", (int) 'L', "", (int) 'l', "", 0); if (strncmp(Name, "status ", 7)) { sprintf(title, "Analyzing %s", Name); sprintf(icon, "Analyzing %s", Name); } else { strcpy(title, Name); strcpy(icon, Name); } } Root = MyVaCreateManagedWidget("analyzer", toplevel, XtNtitle, (XtArgVal) title, XtNiconName, (XtArgVal) icon, XtNboardSize, (XtArgVal) Size, NULL); XtAddCallback(Root, XtNdestroyCallback, CallDestroyAnalyze, (XtPointer) Ana); Reset = XtNameToWidget(Root, "*reset"); if (Reset) XtAddCallback(Reset, XtNcallback, ResetAnalyze,(XtPointer) Ana); undo = XtNameToWidget(Root, "*undo"); if (undo) XtAddCallback(undo, XtNcallback, UndoAnalyze, (XtPointer) Ana); Analyse = XtNameToWidget(Root, "*analyze"); if (Analyse) XtAddCallback(Analyse, XtNcallback, AnalyzeAnalyze, (XtPointer) Ana); AllowSuicide = XtNameToWidget(Root, "*allowSuicide"); if (AllowSuicide) { XtVaSetValues(AllowSuicide, XtNstate, (XtArgVal) (Ana->Log->AllowSuicide ? True : False), NULL); XtAddCallback(AllowSuicide, XtNcallback, ToggleAllowSuicide, (XtPointer) Ana); } board = XtNameToWidget(Root, "*board"); Blink = XtNameToWidget(Root, "*blink"); if (Blink && board) { XtAddCallback(Blink, XtNcallback, ToggleBlink, (XtPointer) board); XtVaGetValues(Blink, XtNstate, (XtArgVal) &state, NULL); if (state == False) XtVaSetValues(board, XtNoffTimeout, (XtArgVal) 0, NULL); } Scroll = XtNameToWidget(Root, "*scroll"); if (Scroll) { MyScrollbarSetThumb(Scroll, 0.0, 1.0); XtAddCallback(Scroll, XtNjumpProc, JumpAnalyze, (XtPointer) Ana); XtAddCallback(Scroll, XtNscrollProc, ScrollAnalyze, (XtPointer) Ana); XtAddCallback(board, XtNbuttonUp, AnalyzeButton, (XtPointer) Ana); } SgfSave = XtNameToWidget(Root, "*sgfSave"); if (SgfSave) XtAddCallback(SgfSave, XtNcallback, SaveGame, (XtPointer) Ana); SgfFile = XtNameToWidget(Root, "*sgfFile"); if (SgfFile) XtAddCallback(SgfFile, XtNcallback, ChangeSgfFilename, (XtPointer) &Ana->SgfFile); PsSave = XtNameToWidget(Root, "*psSave"); if (PsSave) XtAddCallback(PsSave, XtNcallback, SavePs, (XtPointer) Ana); PsFile = XtNameToWidget(Root, "*psFile"); if (PsFile) XtAddCallback(PsFile, XtNcallback, ChangePsFilename, (XtPointer) &Ana->PsFile); Copy = XtNameToWidget(Root, "*copy"); if (Copy) XtAddCallback(Copy, XtNcallback, CallCopy, (XtPointer) Ana); Score = XtNameToWidget(Root, "*score"); if (Score) XtAddCallback(Score, XtNcallback, CallScore, (XtPointer) Ana); Replay = XtNameToWidget(Root, "*replay"); if (Replay) { XtAddCallback(Replay, XtNcallback, ToggleReplay, (XtPointer) Ana); XtVaGetValues(Replay, XtNstate, (XtArgVal) &state, NULL); ToggleReplay(0, (XtPointer) Ana, INT_TO_XTPOINTER((int) state)); } MyRealizeWidget(Root); OpenBoard(board); SetBoard(board, GamelogToBoard(Ana->Log)); CloseBoard(board); LastMove(board, -1, -1); Ana->TopWidget = Root; Ana->ScrollWidget = Scroll; Ana->BoardWidget = board; Ana->SgfOverwrite = XtNameToWidget(Root, "*sgfOverwrite"); Ana->SgfFromStart = XtNameToWidget(Root, "*sgfFromStart"); Ana->PsOverwrite = XtNameToWidget(Root, "*psOverwrite"); Ana->PsFromStart = XtNameToWidget(Root, "*psFromStart"); Ana->Replay = Replay; Ana->MoveBeep = XtNameToWidget(Root, "*moveBeep"); Ana->MoveRaise = XtNameToWidget(Root, "*moveRaise"); Ana->ErrorBeep = XtNameToWidget(Root, "*errorBeep"); Ana->ErrorRaise = XtNameToWidget(Root, "*errorRaise"); Ana->Copy = Copy; Ana->Score = Score; return Ana; } Analyze *OpenAnalyze(Widget w, const char *Name, int Level, size_t Size, int Move, int AllowSuicide, float WhiteAdvantage) { Analyze *Ana; Gamelog *Log; char **Board; Boolean flip; Ana = mynew(Analyze); WITH_HANDLING { Ana->Model = 0; Ana->Name = Ana->SgfFile = Ana->PsFile = NULL; Ana->Log = NULL; Ana->Next = AnalyzeBase.Next; Ana->Previous = &AnalyzeBase; Ana->Next->Previous = Ana->Previous->Next = Ana; Ana->Level = Level; Ana->Size = Size; Ana->BaseMove = Move; Ana->Name = mystrdup(Name); Ana->scoring = False; Ana->WhiteAdvantage = WhiteAdvantage; Ana->Log = Log = AllocGamelog(Size, Size, AllowSuicide); AddComment(Log, &LastMoveFun, INT_TO_XTPOINTER(Size-1)); if (w) { Board = AllocBoard(Size, Size); WITH_UNWIND { GetBoard(w, Board); PositionToNode(Log, Board, Empty); } ON_UNWIND { FreeBoard(Board, Size); } END_UNWIND; } else SetStones(Log, NULL); AddComment(Log, &LastMoveFun, INT_TO_XTPOINTER(-Size-1)); RealOpenAnalyze(Ana); XtVaGetValues(w, XtNflipBoard, &flip, NULL); XtVaSetValues(Ana->BoardWidget, XtNflipBoard, flip, NULL); if (w) { XtAddCallback(w, XtNdestroyCallback, CallDestroyWidgetReference, (XtPointer) &Ana->Model); XtAddCallback(w, XtNdestroyCallback, CallDestroy, (XtPointer) Ana->Copy); Ana->Model = w; } else { XtUnmanageChild(Ana->Copy); } if (WhiteAdvantage == UNKNOWN_ADVANTAGE) { XtUnmanageChild(Ana->Score); } } ON_EXCEPTION { CallDestroyAnalyze(0, (XtPointer) Ana, 0); } END_HANDLING; return Ana; } Analyze *AnalyzeBoard(char **Board, const char *Name, int Level, size_t Size, int Move, int AllowSuicide, float WhiteAdvantage) { Analyze *Ana; Gamelog *Log; Ana = mynew(Analyze); WITH_HANDLING { Ana->Name = Ana->SgfFile = Ana->PsFile = NULL; Ana->Log = NULL; Ana->Model = 0; Ana->Name = mystrdup(Name); Ana->Next = AnalyzeBase.Next; Ana->Previous = &AnalyzeBase; Ana->Next->Previous = Ana->Previous->Next = Ana; Ana->Level = Level+1; Ana->Size = Size; Ana->BaseMove = Move; Ana->scoring = False; Ana->WhiteAdvantage = WhiteAdvantage; Ana->Log = Log = AllocGamelog(Size, Size, AllowSuicide); AddComment(Log, &LastMoveFun, INT_TO_XTPOINTER(Size-1)); PositionToNode(Log, Board, Empty); AddComment(Log, &LastMoveFun, INT_TO_XTPOINTER(-Size-1)); RealOpenAnalyze(Ana); XtUnmanageChild(Ana->Copy); if (WhiteAdvantage != UNKNOWN_ADVANTAGE) { CallScore(NULL, (XtPointer)Ana, NULL); /* set scoring mode */ } else { XtUnmanageChild(Ana->Score); } } ON_EXCEPTION { CallDestroyAnalyze(0, (XtPointer) Ana, 0); } END_HANDLING; return Ana; } void AnalyzeTime(unsigned long diff) { Analyze *analyze; int node; for (analyze = AnalyzeBase.Next; analyze != &AnalyzeBase; analyze = analyze->Next) if (analyze->ReplayRate) { analyze->ReplayCount += diff; if (analyze->ReplayCount >= analyze->ReplayRate) { analyze->ReplayCount = 0; node = NodeNumber(analyze->Log); if (node == NumberNodes(analyze->Log)-1) { analyze->ReplayRate = 0; if (analyze->Replay) XtVaSetValues(analyze->Replay, XtNstate, (XtArgVal) False, NULL); } else GotoAnalyze(analyze, node+1); } } } static Analyze *FindAnalyzeWidget(Widget w) { Analyze *analyze; for (analyze = AnalyzeBase.Next; analyze != &AnalyzeBase; analyze = analyze->Next) { if (analyze->TopWidget == w || analyze->BoardWidget == w) { return analyze; } } return NULL; } void DisplayScore(Boolean scoring, Gamelog *Log, float WhiteAdvantage, Widget BoardWidget, Widget TopWidget) /* If scoring and positionned at last node, display the score in the title * and draw the board with dame highlighted. Otherwise erase the score in * the title and clear the dame. */ { char **Board = GamelogToBoard(Log); String title; char newTitle[128]; char *p; int node = NodeNumber(Log); int nodes = NumberNodes(Log)-1; int x, y; XtVaGetValues(TopWidget, XtNtitle, (XtArgVal)&title, NULL); if (title == NULL) return; strncpy(newTitle, title, sizeof(newTitle)-1); newTitle[sizeof(newTitle)-1] = '\0'; p = strrchr(newTitle, '+'); /* look for existing result */ if (p && p[1] >= '0' && p[1] <= '9') { p -= 3; /* point at first space */ if (p < newTitle) return; /* just for safety, should not happen */ } else { p = strchr(newTitle, '\0'); } if (scoring && node == nodes) { sprintf(p, " %s", BoardScore(Log, WhiteAdvantage, BoardWidget)); } else { *p = '\0'; /* Clear all marks. The mark on the last move may be restored * later by GotoAnalyze or GotoObserve. */ for (y = 0; y < Log->SizeY; y++) { for (x = 0; x < Log->SizeX; x++) { SetMark(BoardWidget, x, y, NoMark); } } } if (strcmp(newTitle, title)) { XtVaSetValues(TopWidget, XtNtitle, (XtArgVal)newTitle, NULL); } OpenBoard(BoardWidget); SetBoard(BoardWidget, Board); CloseBoard(BoardWidget); } static char *BoardScore(Gamelog *Log, float WhiteAdvantage, Widget BoardWidget) /* Mark territory and dame points and return the computed score as a string like "B+0.5". In this simple version, dead stones are assumed to be removed already, and only IGS counting rules are supported. IN assertion: WhiteAdvantage != UNKNOWN_ADVANTAGE */ { char **Board = GamelogToBoard(Log); float score = WhiteAdvantage; static char result[20]; int x, y; int size = Log->SizeX; Boolean updated; #define SEE_WHITE 0x40 #define SEE_BLACK 0x20 #define FLAGS (SEE_WHITE | SEE_BLACK) #ifdef DUMP # define DUMP_PIECE(x,y) \ { if ((Board[y][x] & ~FLAGS) == White) putchar('W'); \ else if ((Board[y][x] & ~FLAGS) == Black) putchar('B'); \ else if ((Board[y][x] & FLAGS) == SEE_WHITE) putchar('w'); \ else if ((Board[y][x] & FLAGS) == SEE_BLACK) putchar('b'); \ else if ((Board[y][x] & FLAGS) == FLAGS) putchar('d'); /* dame */ \ else if ((Board[y][x] & FLAGS) == 0) putchar('.'); \ else putchar('?'); } # define NEW_LINE putchar('\n') #else # define DUMP_PIECE(x,y) {} # define NEW_LINE {} #endif #ifdef DUMP printf("Analyze before, w advantage %.1f:\n", score); #endif for (y = 0; y < size; y++) { for (x = 0; x < size; x++) { DUMP_PIECE(x,y); if (Board[y][x] == White) { Board[y][x] |= SEE_WHITE; } else if (Board[y][x] == Black) { Board[y][x] |= SEE_BLACK; } } NEW_LINE; } /* Iterate to find the dame: empty points reaching both black and white */ do { updated = FALSE; for (y = 0; y < size; y++) { for (x = 0; x < size; x++) { char old = Board[y][x]; if ((old & ~FLAGS) == Empty) { if (x > 0) Board[y][x] |= (Board[y][x-1] & FLAGS); if (y > 0) Board[y][x] |= (Board[y-1][x] & FLAGS); if (x < size-1) Board[y][x] |= (Board[y][x+1] & FLAGS); if (y < size-1) Board[y][x] |= (Board[y+1][x] & FLAGS); updated |= (Board[y][x] != old); } } } } while (updated); #ifdef DUMP printf("Analyze after:\n"); #endif for (y = 0; y < size; y++) { for (x = 0; x < size; x++) { BWMark mark; BWPiece col = (BWPiece)Board[y][x]; DUMP_PIECE(x,y); if (col == (FLAGS | Empty)) { mark = (appdata.MarkDame ? DameMark : NoMark); } else if (col == (SEE_WHITE | Empty)) { score += 1.; mark = (appdata.MarkTerritories ? WhiteMark : NoMark); } else if (col == (SEE_BLACK | Empty)) { score -= 1.; mark = (appdata.MarkTerritories ? BlackMark : NoMark); } else { mark = NoMark; /* The mark on the last move may be restored * later by GotoAnalyze or GotoObserve. */ } Board[y][x] &= ~FLAGS; SetMark(BoardWidget, x, y, mark); } NEW_LINE; } if (score < 0.) { sprintf(result, "B+%.1f", -score); } else { sprintf(result, "W+%.1f", score); } #ifdef DUMP printf("score %s\n", result); fflush(stdout); #endif return result; }