Make book-edit function WB
authorH.G. Muller <h.g.muller@hccnet.nl>
Fri, 6 May 2011 16:06:48 +0000 (18:06 +0200)
committerH.G. Muller <h.g.muller@hccnet.nl>
Sat, 7 May 2011 14:36:21 +0000 (16:36 +0200)
The tags dialog is used to display the GUI book moves from the current
position, and will be updated when you step or move to another one.
The edited move list (with weights) can be written back to the book.

backend.c
backend.h
book.c
winboard/resource.h
winboard/wedittags.c
winboard/winboard.c
winboard/winboard.rc

index 2658402..8dcfbd6 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -9250,6 +9250,7 @@ ShowMove(fromX, fromY, toX, toY)
     DrawPosition(FALSE, boards[currentMove]);
     DisplayBothClocks();
     HistorySet(parseList,backwardMostMove,forwardMostMove,currentMove-1);
+    DisplayBook(currentMove);
 }
 
 void SendEgtPath(ChessProgramState *cps)
@@ -12311,6 +12312,7 @@ void
 EditTagsEvent()
 {
     char *tags = PGNTags(&gameInfo);
+    bookUp = FALSE;
     EditTagsPopUp(tags, NULL);
     free(tags);
 }
@@ -13491,6 +13493,7 @@ ForwardInner(target)
     if ( !matchMode && gameMode != Training) { // [HGM] PV info: routine tests if empty
        DisplayComment(currentMove - 1, commentList[currentMove]);
     }
+    DisplayBook(currentMove);
 }
 
 
@@ -13593,6 +13596,7 @@ BackwardInner(target)
     HistorySet(parseList,backwardMostMove,forwardMostMove,currentMove-1);
     // [HGM] PV info: routine tests if comment empty
     DisplayComment(currentMove - 1, commentList[currentMove]);
+    DisplayBook(currentMove);
 }
 
 void
index 005b0ff..8e499dd 100644 (file)
--- a/backend.h
+++ b/backend.h
@@ -111,6 +111,7 @@ extern ProcRef firstProgramPR, secondProgramPR;
 extern Board boards[];
 extern char marker[BOARD_RANKS][BOARD_FILES];
 extern char lastMsg[MSG_SIZ];
+extern Boolean bookUp;
 
 char *CmailMsg P((void));
 /* Tord: Added the useFEN960 parameter in PositionToFEN() below */
@@ -232,6 +233,9 @@ Boolean LoadMultiPV P((int x, int y, char *buf, int index, int *start, int *end)
 void UnLoadPV P(());
 void MovePV P((int x, int y, int h));
 int PromoScroll P((int x, int y));
+void EditBookEvent P((void));
+Boolean DisplayBook P((int moveNr));
+void SaveToBook P((char *text));
 
 char *StrStr P((char *string, char *match));
 char *StrCaseStr P((char *string, char *match));
diff --git a/book.c b/book.c
index bd3a49f..aecb30d 100644 (file)
--- a/book.c
+++ b/book.c
@@ -455,25 +455,22 @@ void move_to_string(char move_s[6], uint16 move)
     }
 }
 
