2017-06-29 17 views
1

我写了一个脚本,它将递归调用proc,直到达到解决方案。问题是我的愿望窗口正在变得没有反应,同时。它不打印我为记录添加的puts语句。我知道脚本在计算中很忙,但为什么这些输入不会打印到标准输出?TCL:在长递归计算中避免超时/无响应愿望窗口

如何在如此长的递归过程调用期间保持脚本/希望窗口活着。这里是完整的脚本。

namespace eval chainReactionGlobal { 
    #variable state [list 0 0 0 0 0 0 0 0 0] 
    variable pos  [list 0 1 2 3 4 5 6 7 8] 
    variable posMax [list 1 2 1 2 3 2 1 2 1] 
    variable burstPos [list {1 3} {0 2 4} {1 5} {0 4 6} {1 3 5 7} {2 4 8} {3 7} {4 6 8} {5 7}] 
    variable players [list A B C] 
    variable boxLen 3 
    variable boxWidth 3 
} 

proc ShowGraphicalState {state} { 
    set length $chainReactionGlobal::boxLen 
    set width $chainReactionGlobal::boxWidth 
    puts "\n" 
    puts "--------------------" 
    puts -nonewline "\| [lindex $state 0][string repeat " " [expr 4-[string length [lindex $state 0]]]]\|" 
    puts -nonewline "\| [lindex $state 1][string repeat " " [expr 4-[string length [lindex $state 1]]]]\|" 
    puts -nonewline "\| [lindex $state 2][string repeat " " [expr 4-[string length [lindex $state 2]]]]\|" 
    puts "\n--------------------" 
    puts -nonewline "\| [lindex $state 3][string repeat " " [expr 4-[string length [lindex $state 3]]]]\|" 
    puts -nonewline "\| [lindex $state 4][string repeat " " [expr 4-[string length [lindex $state 4]]]]\|" 
    puts -nonewline "\| [lindex $state 5][string repeat " " [expr 4-[string length [lindex $state 5]]]]\|" 
    puts "\n--------------------" 
    puts -nonewline "\| [lindex $state 6][string repeat " " [expr 4-[string length [lindex $state 6]]]]\|" 
    puts -nonewline "\| [lindex $state 7][string repeat " " [expr 4-[string length [lindex $state 7]]]]\|" 
    puts -nonewline "\| [lindex $state 8][string repeat " " [expr 4-[string length [lindex $state 8]]]]\|" 
    puts "\n--------------------" 
} 

proc GetNextPlayer {currentPlayer} { 
    set currIdx [lsearch $chainReactionGlobal::players $currentPlayer] 
    if {[expr $currIdx+1]<[llength $chainReactionGlobal::players ]} { 
     return [lindex $chainReactionGlobal::players [expr $currIdx+1]] 
    } else { 
     return [lindex $chainReactionGlobal::players 0] 
    }  
} 

# ------------------------------------------------------------------------ 
# This function will take input of a stable state and current player, will 
# return list of possible unstable state the current player can make. 
# ------------------------------------------------------------------------ 
proc GetPossibleStateMatrix {stableState currentPlayer} { 
    array set stateList {} 

    foreach position $chainReactionGlobal::pos { 

     set localState $stableState 
     set currentPosValue [lindex $localState $position] 
     if {$currentPosValue=="0"} { 
      lset localState $position [string repeat $currentPlayer 1] 
     set stateList($position) $localState 
     } elseif {[regexp -all $currentPlayer $currentPosValue]>0} { 
      lset localState $position $currentPosValue$currentPlayer 
      set stateList($position) $localState 
     } 


    } 

    return [array get stateList] 
} 



proc GetStabilizedState {unstableState impactPosList} { 
    set isStable 0 
    set affectedPosList {} 
    while {!$isStable} { 
     foreach position $impactPosList { 
      set posValue [lindex $unstableState $position] 
      if { $posValue=="0"} { 
        set posLength 0 
      } else { 
       set posLength [string length $posValue] 
      } 
      set posMaxLength [lindex $chainReactionGlobal::posMax $position] 

      if {($posLength>$posMaxLength)} { 
       if {[expr $posLength-$posMaxLength-1] > 0} { 
        lset unstableState $position [string repeat [string range $posValue 0 0] [expr [expr $posLength-$posMaxLength]-1]] 
       } else { 
        lset unstableState $position "0" 
       } 

       foreach affectedPos [lindex $chainReactionGlobal::burstPos $position] { 
        set affectedPosValue [lindex $unstableState $affectedPos] 
        if { $affectedPosValue =="0"} { 
         set affectedPosValueLength 0 
        } else { 
         set affectedPosValueLength [string length $affectedPosValue] 
        } 
        set affectedPosMaxLength [lindex $chainReactionGlobal::posMax $affectedPos] 

        if {[expr $affectedPosValueLength+1]>$affectedPosMaxLength } { 
         if {[lsearch $affectedPosList $affectedPos ] ==-1} { 
          lappend affectedPosList $affectedPos 
         } 
        } 
        lset unstableState $affectedPos [string repeat [string range $posValue 0 0] [expr 1+$affectedPosValueLength]]  
       } 
      } 
     } 

     set isStable 1 
     foreach position $chainReactionGlobal::pos { 
      set posValue [lindex $unstableState $position] 
     if { $posValue=="0"} { 
       set posLength 0 
     } else { 
      set posLength [string length $posValue] 
     } 
     set posMaxLength [lindex $chainReactionGlobal::posMax $position] 
      if {($posLength>$posMaxLength) && ($posValue!="0")} { 
       set isStable 0 
      } 
     } 

     if {$isStable==1} { 
      return $unstableState 
     } 
     set impactPosList $affectedPosList 
    } 

} 


