以下是一个简单的编程项目，能够帮助你开始学习 Tcl/Tk。探索 Tcl/Tk 的基础构造，包括用户输入、输出、变量、条件评估、简单函数和基础事件驱动编程。我写这篇文章的初衷源于我想更深入地利用基于 Tcl 的 Expect。这让我写下了以下两篇文章：通过编写一个简单的游戏学习 Tcl 和 通过编写一个简单的游戏学习 Expect。我进行了一些 Ansible 自动化工作，逐渐积累了一些本地脚本。有些脚本我频繁使用，以至于以下循环操作变得有些烦人：打开终端使用 cd 命令跳转至合适的目录输入一条带有若干选项的长命令启动所需的自动化流程我日常使用的是 macOS。实际上我更希望有一个菜单项或者一个图标，能够弹出一个简单的界面接受参数并执行我需要的操作，这就像在 Linux 的 KDE 中一样。经典的 Tcl 类书籍都包含了关于流行的 Tk 扩展的文档。既然我已经深入研究了这个主题，我尝试着对其（即 wish）进行编程。虽然我并非一名 GUI 或者前端开发者，但我发现 Tcl/Tk 脚本编写的方式相当直接易懂。我很高兴能重新审视这个 UNIX 历史的古老且稳定的部分，这种技术在现代平台上依然有用且可用。安装 Tcl/Tk对于 Linux 系统，你可以按照下面的方式安装：$ sudo dnf install tcl $ which wish /bin/wish 而在 macOS 上，你可以通过 Homebrew 来安装最新版的 Tcl/Tk：$ brew install tcl-tk $ which wish /usr/local/bin/wish 编程理念许多编写游戏的教程都会介绍到典型的编程语言结构，如循环、条件判断、变量、函数和过程等等。在此篇文章中，我想要介绍的是 事件驱动编程。当你的程序使用事件驱动编程，它会进入一个特殊的内置循环，等待特定的事件发生。当这个特定的事件发生时，相应的代码就会被触发，产生预期的结果。这些事件可以包括键盘输入、鼠标移动、点击按钮、定时器触发，甚至是任何你的电脑硬件能够识别的事件（可能来自特殊的设备）。你的程序中的代码决定了用户看到了什么，以及程序需要监听什么输入，当这些输入被接收后程序会怎么做，然后进入事件循环等待输入。这篇文章的理念并没有脱离我之前的 Tcl 文章太远。这里最大的不同在于用 GUI 设置和用于处理用户输入的事件循环替代了循环结构。其他的不同则是 GUI 开发需要采取的各种方式来制作一个可用的用户界面。在采用 Tk GUI 开发的时候，你需要了解两个基础的概念： 部件 widget 和 几何管理器 geometry manager 。部件是构成可视化元素的 UI 元素，通过这些元素用户可以与程序进行交互。这其中包括了按钮、文本区域、标签和文本输入框。部件还包括了一些选项选择，如菜单、复选框、单选按钮等。最后，部件也包括了其他的可视化元素，如边框和线性分隔符。几何管理器在放置部件在显示窗口中的位置上扮演着至关重要的角色。有一些不同的几何管理器可以供你使用。在这篇文章中，我主要使用了 grid 几何来让部件在整齐的行中进行布局。我会在这篇文章的结尾地方解释一些几何管理器的不同之处。用 wish 进行猜数字游戏这个示例游戏代码与我其他文章中的示例有所不同，我将它分解为若干部分以方便解释。首先创建一个基本的可执行脚本 numgame.wish ：$ touch numgame.wish $ chmod 755 numgame.wish 使用你喜欢的文本编辑器打开此文件，输入下列代码的第一部分：#!/usr/bin/env wish set LOW 1 set HIGH 100 set STATUS "" set GUESS "" set num [expr round(rand()*100)] 第一行定义了该脚本将通过 wish 执行。接下来，创建了几个全局变量。这里我使用全部大写字母定义全局变量，这些变量将绑定到跟踪这些值的窗口小部件（LOW、HIGH等等）。全局变量 num 是游戏玩家要猜测的随机数值，这个值是通过 Tcl 的命令执行得到并保存到变量中的：proc Validate {var} { if { [string is integer $var] } { return 1 } return 0 } 这是一个验证用户输入的特殊函数，它只接受整数并拒绝其他所有类型的输入：proc check_guess {guess num} { global STATUS LOW HIGH GUESS if { $guess < $LOW } { set STATUS "What?" } elseif { $guess > $HIGH } { set STATUS "Huh?" } elseif { $guess < $num } { set STATUS "Too low!" set LOW $guess } elseif { $guess > $num } { set STATUS "Too high!" set HIGH $guess } else { set LOW $guess set HIGH $guess set STATUS "That's Right!" destroy .guess .entry bind all <Return> {.quit invoke} } set GUESS "" } 这是主要的猜数逻辑循环。global 语句让我们能够修改在文件开头创建的全局变量（关于此主题后面将会有更多解释）。这个条件判断寻找入力范围在 1 至 100 之外以及已经被用户猜过的值。有效的猜测和随机值进行比较。LOW 和 HIGH 的猜测会被追踪，作为 UI 中的全局变量进行报告。在每一步，全局 STATUS 变量都会被更新，这个状态信息会自动在 UI 中显示。对于正确的猜测，destroy 语句会移除 “Guess” 按钮以及输入窗口，并重新绑定回车键，以激活 “Quit” 按钮。最后的语句 set GUESS "" 用于在下一个猜测之前清空输入窗口。label .inst -text "Enter a number between: " label .low -textvariable LOW label .dash -text "-" label .high -textvariable HIGH label .status -text "Status:" label .result -textvariable STATUS button .guess -text "Guess" -command { check_guess $GUESS $num } entry .entry -width 3 -relief sunken -bd 2 -textvariable GUESS -validate all \ -validatecommand { Validate %P } focus .entry button .quit -text "Quit" -command { exit } bind all <Return> {.guess invoke} 这是设置用户界面的部分。前六个标签语句在你的 UI 上创建了不同的文本展示元素，-textvariable 选项监控给定的变量，并自动更新标签的值，这展示了全局变量 LOW、HIGH、STATUS 的绑定。button 行创建了 “Guess” 和 “Quit” 按钮， -command 选项设定了当按钮被按下时要执行的操作。按下 “Guess” 按钮执行了上面的 check_guess 函数以检查用户输入的值。entry 部件更有趣。它创建了一个三字符宽的输入框，并将输入绑定到 GUESS 全局变量。它还通过 -validatecommand 选项设置了验证，阻止输入部件接收除数字以外的任何内容。focus 命令是用户界面的一项改进，使程序启动时输入部件处于激活状态。没有此命令，你需要先点击输入部件才可以输入。bind 命令允许你在按下回车键时自动点击 “Guess” 按钮。如果你记得 check_guess 中的内容，猜测正确之后会重新绑定回车键到 “Quit” 按钮。最后，这部分设定了图形用户界面的布局：grid .inst grid .low .dash .high grid .status .result grid .guess .entry grid .quit grid 几何管理器被逐步调用，以逐渐构建出预期的用户体验。它主要设置了五行部件。前三行是显示不同值的标签，第四行是 “Guess” 按钮和 entry 部件，最后是 “Quit” 按钮。程序到此已经初始化完毕，wish shell 进入事件循环，等待用户输入整数并按下按钮。基于其在被监视的全局变量中找到的变化，它会更新标签。注意，输入光标开始就在输入框中，而且按下回车键将调用适当且可用的按钮。这只是一个初级的例子，Tcl/Tk 有许多可以让间隔、字体、颜色和其他用户界面方面更具有吸引力的选项，这超出了本文中简单 UI 的示例。运行这个应用，你可能会注意到这些部件看起来并不很精致或现代。这是因为我正在使用原始的经典部件集，它们让人回忆起 X Windows Motif 的时代。不过，还有一些默认的部件扩展，被称为主题部件，它们可以让你的应用程序有更现代、更精致的外观和感觉。启动游戏！保存文件之后，在终端中运行它：$ ./numgame.wish 在这种情况下，我无法给出控制台的输出，因此这里有一个动画 GIF 来展示如何玩这个游戏：进一步了解 TclTcl 支持命名空间的概念，所以在这里使用的变量并不必须是全局的。你可以把绑定的部件变量组织进不同的命名空间。对于像这样的简单程序，可能并不太需要这么做。但对于更大规模的项目，你可能会考虑这种方法。proc check_guess 函数体内有一行 global 代码我之前没有解释。在 Tcl 中，所有变量都按值传递，函数体内引用的变量的范围是局部的。在这个情况下，我希望修改的是全局变量，而不是局部范围的版本。Tcl 提供了许多方法来引用变量，在执行堆栈的更高级别执行代码。在一些情况下，像这样的简单引用可能带来一些复杂性和错误，但是调用堆栈的操作非常有力，允许 Tcl 实现那些在其他语言中实现起来可能较为复杂的新的条件和循环结构。最后，在这篇文章中，我没有提到几何管理器，它们用于以特定的顺序展示部件。只有被某种几何管理器管理的部件才能显示在屏幕上。grid 管理器相当简洁，它按照从左到右的方式放置部件。我使用了五个 grid 定义来创建了五行。另外还有两个几何管理器：place 和 pack。pack 管理器将部件围绕窗口边缘排列，而 place 管理器允许固定部件的位置。除这些几何管理器外，还有一些特殊的部件，如 canvas ，text 和 panedwindow，它们可以容纳并管理其他部件。你可以在经典的 Tcl/Tk 参考指南，以及 Tk 命令 文档页上找到这些部件的全面描述。继续学习编程Tcl 和 Tk 提供了一个简单有效的方法来构建图形用户界面和事件驱动应用程序。这个简单的猜数游戏只是你能用这些工具做到的事情的起点。通过继续学习和探索 Tcl 和 Tk，你可以打开构建强大且用户友好的应用程序的无数可能性。继续尝试，继续学习，看看你新习得的 Tcl 和 Tk 技能能带你到哪里。（题图：MJ/40621c50-6577-4033-9f3c-8013bd0286f1）via: https://opensource.com/article/23/4/learn-tcltk-wish-simple-game作者：James Farrell 选题：lkxed 译者：ChatGPT 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
本教程让你通过编写一个 “猜数字” 游戏来探索 Basic。用多种语言编写同一个应用是学习新的编程语言的好方法。大多数编程语言都有某些共同点，如：变量表达式语句这些概念是大多数编程语言的基础。当你理解了它们，你就可以开始研究其他的东西了。编程语言通常有一些相似之处。当你了解了一种编程语言，你就可以通过认识其差异来学习另一种语言的基础知识。用标准程序进行练习是学习新语言的一个好方法。它使你能够专注于语言，而不是程序的逻辑。在这个系列文章中，我使用了一个“猜数字”的程序，在这个程序中，计算机在 1 到 100 之间挑选一个数字，并要求你猜出来。程序循环进行，直到你猜对数字为止。这个程序锻炼了编程语言中的几个概念：变量输入输出条件判断循环这是学习一种新的编程语言的很好的实践。本文主要介绍 Basic。在（Bywater）Basic 中猜数字对于 Basic 编程语言，没有真正的标准。维基百科说：“BASIC（ 初学者通用符号指令代码 Beginners' All-purpose Symbolic Instruction Code ）是一个通用的高级编程语言系列，旨在方便使用”。BWBasic 的实现是在 GPL 下提供的。你可以通过编写一个“猜数字”游戏来探索 Basic。在 Linux 上安装 Basic在 Debian 或 Ubuntu 中，你可以用以下方法安装 Basic：$ apt install -y bwbasic 下载 Fedora、CentOS、Mageia 和其他任何 Linux 发行版的最新版本 tarball。解压并设置可执行，然后从终端运行它：$ tar --extract --file bwbasic*z $ chmod +x bywater $ ./bywater 在 Windows 上，下载 .exe 版本。Basic 代码下面是我的实现：10 value$ = cint(rnd * 100) + 1 20 input "enter guess"; guess$ 30 guess$ = val(guess$) 40 if guess$ < value$ then print "Too low" 50 if guess$ > value$ then print "Too high" 60 if guess$ = value$ then 80 70 goto 20 80 print "That's right" Basic 程序可以是编号的，也可以是不编号的。通常情况下，写程序时最好不编号，但用编号的行来写，可以更容易地引用各个行。按照惯例，编码者将行写成 10 的倍数。这种方法允许在现有的行之间插入新的行，以便进行调试。下面是我对上述方法的解释：10 行：使用内置的 rnd 函数计算一个 1 到 100 之间的随机值，该函数生成一个 0 到 1 之间的数字，不包括 1。20 行：询问一个猜测，并将该值放入 guess$ 标量变量。30 行将该值转换为一个数字。40 行和 50 行：根据比较结果，给猜测者以反馈。70 行：回到循环的起点。60 行：通过将控制权转移到 80 行来打破循环。80 行是最后一行，所以程序在这之后退出。输出示例下面是将该程序放入 program.bas 后的一个例子：$ bwbasic program.bas Bywater BASIC Interpreter/Shell, version 2.20 patch level 2 Copyright (c) 1993, Ted A. Campbell Copyright (c) 1995-1997, Jon B. Volkoff enter guess? 50 Too low enter guess? 75 Too low enter guess? 88 Too high enter guess? 80 Too low enter guess? 84 Too low enter guess? 86 Too high enter guess? 85 That's right 开始学习这个“猜数字”游戏是学习新的编程语言的一个很好的入门程序，因为它以一种相当直接的方式锻炼了几个常见的编程概念。通过在不同的编程语言中实现这个简单的游戏，你可以展示这些语言的一些核心概念，并比较它们的细节。你有喜欢的编程语言吗？你会如何用它来写“猜数字”的游戏？请关注本系列文章，看看你可能感兴趣的其他编程语言的例子吧！via: https://opensource.com/article/23/2/learn-basic-coding-game作者：Moshe Zadka 选题：lkxed 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
通过编写“猜数字”游戏来学习 Ada 编程语言
这个 "猜数字 "游戏是学习新编程语言的一个很好的入门程序，因为它以一种相当直接的方式锻炼了几个常见的编程概念。当你想 学习一种新的编程语言 时，把注意力放在编程语言的共同点上是很好的：变量表达式语句这些概念是大多数编程语言的基础。一旦你理解了它们，你就可以开始琢磨其他的东西了。因为编程语言通常有相似之处，一旦你知道一种语言，你就可以通过了解其差异来学习另一种语言的基础知识。学习新语言的一个好方法是用一个标准程序进行练习。这使你能够专注于语言，而不是程序的逻辑。在这个系列文章中，我使用了一个“猜数字”的程序，在这个程序中，计算机在 1 到 100 之间挑选一个数字，并要求你猜出来。程序循环进行，直到你猜对数字为止。这个程序锻炼了编程语言中的几个概念：变量输入输出条件判断循环这是一个学习新的编程语言的很好的实践实验。安装 AdaAda 编程语言 是一种独特的、高度结构化的语言，有专门一群开发者使用它。Ada 的工具链是 GNU Ada 开发环境，多被称为 GNAT。你可以使用你的发行版的包管理器在 Linux 上安装 GNAT。在 Fedora、CentOS 或类似系统上：$ sudo dnf install gcc-gnat 在 Debian、Linux Mint 及衍生版上:$ sudo apt install gnat 在 macOS 和 Windows 上，你可以从 Adacore 网站 下载一个安装程序（从下拉菜单中选择你的平台）。在 Ada 中猜数字创建一个名为 game.adb 的文件。这个程序使用的两个内置 Ada 库：Text_IO 和 Numerics.Discrete_Random：with Ada.Text_IO; use Ada.Text_IO; with Ada.Numerics.Discrete_Random; 过程头 过程 procedure 的名称必须与文件的名称一致。第一部分是定义变量。注意，discrete_random 是专门针对特定范围的。在这里，允许数字范围：procedure Game is type randRange is range 1..100; package Rand_Int is new ada.numerics.discrete_random(randRange); use Rand_Int; gen : Generator; num : randRange; incorrect: Boolean := True; guess: randRange; 过程逻辑该逻辑从 reset(gen) 开始。这将初始化随机数发生器，确保每次运行程序时，用 random(gen) 初始化的数字将是不同的。下一步是运行循环：输出猜测的指令读取该行将其转换为 randRange。将其与数字进行核对如果数字匹配，incorrect 被设置为 False，导致循环的下一次迭代退出。最后，程序在退出前会打印出对猜测正确性的确认：begin reset(gen); num := random(gen); while incorrect loop Put_Line ("Guess a number between 1 and 100"); declare guess_str : String := Get_Line (Current_Input); begin guess := randRange'Value (guess_str); end; if guess < num then Put_line("Too low"); elsif guess > num then Put_line("Too high"); else incorrect := False; end if; end loop; Put_line("That's right"); end Game; 编译程序编译 Ada 程序的最简单方法是使用 gnatmake：$ gnatmake game.adb aarch64-linux-gnu-gcc-10 -c game.adb aarch64-linux-gnu-gnatbind-10 -x game.ali aarch64-linux-gnu-gnatlink-10 game.ali 这将生成一个名为 game 的二进制文件。运行程序程序的每次运行都会有一些不同。这是一个例子：$ ./game Guess a number between 1 and 100 50 Too low Guess a number between 1 and 100 75 Too low Guess a number between 1 and 100 82 Too low Guess a number between 1 and 100 90 Too high Guess a number between 1 and 100 87 Too low Guess a number between 1 and 100 88 That's right 学习 Ada这个“猜数字”游戏是学习新的编程语言的一个很好的入门程序，因为它以一种相当直接的方式锻炼了几个常见的编程概念。通过在不同的编程语言中实现这个简单的游戏，你可以展示这些语言的一些核心概念，并比较它们的细节。你有喜欢的编程语言吗？你会如何用它来写“猜数字”的游戏？请关注本系列文章，看看你可能感兴趣的其他编程语言的例子吧!via: https://opensource.com/article/23/1/learn-ada-simple-game作者：Moshe Zadka 选题：lkxed 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
不同编程语言是如何完成同一件事
通过一个简单的小游戏比较 13 种编程语言。当我开始学习一种新的编程语言时，会把重点放在定义变量、书写声明以及计算表达式，一旦对这些概念有一个大致的了解，通常就能够自己弄清剩下的部分。大多数编程语言都具有相似性，所以如果你掌握了一种编程语言，学习下一种语言的重点就是弄清楚独有的概念以及区分不同。我喜欢写一些测试程序来帮助练习新的编程语言。其中我经常写的是一个叫做“猜数字”的小游戏，计算机选出 1 到 100 里的任一数字，然后我来猜。程序循环进行，直到猜出正确数字。通过伪代码可以看出，这是个非常简单的程序：计算机在 1 到 100 之间选出一个随机数字循环进行直到猜出该随机数字计算机读取我的猜测告诉我我的猜测过高还是过低我们发表了一些文章，用不同的语言写这个程序。这是一个比较不同语言做同样事情的有趣机会。大多数编程语言具有相似性，所以当你在学习下一种新的编程语言时，主要是学习它的独特之处。C 语言由 Dennis Ritchie 于 1972 年在贝尔实验室创建，是一种早期的通用编程语言。C 语言非常受欢迎，并迅速成为 Unix 系统上的标准编程语言。正是因为它的流行，许多其他编程语言也采用了类似的编程语法。这就是为什么如果你已经知道如何使用 C 语言编程，学习 C++、Rust、Java、Groovy、JavaScript、awk 或 Lua 会更容易。接下来我们看看这些不同的编程语言是如何实现 “猜数字” 游戏的主要步骤。我将把重点放在基本元素的相似或不同，跳过一些外围代码，如分配临时变量。计算机在 1 到 100 之间选出一个随机数字你可以看到这里有许多相似之处。大多数编程语言使用类似 rand() 的函数，你可以设定一个范围来生成随机数。而其他一些语言使用一个特殊的函数来设定范围生成随机数。C：// Using the Linux `getrandom` system call getrandom(&randval, sizeof(int), GRND_NONBLOCK); number = randval % maxval + 1; // Using the standard C library number = rand() % 100 + 1; C++：int number = rand() % 100+1; Rust：let random = rng.gen_range(1..101); Java：private static final int NUMBER = r.nextInt(100) + 1; Groovy：int randomNumber = (new Random()).nextInt(100) + 1 JavaScript：const randomNumber = Math.floor(Math.random() * 100) + 1 awk：randomNumber = int(rand() * 100) + 1 Lua：number = math.random(1,100) 循环进行直到我猜出该随机数字循环通常是用控制流程来实现的，如 while 或 do-while。JavaScript 中的实现没有使用循环，而是 “实时 ”更新 HTML 页面，直到用户猜出正确的数字。Awk 虽然支持循环，但是通过循环读取输入信息是没有意义的，因为 Awk 是基于数据管道的，所以它从文件而不是直接从用户读取输入信息。C：do { … } while (guess != number); C++：do { … } while ( number != guess ); Rust：for line in std::io::stdin().lock().lines() { … break; } Java：while ( guess != NUMBER ) { … } Groovy：while ( … ) { … break; } Lua：while ( player.guess ~= number ) do … end 计算机读取我的猜测不同编程语言对输入的处理方式不同。例如，JavaScript 直接从 HTML 表单中读取数值，而 Awk 则从数据管道中读取数据。C：scanf("%d", &guess); C++：cin >> guess; Rust：let parsed = line.ok().as_deref().map(str::parse::<i64>); if let Some(Ok(guess)) = parsed { … } Java：guess = player.nextInt(); Groovy：response = reader.readLine() int guess = response as Integer JavaScript：let myGuess = guess.value Awk：guess = int($0) Lua：player.answer = io.read() player.guess = tonumber(player.answer) 告诉我猜测过高还是过低在这些类 C 语言中，通常是通过 if 语句进行比较的。每种编程语言打印输出的方式有一些变化，但打印语句在每个样本中都是可识别的。C：if (guess < number) { puts("Too low"); } else if (guess > number) { puts("Too high"); } … puts("That's right!"); C++：if ( guess > number) { cout << "Too high.\n" << endl; } else if ( guess < number ) { cout << "Too low.\n" << endl; } else { cout << "That's right!\n" << endl; exit(0); } Rust：_ if guess < random => println!("Too low"), _ if guess > random => println!("Too high"), _ => { println!("That's right"); break; } Java：if ( guess > NUMBER ) { System.out.println("Too high"); } else if ( guess < NUMBER ) { System.out.println("Too low"); } else { System.out.println("That's right!"); System.exit(0); } Groovy：if (guess < randomNumber) print 'too low, try again: ' else if (guess > randomNumber) print 'too high, try again: ' else { println "that's right" break } JavaScript：if (myGuess === randomNumber) { feedback.textContent = "You got it right!" } else if (myGuess > randomNumber) { feedback.textContent = "Your guess was " + myGuess + ". That's too high. Try Again!" } else if (myGuess < randomNumber) { feedback.textContent = "Your guess was " + myGuess + ". That's too low. Try Again!" } Awk：if (guess < randomNumber) { printf "too low, try again:" } else if (guess > randomNumber) { printf "too high, try again:" } else { printf "that's right\n" exit } Lua：if ( player.guess > number ) then print("Too high") elseif ( player.guess < number) then print("Too low") else print("That's right!") os.exit() end 非类 C 编程语言会怎么样呢？非类 C 编程语言会有很大的不同，需要学习特定的语法来完成每一步。Racket 源于 Lisp 和 Scheme，所以它使用 Lisp 的前缀符和大量括号。Python 使用空格而不是括号来表示循环之类的块。Elixir 是一种函数式编程语言，有自己的语法。Bash 是基于 Unix 系统中的 Bourne shell，它本身借鉴了 Algol68，并支持额外的速记符，如 && 作为 and 的变体。Fortran 是在使用打孔卡片输入代码的时期创建的，所以它依赖于一些重要列的 80 列布局。我将通过比较 if 语句，举例表现这些编程语言的不同。if 判断一个值是否小于或大于另一个值，并向用户打印适当信息。Racket：(cond [(> number guess) (displayln "Too low") (inquire-user number)] [(< number guess) (displayln "Too high") (inquire-user number)] [else (displayln "Correct!")])) Python：if guess < random: print("Too low") elif guess > random: print("Too high") else: print("That's right!") Elixir：cond do guess < num -> IO.puts "Too low!" guess_loop(num) guess > num -> IO.puts "Too high!" guess_loop(num) true -> IO.puts "That's right!" end Bash：[ "0$guess" -lt $number ] && echo "Too low" [ "0$guess" -gt $number ] && echo "Too high" Fortran：IF (GUESS.LT.NUMBER) THEN PRINT *, 'TOO LOW' ELSE IF (GUESS.GT.NUMBER) THEN PRINT *, 'TOO HIGH' ENDIF 更多当你在学习一种新的编程语言时 “猜数字” 游戏是一个很友好的入门程序，通过一种简单的方式练习了几个常见的编程概念。通过不同编程语言实现这个简单游戏，你可以理解一些核心概念和每种语言的细节。学习如何用 C 和类 C 语言编写 “猜数字” 游戏：C， Jim HallC++， Seth KenlonRust， Moshe ZadkaJava， Seth KenlonGroovy， Chris HermansenJavaScript， Mandy Kendallawk， Chris HermansenLua， Seth Kenlon其他语言：Racket， Cristiano L. FontanaPython， Moshe ZadkaElixir， Moshe ZadkaBash， Jim HallFortran， Jim Hallvia: https://opensource.com/article/21/4/compare-programming-languages作者：Jim Hall 选题：lujun9972 译者：VeryZZJ 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
编程语言往往具有许多共同特征。学习一门新语言的好方法是去写一个熟悉的程序。在本文中，我将会使用 Awk 编写一个“猜数字”程序来展示熟悉的概念。当你学习一门新的编程语言时，最好把重点放在大多数编程语言都有的共同点上:变量 —— 存储信息的地方表达式 —— 计算的方法语句 —— 在程序中表示状态变化的方法这些概念是大多是编程语言的基础。一旦你理解了这些概念，你就可以开始把其他的弄清楚。例如，大多数语言都有由其设计所支持的“处理方式”，这些方式在不同语言之间可能有很大的不同。这些方法包括模块化（将相关功能分组在一起）、声明式与命令式、面向对象、低级与高级语法特性等等。许多程序员比较熟悉的是编程“仪式”，即，在处理问题之前设置场景所需花费的工作。据说 Java 编程语言有一个源于其设计的重要仪式要求，就是所有代码都在一个类中定义。但从根本上讲，编程语言通常有相似之处。一旦你掌握了一种编程语言，就可以从学习另一种语言的基本知识开始，品味这种新语言的不同之处。一个好方法是创建一组基本的测试程序。有了这些，就可以从这些相似之处开始学习。你可以选择创建的一个测试程序是“猜数字”程序。电脑从 1 到 100 之间选择一个数字，让你猜这个数字。程序一直循环，直到你猜对为止。“猜数字”程序练习了编程语言中的几个概念:变量输入输出条件判断循环这是学习一门新的编程语言的一个很好的实践实验。注：本文改编自 Moshe Zadka 在 Julia 中使用这种方法和 Jim Hall在 Bash 中使用这种方法的文章。在 awk 程序中猜数让我们编写一个实现“猜数字”游戏的 Awk 程序。Awk 是动态类型的，这是一种面向数据转换的脚本语言，并且对交互使用有着令人惊讶的良好支持。Awk 出现于 20 世纪 70 年代，最初是 Unix 操作系统的一部分。如果你不了解 Awk，但是喜欢电子表格，这就是一个你可以 去学习 Awk 的信号！您可以通过编写一个“猜数字”游戏版本来开始对 Awk 的探索。以下是我的实现（带有行号，以便我们可以查看一些特定功能）： 1 BEGIN { 2 srand(42) 3 randomNumber = int(rand() * 100) + 1 4 print "random number is",randomNumber 5 printf "guess a number between 1 and 100\n" 6 } 7 { 8 guess = int($0) 9 if (guess < randomNumber) { 10 printf "too low, try again:" 11 } else if (guess > randomNumber) { 12 printf "too high, try again:" 13 } else { 14 printf "that's right\n" 15 exit 16 } 17 } 我们可以立即看到 Awk 控制结构与 C 或 Java 的相似之处，但与 Python 不同。 在像 if-then-else、while 这样的语句中，then、else 和 while 部分接受一个语句或一组被 { 和 } 包围的语句。然而，Awk 有一个很大的区别需要从一开始就了解：根据设计，Awk 是围绕数据管道构建的。这是什么意思呢？大多数 Awk 程序都是一些代码片段，它们接收一行输入，对数据做一些处理，然后将其写入输出。认识到这种转换管道的需要，Awk 默认情况下提供了所有的转换管道。让我们通过关于上面程序的一个基本问题来探索：“从控制台读取数据”的结构在哪里？答案是——“内置的”。特别的，第 7-17 行告诉 Awk 如何处理被读取的每一行。在这种情况下，很容易看到第 1-6 行是在读取任何内容之前被执行的。更具体地说，第 1 行上的 BEGIN 关键字是一种“模式”，在本例中，它指示 Awk 在读取任何数据之前，应该先执行 { ... } 中 BEGIN 后面的内容。另一个类似的关键字 END，在这个程序中没有被使用，它指示 Awk 在读取完所有内容后要做什么。回到第 7-17 行，我们看到它们创建了一个类似代码块 { ... } 的片段，但前面没有关键字。因为在 { 之前没有任何东西可以让 Awk 匹配，所以它将把这一行用于接收每一行输入。每一行的输入都将由用户输入作为猜测。让我们看看正在执行的代码。首先，是在读取任何输入之前发生的序言部分。在第 2 行，我们用数字 42 初始化随机数生成器（如果不提供参数，则使用系统时钟）。为什么要用 42？当然要选 42！#The_Hitchhiker's_Guide_to_the_Galaxy) 第 3 行计算 1 到 100 之间的随机数，第 4 行输出该随机数以供调试使用。第 5 行邀请用户猜一个数字。注意这一行使用的是 printf，而不是 print。和 C 语言一样，printf 的第一个参数是一个用于格式化输出的模板。既然用户知道程序需要输入，她就可以在控制台上键入猜测。如前所述，Awk 将这种猜测提供给第 7-17 行的代码。第 18 行将输入记录转换为整数；$0 表示整个输入记录，而 $1 表示输入记录的第一个字段，$2 表示第二个字段，以此类推。是的，Awk 使用预定义的分隔符（默认为空格）将输入行分割为组成字段。第 9-15 行将猜测结果与随机数进行比较，打印适当的响应。如果猜对了，第 15 行就会从输入行处理管道中提前退出。就这么简单！考虑到 Awk 程序不同寻常的结构，代码片段会对特定的输入行配置做出反应，并处理数据，让我们看看另一种结构，看看过滤部分是如何工作的： 1 BEGIN { 2 srand(42) 3 randomNumber = int(rand() * 100) + 1 4 print "random number is",randomNumber 5 printf "guess a number between 1 and 100\n" 6 } 7 int($0) < randomNumber { 8 printf "too low, try again: " 9 } 10 int($0) > randomNumber { 11 printf "too high, try again: " 12 } 13 int($0) == randomNumber { 14 printf "that's right\n" 15 exit 16 } 第 1–6 行代码没有改变。但是现在我们看到第 7-9 行是当输入整数值小于随机数时执行的代码，第 10-12 行是当输入整数值大于随机数时执行的代码，第 13-16 行是两者相等时执行的代码。这看起来“很酷但很奇怪” —— 例如，为什么我们会重复计算 int($0)？可以肯定的是，用这种方法来解决问题会很奇怪。但这些模式确实是分离条件处理的非常好的方式，因为它们可以使用正则表达式或 Awk 支持的任何其他结构。为了完整起见，我们可以使用这些模式将普通的计算与只适用于特定环境的计算分离开来。下面是第三个版本： 1 BEGIN { 2 srand(42) 3 randomNumber = int(rand() * 100) + 1 4 print "random number is",randomNumber 5 printf "guess a number between 1 and 100\n" 6 } 7 { 8 guess = int($0) 9 } 10 guess < randomNumber { 11 printf "too low, try again: " 12 } 13 guess > randomNumber { 14 printf "too high, try again: " 15 } 16 guess == randomNumber { 17 printf "that's right\n" 18 exit 19 } 认识到这一点，无论输入的是什么值，都需要将其转换为整数，因此我们创建了第 7-9 行来完成这一任务。现在第 10-12、13-15 和 16-19 行这三组代码，都是指已经定义好的变量 guess，而不是每次都对输入行进行转换。让我们回到我们想要学习的东西列表:变量 —— 是的，Awk 有这些；我们可以推断出，输入数据以字符串形式输入，但在需要时可以转换为数值输入 —— Awk 只是通过它的“数据转换管道”的方式发送输入来读取数据输出 —— 我们已经使用了 Awk 的 print 和 printf 函数来将内容写入输出条件判断 —— 我们已经学习了 Awk 的 if-then-else 和对应特定输入行配置的输入过滤器循环 —— 嗯，想象一下！我们在这里不需要循环，这还是多亏了 Awk 采用的“数据转换管道”方法；循环“就这么发生了”。注意，用户可以通过向 Awk 发送一个文件结束信号（当使用 Linux 终端窗口时可通过快捷键 CTRL-D）来提前退出管道。不需要循环来处理输入的重要性是非常值得的。Awk 能够长期保持存在的一个原因是 Awk 程序是紧凑的，而它们紧凑的一个原因是不需要从控制台或文件中读取的那些格式代码。让我们运行下面这个程序：$ awk -f guess.awk random number is 25 guess a number between 1 and 100: 50 too high, try again: 30 too high, try again: 10 too low, try again: 25 that's right $ 我们没有涉及的一件事是注释。Awk 注释以 # 开头，以行尾结束。总结Awk 非常强大，这种“猜数字”游戏是入门的好方法。但这不应该是你探索 Awk 的终点。你可以看看 Awk 和 Gawk（GNU Awk）的历史，Gawk 是 Awk 的扩展版本，如果你在电脑上运行 Linux，可能会有这个。或者，从它的原始开发者那里阅读关于 最初版本 的各种信息。你还可以 下载我们的备忘单 来帮你记录下你所学的一切。Awk 备忘单via: https://opensource.com/article/21/1/learn-awk作者：Chris Hermansen 选题：lujun9972 译者：FYJNEVERFOLLOWS 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
Fortran 是在打孔卡时代编写的语言，因此它的语法非常有限。但你仍然可以用它编写有用和有趣的程序。Fortran 77 是我学习的第一门编译型编程语言。一开始时，我自学了如何在 Apple II 上用 BASIC 编写程序，后来又学会在 DOS 上用 QBasic 编写程序。但是当我去大学攻读物理学时，我又学习了 Fortran。Fortran 曾经在科学计算中很常见。曾几何时，所有计算机系统都有一个 Fortran 编译器。Fortran 曾经像今天的 Python 一样无处不在。因此，如果你是像我这样的物理学专业学生，在 1990 年代工作，那你肯定学习了 Fortran。我一直认为 Fortran 与 BASIC 有点相似，所以每当我需要编写一个简短程序，来分析实验室数据或执行其他一些数值分析时，我都会很快想到 Fortran。我在空闲时用 Fortran 编写了一个“猜数字”游戏，其中计算机会在 1 到 100 之间选择一个数字，并让我猜这个数字。程序会一直循环，直到我猜对了为止。“猜数字”程序练习了编程语言中的几个概念：如何为变量赋值、如何编写语句以及如何执行条件判断和循环。这是学习新编程语言时一个很好的的实践案例。Fortran 编程基础虽然 Fortran 这些年来一直在更新，但我最熟悉的还是 Fortran 77，这是我多年前学习的实现版本。Fortran 是程序员还在打孔卡上编程的年代创建的，因此“经典” Fortran 仅限于处理可以放在打孔卡上的数据。这意味着你只能编写符合以下限制条件的经典 Fortran 程序（LCTT 译注：后来的 Fortran 95 等版本已经对这些限制做了很大的改进，如有兴趣建议直接学习新版）：每张卡只允许一行源代码。仅识别第 1-72 列（最后八列，73-80，保留给卡片分类器）。行号（“标签”）位于第 1-5 列。程序语句在第 7-72 列。要表示跨行，请在第 6 列中输入一个连续字符（通常是 +）。要创建注释行，请在第 1 列中输入 C 或 *。只有字符 A 到Z（大写字母）、0 到9（数字）和特殊字符 = + - * / ( ) , . $ ' : 和空格能够使用。虽然有这些限制，你仍然可以编写非常有用和有趣的程序。在 Fortran 中猜数字通过编写“猜数字”游戏来探索 Fortran。这是我的实现代码：CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC C PROGRAM TO GUESS A NUMBER 1-100 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC PROGRAM GUESSNUM INTEGER SEED, NUMBER, GUESS PRINT *, 'ENTER A RANDOM NUMBER SEED' READ *, SEED CALL SRAND(SEED) NUMBER = INT( RAND(0) * 100 + 1 ) PRINT *, 'GUESS A NUMBER BETWEEN 1 AND 100' 10 READ *, GUESS IF (GUESS.LT.NUMBER) THEN PRINT *, 'TOO LOW' ELSE IF (GUESS.GT.NUMBER) THEN PRINT *, 'TOO HIGH' ENDIF IF (GUESS.NE.NUMBER) GOTO 10 PRINT *, 'THATS RIGHT!' END 如果你熟悉其他编程语言，你大概可以通过阅读源代码来弄清楚这个程序在做什么。前三行是注释块，表示程序的功能。第四行 PROGRAM GUESSNUM 将其标识为一个 程序 program ，并由最后一行的 END 语句关闭。定义变量后，程序会提示用户输入随机数种子。Fortran 程序无法从操作系统初始化随机数生成器，因此你必须始终使用“种子”值和 SRAND 子程序 subroutine 启动随机数生成器。Fortran 使用 RAND(0) 函数生成 0 到 0.999…… 之间的随机数。参数 0 告诉 RAND 函数生成一个随机数。将此随机数乘以 100 以生成 0 到 99.999…… 之间的数字，然后加 1 得到 1 到 100.999…… 之间的值。INT 函数将结果截断为整数；因此，变量 NUMBER 就是一个介于 1 到 100 之间的随机数。程序会给出提示，然后进入一个循环。Fortran 不支持更现代的编程语言中可用的 while 或 do-while 循环（LCTT 译注：Fortran 95 等新版支持，也因此在一定程度上减少了 GOTO 的使用）。相反，你必须使用标签（行号）和 GOTO 语句来构建自己的循环。这就是 READ 语句有一个行号的原因：你可以在循环末尾使用 GOTO 跳转到此标签。穿孔卡片没有 <（小于）和 >（大于）符号，因此 Fortran 采用了另一种语法来进行值比较。要测试一个值是否小于另一个值，请使用 .LT.（小于）。要测试一个值是否大于另一个值，请使用 .GT.（大于）。等于和不等于分别是 .EQ. 和 .NE.。在每次循环中，程序都会验证用户的猜测值。如果用户的猜测值小于随机数，程序打印 TOO LOW，如果猜测大于随机数，程序打印 TOO HIGH。循环会一直持续，直到用户的猜测值等于目标随机数为止。当循环退出时，程序打印 THATS RIGHT! 并立即结束运行。$ gfortran -Wall -o guess guess.f $ ./guess ENTER A RANDOM NUMBER SEED 93759 GUESS A NUMBER BETWEEN 1 AND 100 50 TOO LOW 80 TOO HIGH 60 TOO LOW 70 TOO LOW 75 TOO HIGH 73 TOO LOW 74 THATS RIGHT! 每次运行程序时，用户都需要输入不同的随机数种子。如果你总是输入相同的种子，程序给出的随机数也会一直不变。在其他语言中尝试在学习一门新的编程语言时，这个“猜数字”游戏是一个很好的入门程序，因为它以非常简单的方式练习了几个常见的编程概念。通过用不同的编程语言实现这个简单的游戏，你可以弄清一些核心概念以及比较每种语言的细节。你有最喜欢的编程语言吗？如何用你最喜欢的语言来编写“猜数字”游戏？跟随本系列文章来查看你可能感兴趣的其他编程语言示例吧。via: https://opensource.com/article/21/1/fortran作者：Jim Hall 选题：lujun9972 译者：unigeorge 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
通过编写“猜数字”游戏来学习 Elixir 编程语言，并将它与一个你熟知的语言做对比。为了更好的学习一门新的编程语言，最好的方法是去关注主流语言的一些共有特征：变量表达式语句这些概念是大多数编程语言的基础。因为这些相似性，只要你通晓了一门编程语言，你可以通过对比差异来熟知另一门编程语言。另外一个学习新编程语言的好方法是开始编写一个简单标准的程序。它可以让你集中精力在语言上而非程序的逻辑本身。在这个系列的文章中，我们使用“猜数字”程序来实现，在这个程序中，计算机会选择一个介于 1 到 100 之间的数字，并要求你来猜测它。程序会循环执行，直到你正确猜出该数字为止。“猜数字”这个程序使用了编程语言的以下概念：变量输入输出条件判断循环这是一个学习新编程语言的绝佳实践。猜数字的 Elixir 实现Elixir 是一门被设计用于构建稳定可维护应用的动态类型的函数式编程语言。它与 Erlang 运行于同一虚拟机之上，吸纳了 Erlang 的众多长处的同时拥有更加简单的语法。你可以编写一个 Elixir 版本的“猜数字”游戏来体验这门语言。这是我的实现方法：defmodule Guess do def guess() do random = Enum.random(1..100) IO.puts "Guess a number between 1 and 100" Guess.guess_loop(random) end def guess_loop(num) do data = IO.read(:stdio, :line) {guess, _rest} = Integer.parse(data) cond do guess < num -> IO.puts "Too low!" guess_loop(num) guess > num -> IO.puts "Too high!" guess_loop(num) true -> IO.puts "That's right!" end end end Guess.guess() Elixir 通过列出变量的名称后面跟一个 = 号来为了给变量分配一个值。举个例子，表达式 random = 0 给 random 变量分配一个数值 0。代码以定义一个模块开始。在 Elixir 语言中，只有模块可以包含命名函数。紧随其后的这行代码定义了入口函数 guess()，这个函数：调用 Enum.random() 函数来获取一个随机整数打印游戏提示调用循环执行的函数剩余的游戏逻辑实现在 guess_loop() 函数中。guess_loop() 函数利用 尾递归 来实现循环。Elixir 中有好几种实现循环的方法，尾递归是比较常用的一种方式。guess_loop() 函数做的最后一件事就是调用自身。guess_loop() 函数的第一行读取用户输入。下一行调用 parse() 函数将输入转换成一个整数。cond 表达式是 Elixir 版本的多重分支表达式。与其他语言中的 if/elif 或者 if/elsif 表达式不同，Elixir 对于的首个分支或者最后一个没有分支并没有区别对待。这个 cond 表达式有三路分支：猜测的结果可以比随机数大、小或者相等。前两个选项先输出不等式的方向然后递归调用 guess_loop()，循环返回至函数开始。最后一个选项输出 That's right，然后这个函数就完成了。输出例子现在你已经编写了你的 Elixir 代码，你可以运行它来玩“猜数字”的游戏。每次你执行这个程序，Elixir 会选择一个不同的随机数，你可以一直猜下去直到你找到正确的答案：$ elixir guess.exs Guess a number between 1 and 100 50 Too high 30 Too high 20 Too high 10 Too low 15 Too high 13 Too low 14 That's right! “猜数字”游戏是一个学习一门新编程语言的绝佳入门程序，因为它用了非常直接的方法实践了常用的几个编程概念。通过用不同语言实现这个简单的小游戏，你可以实践各个语言的核心概念并且比较它们的细节。你是否有你最喜爱的编程语言？你将怎样用它来编写“猜数字”这个游戏？关注这个系列的文章来看看其他你可能感兴趣的语言实现。via: https://opensource.com/article/20/12/elixir作者：Moshe Zadka 选题：lujun9972 译者：tt67wq 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
通过使用一个简单的游戏来练习一些基本的 JavaScript 概念，迈出创建交互性动态 Web 内容的第一步。可以肯定地说，没有 JavaScript，大多数现代 Web 都将不存在。它是三种标准 Web 技术（以及 HTML 和 CSS ）之一，它使任何人都可以创建我们在万维网体验中所期待的交互式、动态内容。从 React 这样的框架到 D3 这样的数据可视化库，很难想象没有它的 Web。现在有很多东西要学习，开始学习这种流行语言的好方法是编写一个简单的应用程序以熟悉某些概念。 最近，一些人写了关于如何通过编写简单的猜谜游戏来学习自己喜欢的语言的文章，因此这是一个很好的起点！现在开始吧JavaScript 有许多种风格，但我将从最基本的开始，通常称为 “普通 JavaScript”。 JavaScript 主要是一种客户端脚本语言，因此它可以在任何标准浏览器中运行，而无需安装任何程序。你只需要一个代码编辑器（Brackets 就是一个不错的选择）和一个 Web 浏览器。HTML 用户界面JavaScript 在 Web 浏览器中运行，并与其他标准 Web 技术 HTML 和 CSS 交互。要创建此游戏，你首先需要使用 HTML（超文本标记语言）来创建供玩家使用的简单界面。如果你不清楚，HTML 是一种标记语言，用于为 Web 内容提供结构。首先，先创建一个 HTML 文件。该文件应具有 .html 扩展名，以使浏览器知道它是 HTML 文档。你可以将文件命名为 guessingGame.html。在此文件中使用一些基本的 HTML 标签来显示游戏的标题、玩法说明，供玩家用来输入和提交其猜测的交互式元素以及用于向玩家提供反馈的占位符： JavaScript Guessing Game Guess the Number! I am thinking of a number between 1 and 100. Can you guess what it is? My Guess 和 元素使浏览器知道在页面上显示什么类型的文本。标签对 表示标签之间的文本（Guess the Number!）是标题。后面的一组 标签表示带有说明的短文本是一个段落。此代码块末尾的空 标签用作占位符，用于根据用户的输入提供一些反馈。 要在浏览器中运行此文件，请双击文件或打开你喜欢的浏览器,点击菜单，然后选择文件->打开文件。（如果使用 Brackets 软件，也可以使用角落处的闪电图标在浏览器中打开文件）。生成伪随机数猜谜游戏的第一步是为玩家生成一个数字供玩家猜测。JavaScript 包含几个内置的全局对象，可帮助你编写代码。要生成随机数，请使用 Math 对象。JavaScript中的 Math 具有处理和数学相关的属性和功能。你将使用两个数学函数来生成随机数，供你的玩家猜测。Math.random()，会将生成一个介于 0 和 1 之间的伪随机数。（Math.random 包含 0 但不包含 1。这意味着该函数可以生成 0 ，永远不会产生 1）对于此游戏，请将随机数设置在 1 到 100 之间以缩小玩家的选择范围。取刚刚生成的小数，然后乘以 100，以产生一个介于 0 到……甚至不是 100 之间的小数。至此，你将需要其他步骤来解决这个问题。现在，你的数字仍然是小数，但你希望它是一个整数。为此，你可以使用属于 Math 对象的另一个函数 Math.floor()。Math.floor() 的目的是返回小于或等于你作为参数指定的数字的最大整数，这意味着它会四舍五入为最接近的整数：Math.floor(Math.random() * 100) 这样你将得到 0 到 99 之间的整数，这不是你想要的范围。你可以在最后一步修复该问题，即在结果中加 1。瞧！现在，你有一个（有点）随机生成的数字，介于 1 到 100 之间：Math.floor(Math.random() * 100) + 1 变量现在，你需要存储随机生成的数字，以便可以将其与玩家的猜测进行比较。为此，你可以将其存储到一个 变量。JavaScript 具有不同类型的变量，你可以选择这些类型，具体取决于你要如何使用该变量。对于此游戏，请使用 const 和 let。let 用于指示变量在整个程序中可以改变。const 用于指示变量不应该被修改。const 和 let 还有很多要说的，但现在知道这些就足够了。随机数在游戏中仅生成一次，因此你将使用 const 变量来保存该值。你想给变量起一个清楚地表明要存储什么值的名称，因此将其命名为 randomNumber：const randomNumber 有关命名的注意事项：JavaScript 中的变量和函数名称以驼峰形式编写。如果只有一个单词，则全部以小写形式书写。如果有多个单词，则第一个单词均为小写，其他任何单词均以大写字母开头，且单词之间没有空格。打印到控制台通常，你不想向任何人显示随机数，但是开发人员可能想知道生成的数字以使用它来帮助调试代码。 使用 JavaScript，你可以使用另一个内置函数 console.log() 将数字输出到浏览器的控制台。大多数浏览器都包含开发人员工具，你可以通过按键盘上的 F12 键来打开它们。从那里，你应该看到一个 控制台 标签。打印到控制台的所有信息都将显示在此处。由于到目前为止编写的代码将在浏览器加载后立即运行，因此，如果你查看控制台，你应该会看到刚刚生成的随机数！函数接下来，你需要一种方法来从数字输入字段中获得玩家的猜测，将其与你刚刚生成的随机数进行比较，并向玩家提供反馈，让他们知道他们是否正确猜到了。为此，编写一个函数。 函数 是执行一定任务的代码块。函数是可以重用的，这意味着如果你需要多次运行相同的代码，则可以调用函数，而不必重写执行任务所需的所有步骤。根据你使用的 JavaScript 版本，有许多不同的方法来编写或声明函数。由于这是该语言的基础入门，因此请使用基本函数语法声明函数。以关键字 function 开头，然后起一个函数名。好的做法是使用一个描述该函数的功能的名称。在这个例子中，你正在检查玩家的猜测的数，因此此函数的名字可以是 checkGuess。在函数名称之后，写上一组小括号，然后写上一组花括号。 你将在以下花括号之间编写函数的主体：function checkGuess() {} 使用 DOMJavaScript 的目的之一是与网页上的 HTML 交互。它通过文档对象模型（DOM）进行此操作，DOM 是 JavaScript 用于访问和更改网页信息的对象。现在，你需要从 HTML 中获取数字输入字段中玩家的猜测。你可以使用分配给 HTML 元素的 id 属性（在这种情况下为 guess）来做到这一点： JavaScript 可以通过访问玩家输入到数字输入字段中的数来获取其值。你可以通过引用元素的 ID 并在末尾添加 .value 来实现。这次，使用 let 定义的变量来保存用户的猜测值：let myGuess = guess.value 玩家在数字输入字段中输入的任何数字都将被分配给 checkGuess 函数中的 myGuess 变量。条件语句下一步是将玩家的猜测与游戏产生的随机数进行比较。你还想给玩家反馈，让他们知道他们的猜测是太高，太低还是正确。你可以使用一系列条件语句来决定玩家将收到的反馈。条件语句 在运行代码块之前检查是否满足条件。如果不满足条件，则代码停止，继续检查下一个条件，或者继续执行其余代码，而无需执行条件块中的代码：if (myGuess === randomNumber){ feedback.textContent = "You got it right!" } else if(myGuess > randomNumber) { feedback.textContent = "Your guess was " + myGuess + ". That's too high. Try Again!" } else if(myGuess < randomNumber) { feedback.textContent = "Your guess was " + myGuess + ". That's too low. Try Again!" } 第一个条件块使用比较运算符 === 将玩家的猜测与游戏生成的随机数进行比较。比较运算符检查右侧的值，将其与左侧的值进行比较，如果匹配则返回布尔值 true，否则返回布尔值 false。如果数字匹配（猜对了！），为了让玩家知道。通过将文本添加到具有 id 属性 feedback 的 标记中来操作 DOM。就像上面的 guess.value 一样，除了不是从 DOM 获取信息，而是更改其中的信息。 元素没有像 元素那样的值，而是具有文本，因此请使用 .textContent 访问元素并设置要显示的文本：feedback.textContent = "You got it right!" 当然，玩家很有可能在第一次尝试时就猜错了，因此，如果 myGuess 和 randomNumber 不匹配，请给玩家一个线索，以帮助他们缩小猜测范围。如果第一个条件失败，则代码将跳过该 if 语句中的代码块，并检查下一个条件是否为 true。 这使你进入 else if 块：else if(myGuess > randomNumber) { feedback.textContent = "Your guess was " + myGuess + ". That's too high. Try Again!" } 如果你将其作为句子阅读，则可能是这样的：“如果玩家的猜测等于随机数，请让他们知道他们猜对了。否则，请检查玩家的猜测是否大于 randomNumber，如果是，则显示玩家的猜测并告诉他们太高了。”最后一种可能性是玩家的猜测低于随机数。 要检查这一点，再添加一个 else if 块：else if(myGuess < randomNumber) { feedback.textContent = "Your guess was " + myGuess + ". That's too low. Try Again!" } 用户事件和事件监听器如果你看上面的代码，则会看到某些代码在页面加载时自动运行，但有些则不会。你想在玩游戏之前生成随机数，但是你不想在玩家将数字输入到数字输入字段并准备检查它之前检查其猜测。生成随机数并将其打印到控制台的代码不在函数的范围内，因此它将在浏览器加载脚本时自动运行。 但是，要使函数内部的代码运行，你必须对其进行调用。调用函数有几种方法。在此，你希望该函数在用户单击 “Check My Guess” 按钮时运行。单击按钮将创建一个用户事件，然后 JavaScript 可以 “监听” 这个事件，以便知道何时需要运行函数。代码的最后一行将事件侦听器添加到按钮上，以在单击按钮时调用函数。当它“听到”该事件时，它将运行分配给事件侦听器的函数：submitGuess.addEventListener('click', checkGuess) 就像访问 DOM 元素的其他实例一样，你可以使用按钮的 ID 告诉 JavaScript 与哪个元素进行交互。 然后，你可以使用内置的 addEventListener 函数来告诉 JavaScript 要监听的事件。你已经看到了带有参数的函数，但花点时间看一下它是如何工作的。参数是函数执行其任务所需的信息。并非所有函数都需要参数，但是 addEventListener 函数需要两个参数。它采用的第一个参数是将为其监听的用户事件的名称。用户可以通过多种方式与 DOM 交互，例如键入、移动鼠标，键盘上的 TAB 键和粘贴文本。在这种情况下，你正在监听的用户事件是单击按钮，因此第一个参数将是 click。addEventListener的第二个所需的信息是用户单击按钮时要运行的函数的名称。 这里我们需要 checkGuess 函数。现在，当玩家按下 “Check My Guess” 按钮时，checkGuess 函数将获得他们在数字输入字段中输入的值，将其与随机数进行比较，并在浏览器中显示反馈，以使玩家知道他们猜的怎么样。 太棒了！你的游戏已准备就绪。学习 JavaScript 以获取乐趣和收益这一点点的平凡无奇的 JavaScript 只是这个庞大的生态系统所提供功能的一小部分。这是一种值得花时间投入学习的语言，我鼓励你继续挖掘并学习更多。via: https://opensource.com/article/21/1/learn-javascript作者：Mandy Kendall 选题：lujun9972 译者：amwps290 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
通过编写一个简单的游戏学习 C 语言
当你学习一门新的编程语言时，这个“猜数字”游戏是一个很好的入门程序。下面是如何用 C 语言来编写它。我在小学时就开始 自学编程。我的第一个程序是在 Apple II 上编写的，但最终，我还是通过看书和编程练习学会了 C 语言。练习编程的最佳方法是编写示例程序，它能帮助你练习新知识。在我学习一种新的编程语言时，我喜欢编写一个简单的“猜数字”游戏来练习。电脑从 1 到 100 中随机挑选一个数字，你必须通过猜测来算出来。在另一篇文章中，我展示了如何用 Bash 语言编写这个“猜数字”游戏，我的同事也写了一些文章，介绍如何用 Java、Julia 和其他计算机语言编写它。“猜数字”游戏的伟大之处在于它践行了几个编程概念：如何使用变量、如何比较值、如何打印输出以及如何读取输入。整个夏天，我录制了一个系列视频，教人们如何用 C 语言编写程序。从那以后，我听到了很多人都在跟着它学习 C 语言编程的消息。所以，我想接着用 C 语言写一个“猜数字”的游戏。去取一个随机数从写一个函数来选择一个随机数字来开始“猜数字”游戏。在编写函数时，优秀的程序员会尽量使它们具有灵活性，这样他们就可以重用它们来解决略有不同的问题。因此，与其硬编码函数来选择 1 到 100 之间的一个随机数，不如编写函数来选择 1 到某个整数 maxval 之间的一个随机数：#include <stdio.h> #include <sys/random.h> int randnum(int maxval) { /* pick a random number from 1 to maxval */ int randval; getrandom(&randval, sizeof(int), GRND_NONBLOCK); /* could be negative, so ensure it's positive */ if (randval < 0) { return (-1 * randval % maxval + 1); } else { return (randval % maxval + 1); } } 该函数使用 Linux 的系统调用 getrandom 来生成一系列随机数。你可以在手册页中了解关于这个系统调用的更多信息，但请注意，getrandom 将用随机的 0 和 1 填充变量。这意味着最终值可以是正的，也可以是负的，因此你需要在之后进行测试，以确保 randnum 函数的结果是正值。编写程序你可以用这个函数来写你的“猜数字”程序:#include <stdio.h> #include <sys/random.h> int randnum(int maxval) { ... } int main(void) { int number; int guess; number = randnum(100); puts("Guess a number between 1 and 100"); do { scanf("%d", &guess); if (guess < number) { puts("Too low"); } else if (guess > number) { puts("Too high"); } } while (guess != number); puts("That's right!"); return 0; } 程序首先使用 randnum 函数从 1 到 100 之间选择一个随机数。在向用户输出一个提示后，程序进入一个 do-while 循环，以便用户可以猜测数字。在循环的每次迭代中，程序测试用户的猜测的数值。如果用户的猜测小于随机数，程序将输出“Too low”，如果猜测大于随机数，程序将输出“Too high”。循环继续，直到用户的猜测与随机数相同。当循环退出时，程序输出 “That's right!”，然后立即结束：$ gcc -o guess -Wall guess.c $ ./guess Guess a number between 1 and 100 50 Too high 30 Too low 40 Too low 45 Too high 42 Too low 43 Too low 44 That's right! 尝试动手在学习一门新的编程语言时，这个“猜数字”游戏是一个很好的入门程序，因为它以一种非常直接的方式练习了几个常见的编程概念。通过用不同的编程语言实现这个简单的游戏，你可以演示一些核心概念，并比较每种语言的细节。你有最喜欢的编程语言吗？你会如何用它来编写“猜数字”游戏呢？关注本系列文章，查看你可能感兴趣的其他编程语言的示例。via: https://opensource.com/article/21/1/learn-c作者：Jim Hall 选题：lujun9972 译者：qfzy1233 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出