-char *ProbeBook(int moveNr, char *book)
-{
+int GetBookMoves(int moveNr, char *book, entry_t entries[])
+{   // retrieve all entries for given position from book in 'entries', return number.
     FILE *f;
     entry_t entry;
     int offset;
     uint64 key;
-    entry_t entries[MOVE_BUF];
-    int count=0;
-    int ret, i, j;
-    static char move_s[6];
-    int total_weight;
+    int count;
+    int ret;
 
-    if(book == NULL || moveNr >= 2*appData.bookDepth) return NULL
-//    if(gameInfo.variant != VariantNormal) return NULL; // Zobrist scheme only works for normal Chess, so far
+    if(book == NULL || moveNr >= 2*appData.bookDepth) return -1
+//    if(gameInfo.variant != VariantNormal) return -1; // Zobrist scheme only works for normal Chess, so far
     f=fopen(book,"rb");
     if(!f){
-        DisplayError("Polyglot book not valid", 0);
+       DisplayError("Polyglot book not valid", 0);
        appData.usePolyglotBook = FALSE;
-        return NULL;
+       return -1;
     }
 
     key = hash(moveNr);
@@ -482,7 +479,7 @@ char *ProbeBook(int moveNr, char *book)
     offset=find_key(f, key, &entry);
     if(entry.key != key) {
          fclose(f);
-         return NULL;
+         return FALSE;
     }
     entries[0] = entry;
     count=1;
@@ -498,6 +495,20 @@ char *ProbeBook(int moveNr, char *book)
         if(count == MOVE_BUF) break;
         entries[count++] = entry;
     }
+    fclose(f);
+    return count;
+}
+
+char *ProbeBook(int moveNr, char *book)
+{   // 
+    entry_t entries[MOVE_BUF];
+    int count;
+    int i, j;
+    static char move_s[6];
+    int total_weight;
+
+    if((count = GetBookMoves(moveNr, book, entries)) <= 0) return NULL; // no book, or no hit
+
     if(appData.bookStrength != 50) { // transform weights
         double power = 0, maxWeight = 0.0;
         if(appData.bookStrength) power = (100.-appData.bookStrength)/appData.bookStrength;
@@ -522,6 +533,126 @@ char *ProbeBook(int moveNr, char *book)
     move_to_string(move_s, entries[i].move);
     if(appData.debugMode) fprintf(debugFP, "book move field = %d\n", entries[i].move);
 
-    fclose(f);
     return move_s;
 }
+
+extern char yy_textstr[];
+entry_t lastEntries[MOVE_BUF];
+
+char *MovesToText(int count, entry_t *entries)
+{
+       int i, totalWeight = 0;
+       char algMove[6];
+       char *p = (char*) malloc(30*count+1);
+       for(i=0; i<count; i++) totalWeight += entries[i].weight;
+       *p = 0;
+       for(i=0; i<count; i++) {
+           move_to_string(algMove, entries[i].move);
+           snprintf(p+strlen(p), 30, "%5.1f%% %5d %s\n", 100*entries[i].weight/(totalWeight+0.001), entries[i].weight, algMove);
+//lastEntries[i] = entries[i];
+       }
+       return p;
+}
+
+int TextToMoves(char *text, int moveNum, entry_t *entries)
+{
+       int i, w, count=0;
+      uint64 hashKey = hash(moveNum);
+       int  fromX, fromY, toX, toY, to, from;
+       ChessMove  moveType;
+       char promoChar, valid;
+       float dummy;
+       int width = BOARD_RGHT - BOARD_LEFT;
+
+       while((i=sscanf(text, "%f%%%d", &dummy, &w))==2 || (i=sscanf(text, "%d", &w))==1) {
+           if(i == 2) text = strchr(text, '%') + 1;  // skip percentage
+           if(w == 1) text = strstr(text, "1 ") + 2; // skip weight that could be recognized as move number one
+           valid = ParseOneMove(text, moveNum, &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
+           text = strstr(text, yy_textstr) + strlen(yy_textstr); // skip what we parsed
+           if(!valid || moveType != NormalMove) continue;
+           to = toX + toY * width;
+           from = fromX + fromY * width;
+           // TODO: promotions, drops
+           entries[count].move = to + from * width * BOARD_HEIGHT;
+           entries[count].key  = hashKey;
+           entries[count].weight = w;
+           entries[count].learn  = 0; //TODO: learn value?
+           count++;
+       }
+       return count;
+}
+
+Boolean bookUp;
+int currentCount;
+
+Boolean DisplayBook(int moveNr)
+{
+    entry_t entries[MOVE_BUF];
+    int count;
+    char *p;
+    if(!bookUp) return FALSE;
+    count = currentCount = GetBookMoves(moveNr, appData.polyglotBook, entries);
+    if(count < 0) return FALSE;
+    p = MovesToText(count, entries);
+    EditTagsPopUp(p, NULL);
+    free(p);
+    return TRUE;
+}
+
+void EditBookEvent()
+{
+      bookUp = TRUE;
+       bookUp = DisplayBook(currentMove);
+}
+
+void int_to_file(FILE *f, int l, uint64 r)
+{
+    int i;
+    for(i=l-1;i>=0;i--) fputc(r>>8*i & 255, f);
+}
+
+void entry_to_file(FILE *f, entry_t *entry)
+{
+    int_to_file(f,8,entry->key);
+    int_to_file(f,2,entry->move);
+    int_to_file(f,2,entry->weight);
+    int_to_file(f,4,entry->learn);
+}
+
+char buf1[4096], buf2[4096];
+
+void SaveToBook(char *text)
+{
+    entry_t entries[MOVE_BUF], entry;
+    int count = TextToMoves(text, currentMove, entries);
+    int offset, i, len1=0, len2, readpos=0, writepos=0;
+    FILE *f;
+    if(!count) return;
+    f=fopen(appData.polyglotBook, "rb+");
+    if(!f){    DisplayError("Polyglot book not valid", 0); return; }
+    offset=find_key(f, entries[0].key, &entry);
+    if(entries[0].key != entry.key) {
+         DisplayError("Hash keys are different", 0);
+         fclose(f);
+         return;
+    }
+    if(count != currentCount) {
+       readpos = 16*(offset + currentCount);
+       writepos = 16*(offset + count);
+       fseek(f, readpos, SEEK_SET);
+       readpos += len1 = fread(buf1, 1, 4096 - 16*currentCount, f); // salvage some entries immediately behind change
+    }
+    fseek(f, 16*(offset), SEEK_SET);
+    for(i=0; i<count; i++) entry_to_file(f, entries + i); // save the change
+    if(count != currentCount) {
+       do {
+           for(i=0; i<len1; i++) buf2[i] = buf1[i]; len2 = len1;
+           fseek(f, readpos, SEEK_SET);
+           readpos += len1 = fread(buf1, 1, 4096, f);
+           fseek(f, writepos, SEEK_SET);
+           fwrite(buf2, 1, len2, f);
+           writepos += len2;
+       } while(len1);
+    }
+    fclose(f);
+}
index bb5888d..aa1cda7 100644 (file)
 #define OPT_MESS                        1818\r
 #define IDM_Engine1Options             1890\r
 #define IDM_Engine2Options             1891\r
+#define IDM_EditBook                   1892\r
 #define IDM_Tourney                    1894\r
 #define IDC_STATIC                      -1\r
 // static strings that were made dynamic to allow run-time translation\r
index 22a23ab..2ec157d 100644 (file)
@@ -73,6 +73,10 @@ EditTagsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     EnableWindow(GetDlgItem(hDlg, OPT_TagsCancel), canEditTags);\r
     EnableWindow(GetDlgItem(hDlg, OPT_EditTags), !canEditTags);\r
     SendMessage(hwndText, EM_SETREADONLY, !canEditTags, 0);\r
+    if (bookUp) {\r
+      SetWindowText(hDlg, _("Edit Book"));\r
+      SetFocus(hwndText);\r
+    } else\r
     if (canEditTags) {\r
       SetWindowText(hDlg, _("Edit Tags"));\r
       SetFocus(hwndText);\r
@@ -127,8 +131,9 @@ EditTagsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
          else\r
            *p++ = *q++;\r
        }\r
-       *p = NULLCHAR;\r
-        if(resPtr) *resPtr = strdup(str), err = 0; else\r
+       *p = NULLCHAR; err = 0;\r
+        if(resPtr) *resPtr = strdup(str); else\r
+       if(bookUp) SaveToBook(str); else\r
        err = ReplaceTags(str, &gameInfo);\r
        if (err) DisplayError(_("Error replacing tags."), err);\r
 \r
@@ -173,7 +178,7 @@ VOID TagsPopDown(void)
 {\r
   if (editTagsDialog) ShowWindow(editTagsDialog, SW_HIDE);\r
   CheckMenuItem(GetMenu(hwndMain), IDM_Tags, MF_UNCHECKED);\r
-  editTagsUp = FALSE;\r
+  editTagsUp = bookUp = FALSE;\r
 }\r
 \r
 \r
@@ -230,7 +235,7 @@ VOID EditTagsPopUp(char *tags, char **dest)
 \r
 VOID EditTagsProc()\r
 {\r
-  if (editTagsUp) {\r
+  if (editTagsUp && !bookUp) {\r
     TagsPopDown();\r
   } else {\r
     EditTagsEvent();\r
index 0ff5e0b..722b9c8 100644 (file)
@@ -4958,6 +4958,10 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       EditTagsProc();\r
       break;\r
 \r
+    case IDM_EditBook:\r
+      EditBookEvent();\r
+      break;\r
+\r
     case IDM_EditComment:\r
     case IDM_Comment:\r
       if (commentUp && editComment) {\r
index 89cad99..1972762 100644 (file)
@@ -1137,6 +1137,7 @@ BEGIN
         MENUITEM SEPARATOR\r
         MENUITEM "Edit Ta&gs...",               IDM_EditTags\r
         MENUITEM "Edit Co&mment...",            IDM_EditComment\r
+        MENUITEM "Edit Boo&k...",               IDM_EditBook\r
         MENUITEM "Enter &Username...",          IDM_TypeInName\r
         MENUITEM SEPARATOR\r
         MENUITEM "&Revert\tHome",               IDM_Revert\r