标签 猜数字 下的文章

以下是一个简单的编程项目,能够帮助你开始学习 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 执行。接下来,创建了几个全局变量。这里我使用全部大写字母定义全局变量,这些变量将绑定到跟踪这些值的窗口小部件(LOWHIGH等等)。

全局变量 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 之外以及已经被用户猜过的值。有效的猜测和随机值进行比较。LOWHIGH 的猜测会被追踪,作为 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 选项监控给定的变量,并自动更新标签的值,这展示了全局变量 LOWHIGHSTATUS 的绑定。

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 来展示如何玩这个游戏:

用 Wish 编写的猜数游戏

进一步了解 Tcl

Tcl 支持命名空间的概念,所以在这里使用的变量并不必须是全局的。你可以把绑定的部件变量组织进不同的命名空间。对于像这样的简单程序,可能并不太需要这么做。但对于更大规模的项目,你可能会考虑这种方法。

proc check_guess 函数体内有一行 global 代码我之前没有解释。在 Tcl 中,所有变量都按值传递,函数体内引用的变量的范围是局部的。在这个情况下,我希望修改的是全局变量,而不是局部范围的版本。Tcl 提供了许多方法来引用变量,在执行堆栈的更高级别执行代码。在一些情况下,像这样的简单引用可能带来一些复杂性和错误,但是调用堆栈的操作非常有力,允许 Tcl 实现那些在其他语言中实现起来可能较为复杂的新的条件和循环结构。

最后,在这篇文章中,我没有提到几何管理器,它们用于以特定的顺序展示部件。只有被某种几何管理器管理的部件才能显示在屏幕上。grid 管理器相当简洁,它按照从左到右的方式放置部件。我使用了五个 grid 定义来创建了五行。另外还有两个几何管理器:place 和 pack。pack 管理器将部件围绕窗口边缘排列,而 place 管理器允许固定部件的位置。除这些几何管理器外,还有一些特殊的部件,如 canvastextpanedwindow,它们可以容纳并管理其他部件。你可以在经典的 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中国 荣誉推出

这个 "猜数字 "游戏是学习新编程语言的一个很好的入门程序,因为它以一种相当直接的方式锻炼了几个常见的编程概念。

当你想 学习一种新的编程语言 时,把注意力放在编程语言的共同点上是很好的:

  • 变量
  • 表达式
  • 语句

这些概念是大多数编程语言的基础。一旦你理解了它们,你就可以开始琢磨其他的东西了。因为编程语言通常有相似之处,一旦你知道一种语言,你就可以通过了解其差异来学习另一种语言的基础知识。

学习新语言的一个好方法是用一个标准程序进行练习。这使你能够专注于语言,而不是程序的逻辑。在这个系列文章中,我使用了一个“猜数字”的程序,在这个程序中,计算机在 1 到 100 之间挑选一个数字,并要求你猜出来。程序循环进行,直到你猜对数字为止。

这个程序锻炼了编程语言中的几个概念:

  • 变量
  • 输入
  • 输出
  • 条件判断
  • 循环

这是一个学习新的编程语言的很好的实践实验。

安装 Ada

Ada 编程语言 是一种独特的、高度结构化的语言,有专门一群开发者使用它。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_IONumerics.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 种编程语言。

 title=

当我开始学习一种新的编程语言时,会把重点放在定义变量、书写声明以及计算表达式,一旦对这些概念有一个大致的了解,通常就能够自己弄清剩下的部分。大多数编程语言都具有相似性,所以如果你掌握了一种编程语言,学习下一种语言的重点就是弄清楚独有的概念以及区分不同。

我喜欢写一些测试程序来帮助练习新的编程语言。其中我经常写的是一个叫做“猜数字”的小游戏,计算机选出 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)

循环进行直到我猜出该随机数字

循环通常是用控制流程来实现的,如 whiledo-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 语言编写 “猜数字” 游戏:

其他语言:


via: 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 &lt; randomNumber) {
    10            printf "too low, try again:"
    11        } else if (guess &gt; 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-elsewhile 这样的语句中,thenelsewhile 部分接受一个语句或一组被 {} 包围的语句。然而,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) &lt; randomNumber {
     8        printf "too low, try again: "
     9    }
    10    int($0) &gt; 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 &lt; randomNumber {
    11        printf "too low, try again: "
    12    }
    13    guess &gt; 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 的 printprintf 函数来将内容写入输出
  • 条件判断 —— 我们已经学习了 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 是在打孔卡时代编写的语言,因此它的语法非常有限。但你仍然可以用它编写有用和有趣的程序。

 title=

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*
  • 只有字符 AZ(大写字母)、09(数字)和特殊字符 = + - * / ( ) , . $ ' : 和空格能够使用。

虽然有这些限制,你仍然可以编写非常有用和有趣的程序。

在 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 不支持更现代的编程语言中可用的 whiledo-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中国 荣誉推出