proc IsImmediateWin {state currentPlayer} { 
    foreach elem $state { 
     if {$elem==0} { 
      continue 
     } elseif {[regexp $currentPlayer $elem]} { 
      continue 
     } else { 
      return 0 
     } 
    } 
    return 1 
} 

    proc GetWinRatio {state myPlayer currentPlayer {test 0}} { 

     puts "test $test state $state myPlayer $myPlayer currentPlayer $currentPlayer" 

     set loss 0 
     set win 0 
     set possibleStateList [GetPossibleStateMatrix $state $currentPlayer] 
     array set possibleStateArr $possibleStateList 
     # puts possibleStateList$possibleStateList 
     foreach possiblePos [lsort [array names possibleStateArr]] { 
      set possibleState $possibleStateArr($possiblePos) 
      puts "possibleState ----> $possibleState       possiblePos $possiblePos" 
      set stableState [GetStabilizedState $possibleState $possiblePos] 
      puts "stableState ----> $stableState" 


      if {[IsImmediateWin $stableState $currentPlayer]} { 
       if {$currentPlayer==$myPlayer } { 
        incr win 
       } else { 
        incr loss 
       } 
      } else { 
      puts "not immediate win" 

       set result [GetWinRatio $stableState $myPlayer [GetNextPlayer $currentPlayer] [expr $test+1] ] 
       # set result "0:0" 
       set winRes [lindex [split $result ":"] 0] 
       set lossRes [lindex [split $result ":"] 1] 

       incr win $winRes 
       incr loss $lossRes 
      } 
      # puts "state [ShowGraphicalState $stableState] wins:$win loss:$loss" 

     } 
     return ${win}:${loss} 
    } 
    puts "[GetWinRatio [list A CC A A B B A B C] A A]"  
+0

你在哪个平台上运行这个平台? –

+0

我在运行Windows 7的Wish86.exe中运行脚本。 –

回答

1

您使用的愿望,那就是为什么你需要一个Tk命令updateupdate idletasks。在控制台中使用tclsh时,不需要此命令。

由于功能GetPossibleStateMatrix不存在,我无法测试您的代码。 这样所以,我测试代码:

for {set i 0} {$i < 10000} {incr i} {puts $i} 

是的,没有输出,直到执行结束。所以,我已经添加update命令:

for {set i 0} {$i < 10000} {incr i} {puts $i; update} 

现在我可以看到在执行过程中的输出。

试试你的第一puts后添加update命令:

proc GetWinRatio {state myPlayer currentPlayer {test 0}} { 

    puts "test $test state $state myPlayer $myPlayer currentPlayer $currentPlayer" 
    update 
    . . . 
+0

我添加了完整的代码。请看看 –

+1

@Codename_DJ我在每个'puts'后面添加'update'命令并运行你的代码。它很快就表明: 试验3状态A CC 0 AA CCC C A CCÇmyPlayer甲currentPlayer甲 possibleState ----> AA CC 0 AA CCC C A CCÇpossiblePos ,之后采空响应。看起来像'GetStabilizedState'函数中的问题。 –

+0

我一直在看这个错误的地方:)。感谢有关更新的提示。 –

1

在Windows控制台Tk的实际上是在主线程单独解释上下文中运行。它有自己的Tk窗口层次结构,但与Tcl代码共享主事件循环。不幸的是,这意味着如果您让主解释器中运行的Tcl代码非常繁忙(例如,通过执行大量处理),则停止在控制台中处理显示更新。文本出现在窗口模型中,但实际显示更新所处理的代码位于空闲事件中计划的回调中。

修复方法是将updateupdate idletasks放在主处理循环内某处。后者足以处理来自puts调用的显示更新,但前者允许您与窗口交互(例如,滚动它)。不利的一面是你可以在你的主窗口中处理其他事件,并且你或者需要小心地作为用户或者更新你的GUI,以便在长时间处理过程中将人员锁定。有很多不同的方法可以做到这一点,但如果只是为了您自己的用途,“小心”的方法很好。