轨道
/
Go
Go
/
练习
/
机器人模拟器
机器人模拟器

机器人模拟器

中等

说明

编写一个机器人模拟器。

一家机器人工厂的测试设施需要一个程序来验证机器人的移动。

机器人有三种可能的移动方式:

  • 向右转
  • 向左转
  • 前进

机器人被放置在一个假想的无限网格上,面朝某个特定的方向(北、东、南或西),并位于一组 {x,y} 坐标处,例如 {3,8},坐标向北和向东递增。

随后,机器人会收到若干条指令,此时测试设施会验证机器人的新位置,以及它面朝的方向。

  • 字母串“RAALAL”表示:
    • 向右转
    • 前进两次
    • 向左转
    • 前进一次
    • 再向左转一次
  • 假设一个机器人从 {7, 3} 出发,面朝北。 那么执行这串指令后,它应该停在 {9, 4},面朝西。

实现说明

测试分为 3 步。

使用 go test 运行所有测试,或者用 -tags 选项运行指定的测试。

示例:

go test                      # run all tests
go test -tags step1          # run just step 1 tests.
go test -tags 'step1 step2'  # run step1 and step2 tests

你会拿到源文件 defs.go,它定义了测试程序所需要的许多东西。这个文件按步骤分为三个部分。

第 1 步

要完成第 1 步,你需要定义 Right、Left、Advance、N、S、E、W 和 Dir。 完成第 1 步之后,再进入第 2 步。

第 2 步

在第 1 步里,你实现了机器人的移动,但这还算不上真正的模拟。比如,源代码里“机器人”在哪里?“网格”又在哪里?把机器人的动作转换成网格位置的运算在哪里,在机器人里,还是在网格里?物理世界可不是这样。

第 2 步引入了一个“房间”。这看起来只是个小改动,但我们会做大幅调整,来厘清“房间”“机器人”和“测试程序”各自的角色,并开始厘清这个模拟的物理规则。你要把 Room 和 Robot 定义为函数,测试程序把它们作为 goroutine 启动,从而“让它们诞生”。信息通过 Go channel 在测试程序、机器人和房间之间流动。

把 Room 看作一个“物理引擎”,它负责建模并模拟一个带墙壁和机器人的物理房间。它应当以某种方式对房间的坐标空间、机器人和墙壁的位置建模,并确保比如机器人不会穿墙。我们希望 Robot 是执行动作的代理,同时希望 Room 维护一致的事实。

测试程序创建 channel,并启动 Room 和 Robot。然后测试程序向 Robot 发送命令。命令发送完毕后,它会关闭命令 channel。Robot 必须接收命令,并把它正在尝试执行的动作告知 Room。当它感知到命令 channel 关闭时,必须自行关闭。房间必须解释机器人动作带来的物理后果。当它感知到机器人关闭时,会向测试程序发回一份最终报告,说明机器人的最终位置和方向。

第 3 步

第 3 步有三个重大变化:

  • 机器人运行脚本,而不是响应单条命令。
  • 日志 channel 让机器人和房间都能记录消息。
  • 房间允许多个机器人同时存在并发运行。

对于 Room3 发出的最终位置报告,你可以直接返回从 robots channel 收到的那个切片,只需更新其中的位置和方向。遇到以下情况时,必须在日志 channel 上发送消息:

  • 机器人没有名字
  • 机器人名字重复
  • 多个机器人被放在同一个位置
  • 机器人被放在房间外
  • 脚本中有未定义的命令
  • 来自未知机器人的动作
  • 机器人试图前进撞墙
  • 机器人试图前进撞上另一个机器人

来源

灵感来自一家知名公司的面试题。
通过 GitHub 编辑 链接将在新窗口或新标签页中打开
Go Exercism

准备好开始 机器人模拟器 了吗?

注册 Exercism,借助 34 个概念165 个练习 和真人导师指导,学习并掌握 Go,全部免费。