【问题标题】:TK/TCL, trouble understanding this tic tac toe code snippetTK/TCL,无法理解这个井字代码片段
【发布时间】:2015-04-27 04:32:55
【问题描述】:

谁能帮我解释一下下面的sn-p是做什么的。此代码 sn-p 取自 http://wiki.tcl.tk/12374。它旨在创建井字游戏。了解 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 怎么能被定义为引用它自己???作者使用这些变量来绘制井字线,但我什至不知道这些变量是什么意思。这些变量是否指定了画布的某个维度,以便作者可以使用它来绑定特定区域以单击活动?

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

这是板的外观图像:

【问题讨论】:

  • w2B(w2) 实际上是不同的变量,就像barfoobarfoo(bar) 是不同的变量。

标签: tcl tk


【解决方案1】:

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"
}

过程中的局部变量不需要 需要声明,但如果你想访问一个非局部变量,你必须使用一个命令(通常是globalupvar)来将其纳入范围。

proc variableExample {formalArgument1 formalArgument2} {
    set localVar1 "abc"
    set localVar2 "def"
    global thisOtherVar
    append thisOtherVar "ghi" $formalArgument1
    puts "Currently, got $localVar1 $localVar2 and '$thisOtherVar'"
}

global 放在程序的顶部是很常规的做法,但这完全没有必要。它的效果从您执行它的地方一直持续到过程调用结束。 Tcl 的语义严格可操作,具有极其严格定义的评估顺序(从左到右,总是)。

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

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}

把它分解成碎片:

expr {…}

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

$B(w2) - 15

好的,这是从数组Bw2 元素中读取的值(由于$)减去15(数字)。这里的w2 只是一个字符串。其他地方有同名变量纯属巧合。

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

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

B(w2)的内容减15的结果赋给变量w2。这就是它所做的全部。 (数组B 是一个全局数组;参见过程顶部的global。)


线条:

    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}]

这些从全局数组 B 中获取画布的 一半 高度和宽度,移除 15 个像素作为边距,然后将 hbar/vbar 设置为该值的三分之一值,以便绘制的坐标更容易。一旦您意识到画布已将其绘图原点移动(类似于滚动)到其窗口的 center,它会有所帮助。请注意,-$hbar 虽然很可爱,但实际上有点调皮;它使用字符串连接来否定一个值,当值是正数并且没有明确的符号时这是可以的,但如果它改变了就会很脆弱。与[expr {-$hbar}] 相比,它的速度很慢,尽管时间更长;计算成本与命令长度不完全匹配。

【讨论】:

    猜你喜欢
    • 2012-10-24
    • 2018-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多