Scid  4.7.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
book.tcl
Go to the documentation of this file.
1 ###
2 ### book.tcl: part of Scid.
3 ### Copyright (C) 2007 Pascal Georges
4 ###
5 ######################################################################
6 ### Book window
7 
8 namespace eval book {
9  set isOpen 0
10  set isReadonly 0
11  set bookList ""
12  set bookPath ""
13  set currentBook "" ; # book in form abc.bin
14  set currentTuningBook ""
15  set bookMoves ""
16  set cancelBookExport 0
17  set exportCount 0
18  set exportMax 3000
19  set hashList ""
20  set bookSlot 0
21  set bookTuningSlot 2
22  set oppMovesVisible 0
23 
24 
25  ################################################################################
26  # open a book, closing any previously opened one (called by annotation analysis)
27  # arg name : gm2600.bin for example
28  ################################################################################
29  proc scBookOpen { name slot } {
30  if {$slot == $::book::bookSlot} {
31  if {$::book::currentBook != ""} {
32  sc_book close $::book::bookSlot
33  }
34  set ::book::currentBook $name
35  }
36  if {$slot == $::book::bookTuningSlot} {
37  if {$::book::currentTuningBook != ""} {
38  sc_book close $::book::bookTuningSlot
39  }
40  set ::book::currentTuningBook $name
41  }
42 
43  set bn [ file join $::scidBooksDir $name]
44  set ::book::isReadonly [sc_book load $bn $slot]
45  }
46 
47  ################################################################################
48  # Return a move in book for position fen. If there is no move in book, returns ""
49  # Is used by engines, not book windows
50  ################################################################################
51  proc getMove { book fen slot} {
52  set tprob 0
53  ::book::scBookOpen $book $slot
54  set bookmoves [sc_book moves $slot]
55  if {[llength $bookmoves] == 0} {
56  return ""
57  }
58  set r [expr {(int (rand() * 100))}]
59  for {set i 0} {$i<[llength $bookmoves]} {incr i 2} {
60  set m [lindex $bookmoves $i]
61  set prob [string range [lindex $bookmoves [expr $i + 1]] 0 end-1]
62  incr tprob $prob
63  if { $tprob >= $r } {
64  break
65  }
66  }
67  sc_book close $slot
68  return $m
69  }
70 
71  ################################################################################
72  # Show moves leading to book positions
73  ################################################################################
74  proc togglePositionsDisplay {} {
75  global ::book::oppMovesVisible
76  if { $::book::oppMovesVisible == 0} {
77  set ::book::oppMovesVisible 1
78  pack .bookWin.f.text1 -expand yes -fill both
79  } else {
80  set ::book::oppMovesVisible 0
81  pack forget .bookWin.f.text1
82  }
83  }
84 
85  ################################################################################
86  # Open a window to select book and display book moves
87  # arg name : gm2600.bin for example
88  ################################################################################
89  proc open { {name ""} } {
90  global ::book::bookList ::book::bookPath ::book::currentBook ::book::isOpen ::book::lastBook
91 
92  set w .bookWin
93 
94  if {[winfo exists $w]} { return}
95 
96  set ::book::isOpen 1
97 
99  ::setTitle $w $::tr(Book)
100  wm resizable $w 0 1
101 
102  ttk::frame $w.f
103 
104  # load book names
105  if { $name == "" && $lastBook != "" } {
106  set name $lastBook
107  }
108  set bookPath $::scidBooksDir
109  set bookList [ lsort -dictionary [ glob -nocomplain -directory $bookPath *.bin]]
110 
111  # No book found
112  if { [llength $bookList] == 0 } {
113  tk_messageBox -title "Scid" -type ok -icon error -message "No books found. Check books directory"
114  set ::book::isOpen 0
115  set ::book::currentBook ""
117  return
118  }
119 
120  set i 0
121  set idx 0
122  set tmp {}
123  foreach file $bookList {
124  set f [ file tail $file]
125  lappend tmp $f
126  if {$name == $f} {
127  set idx $i
128  }
129  incr i
130  }
131  ttk::combobox $w.f.combo -width 12 -values $tmp
132 
133  catch { $w.f.combo current $idx}
134  pack $w.f.combo
135 
136  # text displaying book moves
137  ttk::frame $w.f.fscroll
138  autoscrollframe -bars y $w.f.fscroll text $w.f.text -wrap word -state disabled -width 12
139 
140  ttk::button $w.f.b -text $::tr(OtherBookMoves) -command { ::book::togglePositionsDisplay }
141  ::utils::tooltip::Set $w.f.b $::tr(OtherBookMovesTooltip)
142 
143  text $w.f.text1 -wrap word -state disabled -width 12
144 
145  pack $w.f.fscroll -expand yes -fill both
146  pack $w.f.b
147  pack $w.f.text1 -expand yes -fill both
148 
149  pack $w.f -expand 1 -fill both
150 
151  bind $w.f.combo <<ComboboxSelected>> ::book::bookSelect
152  bind $w <Destroy> "::book::closeMainBook"
153  # we make a redundant check here, another one is done a few line above
154  if { [catch {bookSelect}] } {
155  tk_messageBox -title "Scid" -type ok -icon error -message "No books found. Check books directory"
156  set ::book::isOpen 0
157  set ::book::currentBook ""
158  ::win::closeWindow .bookWin
159  }
160  }
161  ################################################################################
162  #
163  ################################################################################
164  proc closeMainBook {} {
165  if { $::book::currentBook == "" } { return}
166  focus .
167  sc_book close $::book::bookSlot
168  set ::book::isOpen 0
169  set ::book::currentBook ""
170  }
171  ################################################################################
172  # updates book display when board changes
173  ################################################################################
174  proc refresh {} {
175  global ::book::bookMoves
176 
177  foreach t [.bookWin.f.text tag names] {
178  if { [string match "bookMove*" $t] } {
179  .bookWin.f.text tag delete $t
180  }
181  }
182  foreach t [.bookWin.f.text1 tag names] {
183  if { [string match "bookMove*" $t] } {
184  .bookWin.f.text1 tag delete $t
185  }
186  }
187  set bookMoves [sc_book moves $::book::bookSlot]
188  .bookWin.f.text configure -state normal
189  .bookWin.f.text delete 1.0 end
190  for {set i 0} {$i<[llength $bookMoves]} {incr i 2} {
191  set line [expr $i /2 +1]
192  set m ""
193  append m [::trans [lindex $bookMoves $i]] "\t" [lindex $bookMoves [expr $i + 1]] "\n"
194  .bookWin.f.text insert end $m
195  .bookWin.f.text tag add bookMove$line $line.0 $line.end
196  .bookWin.f.text tag bind bookMove$line <ButtonPress-1> "::book::makeBookMove [lindex $bookMoves $i]"
197  }
198  .bookWin.f.text configure -state disabled -height [expr [llength $bookMoves] / 2]
199 
200 
201  set oppBookMoves [sc_book positions $::book::bookSlot]
202  .bookWin.f.text1 configure -state normal
203  .bookWin.f.text1 delete 1.0 end
204  for {set i 0} {$i<[llength $oppBookMoves]} {incr i 1} {
205  set line [expr $i +1]
206  set m ""
207  append m [::trans [lindex $oppBookMoves $i]] "\n"
208  .bookWin.f.text1 insert end $m
209  .bookWin.f.text1 tag add bookMove$line $line.0 $line.end
210  .bookWin.f.text1 tag bind bookMove$line <ButtonPress-1> "::book::makeBookMove [lindex $oppBookMoves $i]"
211  }
212  .bookWin.f.text1 configure -state disabled -height [llength $oppBookMoves]
213  if { $::book::oppMovesVisible == 0 } {
214  pack forget .bookWin.f.text1
215  }
216  }
217  ################################################################################
218  #
219  ################################################################################
220  proc makeBookMove { move } {
221  addSanMove $move
222  }
223  ################################################################################
224  #
225  ################################################################################
226  proc bookSelect { { n "" } { v 0} } {
227  set ::book::lastBook [.bookWin.f.combo get]
228  scBookOpen [.bookWin.f.combo get] $::book::bookSlot
229  refresh
230  }
231  ################################################################################
232  #
233  ################################################################################
234  proc tuning { {name ""} } {
235  global ::book::bookList ::book::bookPath ::book::currentBook ::book::isOpen
236 
237  set w .bookTuningWin
238 
239  if {[winfo exists $w]} {
240  return
241  }
242 
244  ::setTitle $w $::tr(Book)
245  # wm resizable $w 0 0
246 
247  bind $w <F1> { helpWindow BookTuningWindow }
248  setWinLocation $w
249 
250  ttk::frame $w.fcombo
251  ttk::frame $w.f
252  # load book names
253  set bookPath $::scidBooksDir
254  set bookList [ lsort -dictionary [ glob -nocomplain -directory $bookPath *.bin]]
255 
256  # No book found
257  if { [llength $bookList] == 0 } {
258  tk_messageBox -title "Scid" -type ok -icon error -message "No books found. Check books directory"
259  set ::book::isOpen 0
260  set ::book::currentBook ""
262  return
263  }
264 
265  set i 0
266  set idx 0
267  set tmp {}
268  foreach file $bookList {
269  set f [ file tail $file]
270  lappend tmp $f
271  if {$name == $f} {
272  set idx $i
273  }
274  incr i
275  }
276 
277  ttk::combobox $w.fcombo.combo -width 12 -values $tmp
278  catch { $w.fcombo.combo current $idx}
279  pack $w.fcombo.combo -expand yes -fill x
280 
281  ttk::frame $w.fbutton
282 
283 
284  ttk::menubutton $w.fbutton.mbAdd -text $::tr(AddMove) -menu $w.fbutton.mbAdd.otherMoves
285  menu $w.fbutton.mbAdd.otherMoves
286 
287 
288  ttk::button $w.fbutton.bExport -text $::tr(Export) -command ::book::export
289  ttk::button $w.fbutton.bSave -text $::tr(Save) -command ::book::save
290 
291  pack $w.fbutton.mbAdd $w.fbutton.bExport $w.fbutton.bSave -side top -fill x -expand yes
292 
293 
294  pack $w.fcombo $w.f $w.fbutton -side top
295 
296  bind $w.fcombo.combo <<ComboboxSelected>> ::book::bookTuningSelect
297 
298  bind $w <Destroy> "if {\[string equal $w %W\]} { ::book::closeTuningBook }"
299  bind $w <F1> { helpWindow BookTuning }
300 
302 
303  }
304  ################################################################################
305  #
306  ################################################################################
307  proc closeTuningBook {} {
308  if { $::book::currentTuningBook == "" } { return}
309  focus .
310  sc_book close $::book::bookTuningSlot
311  set ::book::currentTuningBook ""
312  }
313  ################################################################################
314  #
315  ################################################################################
316  proc bookTuningSelect { { n "" } { v 0} } {
317  set w .bookTuningWin
318  scBookOpen [.bookTuningWin.fcombo.combo get] $::book::bookTuningSlot
319  if { $::book::isReadonly > 0 } {
320  $w.fbutton.bSave configure -state disabled
321  } else {
322  $w.fbutton.bSave configure -state normal
323  }
325  }
326  ################################################################################
327  # add a move to displayed bookmoves
328  ################################################################################
329  proc addBookMove { move } {
330  global ::book::bookTuningMoves
331 
332  if { $::book::isReadonly > 0 } { return}
333 
334  set w .bookTuningWin
335  set children [winfo children $w.f]
336  set count [expr [llength $children] / 2]
337  ttk::label $w.f.m$count -text [::trans $move]
338  bind $w.f.m$count <ButtonPress-1> " ::book::makeBookMove $move"
339  ttk::spinbox $w.f.sp$count -from 0 -to 100 -width 3
340  $w.f.sp$count set 0
341  grid $w.f.m$count -row $count -column 0 -sticky w
342  grid $w.f.sp$count -row $count -column 1 -sticky w
343  $w.fbutton.mbAdd.otherMoves delete [::trans $move]
344  lappend ::book::bookTuningMoves $move
345  }
346  ################################################################################
347  # updates book display when board changes
348  ################################################################################
349  proc refreshTuning {} {
350 
351  if { $::book::isReadonly > 0 } { return}
352 
353  #unfortunately we need this as the moves on the widgets are translated
354  #and widgets have no clientdata in tcl/tk
355  global ::book::bookTuningMoves
356  set ::book::bookTuningMoves {}
357  set moves [sc_book moves $::book::bookTuningSlot]
358 
359  set w .bookTuningWin
360  # erase previous children
361  set children [winfo children $w.f]
362  foreach c $children {
363  destroy $c
364  }
365 
366  set row 0
367  for {set i 0} {$i<[llength $moves]} {incr i 2} {
368  lappend ::book::bookTuningMoves [lindex $moves $i]
369  ttk::label $w.f.m$row -text [::trans [lindex $moves $i]]
370  bind $w.f.m$row <ButtonPress-1> " ::book::makeBookMove [lindex $moves $i] "
371  ttk::spinbox $w.f.sp$row -from 0 -to 100 -width 3
372  set pct [lindex $moves [expr $i+1]]
373  set value [string replace $pct end end ""]
374  $w.f.sp$row set $value
375  grid $w.f.m$row -row $row -column 0 -sticky w
376  grid $w.f.sp$row -row $row -column 1 -sticky w
377  incr row
378  }
379  # load legal moves
380  $w.fbutton.mbAdd.otherMoves delete 0 end
381  $w.fbutton.mbAdd.otherMoves add command -label $::tr(None)
382  set moveList [ sc_pos moves]
383  foreach move $moveList {
384  if { [ lsearch $moves $move] == -1 } {
385  $w.fbutton.mbAdd.otherMoves add command -label [::trans $move] -command "::book::addBookMove $move"
386  }
387  }
388  }
389  ################################################################################
390  # sends to book the list of moves and probabilities.
391  ################################################################################
392  proc save {} {
393  global ::book::bookTuningMoves
394  if { $::book::isReadonly > 0 } { return}
395 
396  set prob {}
397  set w .bookTuningWin
398  set children [winfo children $w.f]
399  set count [expr [llength $children] / 2]
400  for {set row 0} {$row < $count} {incr row} {
401  lappend prob [$w.f.sp$row get]
402  }
403  set tempfile [file join $::scidUserDir tempfile.[pid]]
404  sc_book movesupdate $::book::bookTuningMoves $prob $::book::bookTuningSlot $tempfile
405  file delete $tempfile
406  if { [ winfo exists .bookWin] } {
408  }
409  }
410  ################################################################################
411  #
412  ################################################################################
413  proc export {} {
416  progressWindow "Scid" "ExportingBook..." $::tr(Cancel) "::book::sc_progressBar"
417  set ::book::cancelBookExport 0
418  set ::book::exportCount 0
420  set ::book::hashList ""
422  if { $::book::exportCount >= $::book::exportMax } {
423  tk_messageBox -title "Scid" -type ok -icon info \
424  -message "$::tr(Movesloaded) $::book::exportCount\n$::tr(BookPartiallyLoaded)"
425  } else {
426  tk_messageBox -title "Scid" -type ok -icon info -message "$::tr(Movesloaded) $::book::exportCount"
427  }
428  updateBoard -pgn
429  }
430 
431  ################################################################################
432  #
433  ################################################################################
434  proc book2pgn { } {
435  global ::book::hashList
436 
437  if {$::book::cancelBookExport} { return}
438  if { $::book::exportCount >= $::book::exportMax } {
439  return
440  }
441  set hash [sc_pos hash]
442  if {[lsearch -sorted -integer -exact $hashList $hash] != -1} {
443  return
444  } else {
445  lappend hashList $hash
446  set hashList [lsort -integer -unique $hashList]
447  }
448 
449  updateBoard -pgn
450 
451  set bookMoves [sc_book moves $::book::bookTuningSlot]
452  incr ::book::exportCount
453  if {[expr $::book::exportCount % 50] == 0} {
454  updateProgressWindow $::book::exportCount $::book::exportMax
455  update
456  }
457  if {[llength $bookMoves] == 0} { return}
458 
459  for {set i 0} {$i<[llength $bookMoves]} {incr i 2} {
460  set move [lindex $bookMoves $i]
461  if {$i == 0} {
462  sc_move addSan $move
463  book2pgn
464  sc_move back
465  } else {
466  sc_var create
467  sc_move addSan $move
468  book2pgn
469  sc_var exit
470  }
471  }
472 
473  }
474  ################################################################################
475  # cancel book export
476  ################################################################################
477  proc sc_progressBar {} {
478  set ::book::cancelBookExport 1
479  }
480 }
481 ###
482 ### End of file: book.tcl
483 ###