天天看點

通過“猜數字”遊戲學習 Tcl

作者:硬核老王
通過“猜數字”遊戲學習 Tcl
探索 Tcl 的基本語言結構,包括使用者輸入、輸出、變量、條件評估、循環和簡單函數。

我的 Tcl 之旅始于最近需要将一個困難的基于 Java 的指令行配置工具自動化。我使用 Ansible 做了一些自動化程式設計,偶爾也會使用

expect

子產品。坦率地說,我發現這個子產品的作用有限,原因包括:難以對相同的提示進行排序,難以捕捉到額外步驟的值,控制邏輯的靈活性有限,等等。有時你可以用

shell

子產品來代替。但有時你會遇到那種特立獨行、過于複雜的指令行程式,似乎無法實作自動化。

就我而言,我正在自動安裝我公司的一個程式。最後的配置步驟隻能通過指令行來完成,通過幾個不規範的、重複的提示和需要捕捉的資料輸出。好在傳統的 Expect 是唯一的答案。要使用 Expect 的基本功能,并不需要對 Tcl 有很深的了解,但你了解的越多,你就能從它那裡得到更多的力量。這是後續文章的話題。現在,我探讨一下 Tcl 的基本語言結構,包括使用者輸入、輸出、變量、條件判斷、循環和簡單函數。

安裝 Tcl

在 Linux 系統上,我使用這個:

# dnf install tcl
# which tclsh
/bin/tclsh
           

在 macOS 上,你可以使用 Homebrew來安裝最新的 Tcl:

$ brew install tcl-tk
$ which tclsh
/usr/local/bin/tclsh
           

在 Tcl 中猜數字

從建立基本的可執行腳本

numgame.tcl

開始:

$ touch numgame.tcl
$ chmod 755 numgame.tcl
           

接着在你的檔案中開始編碼,标題是通常的 #!:

#!/usr/bin/tclsh
           

這裡有一些關于 Tcl 的簡單介紹,以便與本文一起追蹤。

第一點是,Tcl 處理的都是字元串。變量通常被當作字元串處理,但可以自動切換類型和内部表示(這一點你通常無法看到)。函數可以把它們的字元串參數解釋為數字(

expr

),并且隻通過值傳遞。字元串通常使用雙引号或大括号來劃分。雙引号允許變量擴充和轉義序列,而大括号則完全沒有擴充。

第二點是 Tcl 語句可以用分号隔開,但通常不這樣。語句行可以用反斜杠字元來分割,然而,典型的做法是将多行語句放在大括号内,以避免需要這樣做。大括号隻是更簡單,下面的代碼格式也反映了這一點。大括号允許對字元串進行延遲求值。在 Tcl 進行變量替換之前,值被傳遞給函數。

最後,Tcl 使用方括号進行指令替換。方括号之間的任何東西都會被送到 Tcl 解釋器的一個新的遞歸調用中進行求值。這對于在表達式中間調用函數或為函數生成參數是很友善的。

過程

雖然在這個遊戲中沒有必要,但我先舉一個在 Tcl 中定義函數的例子,你可以在以後使用:

proc used_time {start} {
	return [expr [clock seconds] - $start]
}
           

使用

proc

将其設定為一個函數(或過程)定義。接下來是函數的名稱。然後是一個包含參數的清單;在本例中是一個參數

{start}

,然後是函數主體。注意,主體的大括号在這一行開始,它不能在下面一行。該函數傳回一個值。傳回值是一個複合求值(方括号),它從讀取系統時鐘

[clock seconds]

開始,并進行數學運算以減去

$start

參數。

設定、邏輯和完成

你可以在這個遊戲的其餘部分增加更多的細節,進行一些初始設定,對玩家的猜測進行疊代,然後在完成後列印結果:

set num [expr round(rand()*100)]
set starttime [clock seconds]
set guess -1
set count 0

puts "Guess a number between 1 and 100"

while { $guess != $num } {
	incr count
	puts -nonewline "==> "
	flush stdout
	gets stdin guess

	if { $guess  $num } {
		puts "Too large, try again"
	} else {
		puts "That's right!"
	}
}

set used [used_time $starttime]

puts "You guessed value $num after $count tries and $used elapsed seconds"
           

前面的

set

語句建立變量。前兩個求值表達式用于識别 1 到 100 之間的随機數,下一個儲存系統時鐘啟動時間。

puts

gets

指令用于來自玩家的輸出和輸入。我使用的

puts

暗示輸出是标準輸出。

gets

需要定義輸入通道,是以這段代碼指定

stdin

作為使用者的終端輸入源。

puts

省略行末終止符時,需要

flush stdout

指令,因為 Tcl 緩沖了輸出,在需要下一個 I/O 之前可能不會被顯示。

從這裡開始,

while

語句說明了循環控制結構和條件邏輯,需要給玩家回報并最終結束循環。

最後的

set

指令調用我們的函數來計算遊戲的耗時秒數,接着是收集到的統計數字來結束遊戲。

玩吧!

$ ./numgame.tcl
Guess a number between 1 and 100
==> 100
Too large, try again
==> 50
Too large, try again
==> 25
Too large, try again
==> 12
Too large, try again
==> 6
Too large, try again
==> 3
That's right!
You guessed value 3 after 6 tries and 20 elapsed seconds
           

繼續學習

當我開始這個練習時,我懷疑回到 90 年代末的流行語言對我有多大的幫助。一路走來,我發現 Tcl 有幾處讓我非常喜歡的地方,我最喜歡的是方括号内的指令求值。與其他許多過度使用複雜閉包結構的語言相比,它似乎更容易閱讀和使用。我以為它是一種 已消亡的語言,但實際上它仍在蓬勃發展,并在多個平台上得到支援。我學到了一些新的技能,并對這種古老的語言有了新的認識。

在 https://www.tcl-lang.org上檢視官方網站。你可以找到最新的源代碼、二進制發行版、論壇、文檔,以及仍在進行的會議資訊的參考。

via: https://opensource.com/article/23/2/learn-tcl-writing-simple-game

作者:James Farrell選題:lkxed譯者:geekpi校對:wxy

本文由 LCTT原創編譯,Linux中國榮譽推出