TK / TCL,无法理解这个tic tac toe代码段

时间:2015-04-27 04:32:56

标签: tcl tk

任何人都可以帮我解释一下下面的代码片段。此代码段取自http://wiki.tcl.tk/12374。它旨在创造一个tic tac toe游戏。没有太多资源可以理解Tk / Tcl,所以这给我带来了很大的困难。

proc DrawBoard {{redraw 0}} { 
    global S B GAME C 

    if {$redraw} {                              ;# Must redraw everything
        .c delete all
        set w2 [expr {$B(w2) - 15}]             ;# Make a little margins
        set h2 [expr {$B(h2) - 15}]
        set hbar [expr {$h2 / 3.0}]   
        set vbar [expr {$w2 / 3.0}]

        set B(0) [list -$w2   -$h2   -$vbar -$hbar] ;# All 9 cells
        set B(1) [list -$vbar -$h2    $vbar -$hbar]
        set B(2) [list  $vbar -$h2    $w2   -$hbar]
        set B(3) [list -$w2   -$hbar -$vbar  $hbar]
        set B(4) [list -$vbar -$hbar  $vbar  $hbar]
        set B(5) [list  $vbar -$hbar  $w2    $hbar]
        set B(6) [list -$w2    $hbar -$vbar  $h2]
        set B(7) [list -$vbar  $hbar  $vbar  $h2]
        set B(8) [list  $vbar  $hbar  $w2    $h2]

        for {set i 0} {$i < 9} {incr i} {       ;# Rectangle for each cell
            .c create rect $B($i) -tag b$i -fill {} -outline {}
            .c bind b$i <Button-1> [list DoClick $i]
            set B($i) [ShrinkBox $B($i) 25]
        }
        .c create line -$w2 $hbar $w2 $hbar -tag bar ;# Draw the cross bars
        .c create line -$w2 -$hbar $w2 -$hbar -tag bar
        .c create line $vbar -$h2 $vbar $h2 -tag bar
        .c create line -$vbar -$h2 -$vbar $h2 -tag bar
        .c itemconfig bar -width 20 -fill $::C(bars) -capstyle round
    }
    .new config -state [expr {$GAME(tcnt) == 0 ? "disabled" : "normal"}]

    for {set i 0} {$i < 9} {incr i} {
        .c itemconfig b$i -fill {}              ;# Erase any win lines
        DrawXO $GAME(board,$i) $i
    }
    foreach i $GAME(win) {                      ;# Do we have a winner???
        .c itemconfig b$i -fill $C(win)
    }
}

好的,我关注的w2, h2, hbar, vbar变量是最重要的问题。特别是他们如何宣布。例如,set w2 [expr {$B(w2) - 15}]w2如何定义自己?作者使用这些变量来绘制tic tac toe线,但我甚至不知道这些变量是什么意思。这些变量是否指定了画布的某些维度,以便作者可以使用它来绑定特定区域以单击活动?

如果我理解这四个变量,其他一切都有意义!

以下是电路板的图像: enter image description here

1 个答案:

答案 0 :(得分:3)

Tcl中的变量(Tk只是一个生成在Tcl之上的窗口绘图工具包)在写入时被定义;通常没有明确的声明。唯一的例外是直接在命名空间中使用变量,最好在第一次使用之前使用variable命令声明它们,如下所示:

namespace eval exampleNamespace {
    variable xmpl1 "abc def"

    # Or equivalently...

    variable xmpl2
    set xmpl2 "abc def"

    # You have to use the second style with arrays...

    variable arrayXmpl
    set arrayXmpl(1) "pqr stu"
    set arrayXmpl(2) "qwerty uiop"
}

过程中的局部变量不需要声明,但是如果要访问非本地变量,则必须使用命令(通常为global或{{1将它带入范围。

upvar

proc variableExample {formalArgument1 formalArgument2} { set localVar1 "abc" set localVar2 "def" global thisOtherVar append thisOtherVar "ghi" $formalArgument1 puts "Currently, got $localVar1 $localVar2 and '$thisOtherVar'" } 放在程序的顶部是很常见的,但这完全没有必要。它的效果会持续到您执行此操作的位置,直到过程调用结束。 Tcl的语义严格可操作,具有非常严格定义的评估顺序(从左到右,始终)。

现在,数组是聚合变量。数组的每个元素本身就是一个变量。它们与普通的简单变量不同,尽管整个数组的名称与简单变量的命名方案相同。你不能在同一范围内有一个简单的global和一个foo(首先没有foo(bar)一个,这会删除变量)。元素中的键是 strings - 幕后实现是一个高性能的哈希表 - 完全不是变量,这意味着unsetB(w2)个变量是完全不同的;他们根本不是一回事。但是,我们可以使用变量(和其他Tcl替换)来计算要用作键的字符串,因此我们可以这样做:

w2

让我们来看看你困惑的例子:

set name "w2"
set B($name) "example of "
append B(w2) "array key handling"
puts "this is an $B($name)"

将其分解成碎片:

set w2 [expr {$B(w2) - 15}]

它将写入变量set w2 […] 。这就是w2命令对两个参数的作用。将要写入的内容是评估另一个命令的结果。我们需要深入了解。

set

将其分解成碎片:

expr {$B(w2) - 15}

这会产生评估大括号中表达式的结果。 强烈建议您在所有表达式周围添加大括号;它更安全,更快。表达是什么? (注意,表达式使用与Tcl其余部分不同的语法。)

expr {…}

好的,这是从数组$B(w2) - 15 的{​​{1}}元素中读取的值(因为15)减去$(数字)。这里的w2 只是一个字符串。其他地方有一个同名的变量是巧合。

就是这样。重新组装,我们看到:

B

w2的内容中的减去15的结果分配给变量set w2 [expr {$B(w2) - 15}] 。它确实是所有。 (数组B(w2)是一个全局数组;请参阅过程顶部的w2。)

行:

B

这些从全局数组global获取画布的 half 高度和宽度,删除15个像素的边距,然后设置 set w2 [expr {$B(w2) - 15}] ;# Make a little margins set h2 [expr {$B(h2) - 15}] set hbar [expr {$h2 / 3.0}] set vbar [expr {$w2 / 3.0}] / {{1}到该值的三分之一,以便绘图的坐标更容易。一旦您意识到画布已将其绘图原点移动(类似于滚动)到其窗口的 center ,它会有所帮助。并且要注意做B实际上有点顽皮,虽然很可爱;它使用字符串连接来否定一个值,当值为正且没有显式符号时可以,但如果它发生了变化则会很脆弱。与做hbar相比,它的速度很慢,但是时间更长;计算的成本与命令的长度并不完全匹配。