9 namespace eval sergame {
12 set ::uci::uciInfo(log_stdout3) 0
15 set openingMovesList {}
16 set openingMovesHash {}
19 array set engineListBox {}
26 set lastPlayerMoveUci ""
32 global ::sergame::configWin ::sergame::chosenOpening
34 set w ".configSerGameWin"
35 if {[
winfo exists $w]} {
41 wm title $w "$::tr(configuregame)"
43 bind $w <F1> { helpWindow SeriousGame }
46 ttk::frame $w.fconfig -padding 10
47 ttk::frame $w.fbuttons
48 ttk::labelframe $w.fengines -text $::tr(Engine)
49 ttk::labelframe $w.ftime -text $::tr(TimeMode)
50 ttk::labelframe $w.fopening -text $::tr(Opening)
52 grid $w.fengines -row 0 -column 0 -pady { 0 10 } -sticky we -padx { 0 10 }
53 grid $w.fopening -row 0 -column 1 -pady { 0 10 } -sticky nswe -padx { 10 0 }
54 grid $w.ftime -row 1 -column 0 -pady { 10 0 } -sticky nswe -padx { 0 10 }
55 grid $w.fconfig -row 1 -column 1 -pady { 10 0 } -sticky we -padx { 10 0 }
56 grid $w.fbuttons -row 2 -column 1 -sticky we
59 ttk::frame $w.fengines.fEnginesList
60 listbox $w.fengines.fEnginesList.lbEngines -yscrollcommand "$w.fengines.fEnginesList.ybar set" \
61 -height 5 -width 20 -exportselection 0
62 ttk::scrollbar $w.fengines.fEnginesList.ybar -command "$w.fengines.fEnginesList.lbEngines yview"
63 pack $w.fengines.fEnginesList.ybar -side right -fill y
64 pack $w.fengines.fEnginesList.lbEngines -side left -fill x -expand 1
65 pack $w.fengines.fEnginesList -expand yes -fill x -side top
68 foreach e $::engines(list) {
69 if { [
lindex $e 7] != 1} {
incr idx continue}
70 set ::sergame::engineListBox($i) $idx
71 set name [
lindex $e 0]
72 $w.fengines.fEnginesList.lbEngines insert end $name
78 ttk::button $w.fengines.bEngineConfig -text $::tr(ConfigureUCIengine) -command {
79 set sel [.configSerGameWin.fengines.fEnginesList.lbEngines curselection]
80 set index $::sergame::engineListBox($sel)
81 set engineData [lindex $::engines(list) $index]
82 set name [lindex $engineData 0]
83 set cmd [ toAbsPath [lindex $engineData 1] ]
84 set args [lindex $engineData 2]
85 set dir [ toAbsPath [lindex $engineData 3] ]
86 set options [lindex $engineData 8]
87 set ::uci::autoSaveOptionsIndex $index
88 set ::uci::autoSaveOptions 1
89 ::uci::uciConfig 3 [ toAbsPath $cmd ] $args [ toAbsPath $dir ] $options
91 pack $w.fengines.bEngineConfig -side top -pady 5 -anchor e -padx 4
95 tk_messageBox -type ok -message "No UCI engine defined" -icon error
100 $w.fengines.fEnginesList.lbEngines selection set $::sergame::chosenEngine
101 $w.fengines.fEnginesList.lbEngines see $::sergame::chosenEngine
104 ttk::checkbutton $w.fconfig.cbUseBook -text $::tr(UseBook) -variable ::sergame::useBook
105 set bookPath $::scidBooksDir
106 set bookList [ lsort -dictionary [ glob -nocomplain -directory $bookPath *.bin]]
107 if { [
llength $bookList] == 0 } {
108 $w.fconfig.cbUseBook configure -state disabled
109 set ::sergame::useBook 0
114 foreach file $bookList {
115 lappend tmp [
file tail $file]
116 if { $::sergame::bookToUse == [
file tail $file]} {
122 ttk::combobox $w.fconfig.combo -width 12 -values $tmp
123 catch { ch$w.fconfig.combo current $idx}
128 ttk::frame $w.ftime.timebonus
129 pack $w.ftime.timebonus -side top -fill x
131 ttk::radiobutton $w.ftime.timebonus.rb1 -text $::tr(TimeBonus) -value "timebonus" -variable ::sergame::timeMode
132 grid $w.ftime.timebonus.rb1 -row $row -column 0 -sticky w -rowspan 2
134 ttk::label $w.ftime.timebonus.whitelabel -text $::tr(White)
135 grid $w.ftime.timebonus.whitelabel -row $row -column 1
136 ttk::spinbox $w.ftime.timebonus.whitespminutes -background white -width 2 -from 1 -to 120 -increment 1 -validate all -validatecommand { regexp {^[0-9]+$} %P }
137 grid $w.ftime.timebonus.whitespminutes -row $row -column 2
138 ttk::label $w.ftime.timebonus.whitelminutes -text $::tr(TimeMin)
139 grid $w.ftime.timebonus.whitelminutes -row $row -column 3
140 ttk::spinbox $w.ftime.timebonus.whitespseconds -background white -width 2 -from 0 -to 60 -increment 1 -validate all -validatecommand { regexp {^[0-9]+$} %P }
141 grid $w.ftime.timebonus.whitespseconds -row $row -column 4
142 ttk::label $w.ftime.timebonus.whitelseconds -text $::tr(TimeSec)
143 grid $w.ftime.timebonus.whitelseconds -row $row -column 5
146 ttk::label $w.ftime.timebonus.blacklabel -text $::tr(Black)
147 grid $w.ftime.timebonus.blacklabel -row $row -column 1
148 ttk::spinbox $w.ftime.timebonus.blackspminutes -background white -width 2 -from 1 -to 120 -increment 1 -validate all -validatecommand { regexp {^[0-9]+$} %P }
149 grid $w.ftime.timebonus.blackspminutes -row $row -column 2
150 ttk::label $w.ftime.timebonus.blacklminutes -text $::tr(TimeMin)
151 grid $w.ftime.timebonus.blacklminutes -row $row -column 3
152 ttk::spinbox $w.ftime.timebonus.blackspseconds -background white -width 2 -from 0 -to 60 -increment 1 -validate all -validatecommand { regexp {^[0-9]+$} %P }
153 grid $w.ftime.timebonus.blackspseconds -row $row -column 4
154 ttk::label $w.ftime.timebonus.blacklseconds -text $::tr(TimeSec)
155 grid $w.ftime.timebonus.blacklseconds -row $row -column 5
157 $w.ftime.timebonus.whitespminutes set [
expr $::uci::uciInfo(wtime3) / (60 * 1000)]
158 $w.ftime.timebonus.whitespseconds set [
expr $::uci::uciInfo(winc3) / 1000]
159 $w.ftime.timebonus.blackspminutes set [
expr $::uci::uciInfo(btime3) / (60 * 1000)]
160 $w.ftime.timebonus.blackspseconds set [
expr $::uci::uciInfo(binc3) / 1000]
163 ttk::frame $w.ftime.depth
164 ttk::radiobutton $w.ftime.depth.button -text $::tr(FixedDepth) -value "depth" -variable ::sergame::timeMode -width 16
165 ttk::spinbox $w.ftime.depth.value -background white -width 3 -from 1 -to 20 -increment 1 -validate all -validatecommand { regexp {^[0-9]+$} %P }
166 $w.ftime.depth.value set $::sergame::depth
168 pack $w.ftime.depth -side top -fill x
169 pack $w.ftime.depth.button -side left
170 pack $w.ftime.depth.value -side left
172 ttk::frame $w.ftime.nodes
173 ttk::radiobutton $w.ftime.nodes.button -text "$::tr(Nodes) (x1000)" -value "nodes" -variable ::sergame::timeMode -width 16
174 ttk::spinbox $w.ftime.nodes.value -background white -width 3 -from 5 -to 10000 -increment 5 -validate all -validatecommand { regexp {^[0-9]+$} %P }
175 $w.ftime.nodes.value set [
expr $::sergame::nodes /1000]
177 pack $w.ftime.nodes -side top -fill x
178 pack $w.ftime.nodes.button -side left
179 pack $w.ftime.nodes.value -side left
181 ttk::frame $w.ftime.movetime
182 ttk::radiobutton $w.ftime.movetime.button -text $::tr(SecondsPerMove) -value "movetime" -variable ::sergame::timeMode -width 16
183 ttk::spinbox $w.ftime.movetime.value -background white -width 3 -from 1 -to 120 -increment 1 -validate all -validatecommand { regexp {^[0-9]+$} %P }
184 $w.ftime.movetime.value set [
expr $::sergame::movetime /1000]
186 pack $w.ftime.movetime -side top -fill x
187 pack $w.ftime.movetime.button -side left
188 pack $w.ftime.movetime.value -side left
190 pack $w.fconfig.cbUseBook -side top -anchor w
191 pack $w.fconfig.combo -side top -anchor w -padx 20 -fill x
194 ttk::checkbutton $w.fconfig.cbPosition -text $::tr(StartFromCurrentPosition) -variable ::sergame::startFromCurrent
195 pack $w.fconfig.cbPosition -side top -anchor w
198 ttk::checkbutton $w.fconfig.cbPonder -text $::tr(Ponder) -variable ::sergame::ponder
199 pack $w.fconfig.cbPonder -side top -anchor w
202 ttk::checkbutton $w.fconfig.cbCoach -text $::tr(CoachIsWatching) -variable ::sergame::coachIsWatching
203 pack $w.fconfig.cbCoach -side top -anchor w
205 ttk::checkbutton $w.fconfig.storeEval -text $::tr(AddScoreToShortAnnotations) -variable ::sergame::storeEval
206 pack $w.fconfig.storeEval -side top -anchor w
209 ttk::checkbutton $w.fopening.cbOpening -text $::tr(SpecificOpening) -variable ::sergame::isOpening
210 ttk::frame $w.fopening.fOpeningList
211 listbox $w.fopening.fOpeningList.lbOpening -yscrollcommand "$w.fopening.fOpeningList.ybar set" \
212 -height 5 -width 36 -list ::tacgame::openingList -exportselection 0
213 $w.fopening.fOpeningList.lbOpening selection set $::sergame::chosenOpening
214 $w.fopening.fOpeningList.lbOpening see $::sergame::chosenOpening
216 ttk::scrollbar $w.fopening.fOpeningList.ybar -command "$w.fopening.fOpeningList.lbOpening yview"
217 pack $w.fopening.fOpeningList.ybar -side right -fill y
218 pack $w.fopening.fOpeningList.lbOpening -side left -fill both -expand 1
219 pack $w.fopening.fOpeningList -fill both -side top
220 pack $w.fopening.cbOpening -fill x -side top
222 ttk::button $w.fbuttons.close -text $::tr(Play) -command {
224 set ::sergame::chosenEngine [.configSerGameWin.fengines.fEnginesList.lbEngines curselection]
225 set ::sergame::engineName [.configSerGameWin.fengines.fEnginesList.lbEngines get $::sergame::chosenEngine]
226 set ::sergame::chosenOpening [.configSerGameWin.fopening.fOpeningList.lbOpening curselection]
227 if {$::sergame::useBook} {
228 set ::sergame::bookToUse [.configSerGameWin.fconfig.combo get]
229 if {$::sergame::bookToUse == "" } {
230 set ::sergame::useBook 0
233 set ::uci::uciInfo(wtime3) [expr [.configSerGameWin.ftime.timebonus.whitespminutes get]*1000*60]
234 set ::uci::uciInfo(btime3) [expr [.configSerGameWin.ftime.timebonus.blackspminutes get]*1000*60]
235 set ::uci::uciInfo(winc3) [expr [.configSerGameWin.ftime.timebonus.whitespseconds get]*1000]
236 set ::uci::uciInfo(binc3) [expr [.configSerGameWin.ftime.timebonus.blackspseconds get]*1000]
237 set ::uci::uciInfo(fixeddepth3) [.configSerGameWin.ftime.depth.value get]
238 set ::uci::uciInfo(fixednodes3) [expr [.configSerGameWin.ftime.nodes.value get]*1000]
239 set ::uci::uciInfo(movetime3) [expr [.configSerGameWin.ftime.movetime.value get]*1000]
241 destroy .configSerGameWin
242 ::sergame::play $::sergame::chosenEngine
244 ttk::button $w.fbuttons.cancel -textvar ::tr(Cancel) -command "focus .; destroy $w"
246 packbuttons right $w.fbuttons.cancel $w.fbuttons.close
247 bind $w <Escape> { .configSerGameWin.fbuttons.cancel invoke }
248 bind $w <Return> { .configSerGameWin.fbuttons.close invoke }
249 bind $w <F1> { helpWindow SeriousGame }
251 bind $w <Configure> "recordWinSize $w"
258 proc play { engine {n 3} } {
259 global ::sergame::chosenOpening ::sergame::isOpening ::tacgame::openingList ::sergame::openingMovesList \
260 ::sergame::openingMovesHash ::sergame::openingMoves ::sergame::outOfOpening
262 if {$::sergame::isOpening || !$::sergame::startFromCurrent} {
266 set ::sergame::lFen {}
269 set engineData [
lindex $::engines(list) $::sergame::engineListBox($engine)]
272 set ::uci::uciInfo(prevscore$n) 0.0
273 set ::uci::uciInfo(score$n) 0.0
274 set ::uci::uciInfo(ponder$n) ""
276 if {$::sergame::startFromCurrent} {
281 if {$::sergame::ponder} {
289 set fields [
split [
lindex $openingList $chosenOpening] ":"]
290 set openingName [
lindex $fields 0]
291 set openingMoves [
string trim [
lindex $fields 1]]
292 set openingMovesList ""
293 set openingMovesHash ""
295 foreach m [
split $openingMoves] {
300 set p [
string trim $m]
301 lappend openingMovesList [
string trim [regsub {^[1-9]+\.} $p ""]]
304 lappend openingMovesHash [
sc_pos hash]
305 foreach m $openingMovesList {
306 if {[
catch {
sc_move addSan $m}]} { }
307 lappend openingMovesHash [
sc_pos hash]
313 set ::sergame::playerColor "black"
314 set ::sergame::engineColor "white"
316 set ::sergame::playerColor "white"
317 set ::sergame::engineColor "black"
320 if {!$::sergame::startFromCurrent} {
322 sc_game tags set -event "Serious game"
323 sc_game tags set -$::sergame::playerColor "Player"
324 sc_game tags set -$::sergame::engineColor "$::sergame::engineName"
328 set ::sergame::waitPlayerMove 0
329 set ::sergame::wentOutOfBook 0
330 set ::playMode "::sergame::callback"
339 proc callback {cmd} {
346 proc abortGame { { n 3 } } {
348 after cancel ::sergame::engineGo $n
350 set ::sergame::lFen {}
351 if { $::uci::uciInfo(pipe$n) != ""} {
353 set ::uci::uciInfo(bestmove$n) "abort"
358 proc clocks {cmd {n 3}} {
359 if {$::sergame::timeMode != "timebonus"} {
return}
369 if { [
sc_pos side] == "white" } {
394 proc takeBack {takebackClockW takebackClockB} {
396 if {$takebackClockW != ""} {
407 proc sendToEngine {n text} {
409 catch {
puts $::uci::uciInfo(pipe$n) $text}
415 set move_done [
sc_game info previousMove]
416 if { [
string index [
sc_game info previousMove] end] == "#"} {
425 proc engineGo { n } {
426 global ::sergame::isOpening ::sergame::openingMovesList ::sergame::openingMovesHash ::sergame::openingMoves \
427 ::sergame::timeMode ::sergame::outOfOpening
429 after cancel ::sergame::engineGo $n
433 if { [
sc_pos side] != $::sergame::engineColor } {
434 set ::sergame::waitPlayerMove 1
435 after 1000 ::sergame::engineGo $n
439 set takebackClockW ""
440 set takebackClockB ""
441 if {$::sergame::waitPlayerMove} {
443 set ::sergame::waitPlayerMove 0
444 if {$::sergame::timeMode == "timebonus"} {
453 if {$isOpening && !$outOfOpening} {
456 if { !$outOfOpening } {
457 set ply [
expr [
sc_pos moveNumber] * 2 - 1]
458 if { [
sc_pos side] == "white" } {
459 set ply [
expr $ply - 1]
462 if { [lsearch $openingMovesHash [
sc_pos hash]] == -1 && [
llength $openingMovesList] >= $ply} {
464 set answer [
tk_messageBox -icon question -parent .main -title $::tr(OutOfOpening) -type yesno \
465 -message "$::tr(NotFollowedLine) $openingMoves\n $::tr(DoYouWantContinue)"]
467 takeBack $takebackClockW $takebackClockB
468 after 1000 ::sergame::engineGo $n
479 set length [
llength $openingMovesHash]
480 for {
set i 0} { $i < [
expr $length-1] } {
incr i} {
481 set h [
lindex $openingMovesHash $i]
483 set index [lsearch $openingMovesHash $h]
484 set move [
lindex $openingMovesList $index]
488 if {$action == "replace"} {
489 if {[
catch {
sc_move addSan $move}]} {}
490 }
elseif {$action == "var"} {
492 if {[
catch {
sc_move addSan $move}]} {}
493 }
elseif {$action == "mainline"} {
495 if {[
catch {
sc_move addSan $move}]} {}
503 after 1000 ::sergame::engineGo $n
510 if {$::sergame::useBook && ! $::sergame::wentOutOfBook} {
513 set ::sergame::wentOutOfBook 1
518 set ::uci::uciInfo(prevscore$n) 0.0
522 after 1000 ::sergame::engineGo $n
529 if { $::sergame::ponder && $::uci::uciInfo(ponder$n) == $::sergame::lastPlayerMoveUci} {
533 if { $::sergame::ponder } {
536 set ::analysis(waitForReadyOk$n) 1
538 vwait ::analysis(waitForReadyOk$n)
542 if {$timeMode == "timebonus"} {
543 ::sergame::sendToEngine $n "go wtime $wtime btime $btime winc $::uci::uciInfo(winc$n) binc $::uci::uciInfo(binc$n)"
544 }
elseif {$timeMode == "depth"} {
546 }
elseif {$timeMode == "movetime"} {
548 }
elseif {$timeMode == "nodes"} {
553 set ::uci::uciInfo(bestmove$n) ""
554 vwait ::uci::uciInfo(bestmove$n)
558 if { $::sergame::coachIsWatching && $::uci::uciInfo(prevscore$n) != "" } {
560 set delta [
expr $::uci::uciInfo(score$n) - $::uci::uciInfo(prevscore$n)]
561 if {$delta > $::informant("?!") && $::sergame::engineColor == "white" ||
562 $delta < [
expr 0.0 - $::informant("?!")] && $::sergame::engineColor == "black" } {
566 if {$delta > $::informant("?") && $::sergame::engineColor == "white" ||
567 $delta < [
expr 0.0 - $::informant("?")] && $::sergame::engineColor == "black" } {
571 if {$delta > $::informant("??") && $::sergame::engineColor == "white" ||
572 $delta < [
expr 0.0 - $::informant("??")] && $::sergame::engineColor == "black" } {
577 set tBlunder "DubiousMovePlayedTakeBack"
578 }
elseif {$blunder == 2} {
579 set tBlunder "WeakMovePlayedTakeBack"
580 }
elseif {$blunder == 3} {
581 set tBlunder "BadMovePlayedTakeBack"
586 set answer [
tk_messageBox -icon question -parent .main -title "Scid" -type yesno -message $::tr($tBlunder)]
587 if {$answer == yes} {
588 takeBack $takebackClockW $takebackClockB
589 after 1000 ::sergame::engineGo $n
597 if { $::uci::uciInfo(bestmove$n) == "abort" } {
603 set ::uci::uciInfo(prevscore$n) $::uci::uciInfo(score$n)
604 if { $::sergame::storeEval == 1 } {
613 if {$::sergame::ponder && $::uci::uciInfo(ponder$n) != ""} {
617 if {$timeMode == "timebonus"} {
618 ::sergame::sendToEngine $n "go ponder wtime $wtime btime $btime winc $::uci::uciInfo(winc$n) binc $::uci::uciInfo(binc$n)"
619 }
elseif {$timeMode == "depth"} {
621 }
elseif {$timeMode == "movetime"} {
623 }
elseif {$timeMode == "nodes"} {
628 after 1000 ::sergame::engineGo $n
635 set elt [
lrange [
split [
sc_pos fen]] 0 2]
637 if { $elt != [
lindex $::sergame::lFen end] } {
638 lappend ::sergame::lFen $elt
641 if { [
llength [lsearch -all $::sergame::lFen $elt]] >=3 } {
642 tk_messageBox -type ok -message $::tr(Draw) -parent .main -icon info
643 puts $::sergame::lFen
651 proc logEngine {n text} {
652 if {$::uci::uciInfo(log_stdout$n)} {
653 puts stdout "$n $text"