第一单元:笛卡尔坐标、moveXY 与 buildXY 基础

Unit 1: Cartesian Coordinates, moveXY & buildXY
对应关卡 · 边际森林 Border Forest · 平原森林保卫战 → 森林逃避

1.1 笛卡尔坐标系概述

Introduction to the Cartesian Coordinate System

1.1.1 坐标的起源(The Origin of Coordinates)

1.1.1.1 一个关于苍蝇的传说 A legend about a fly on the ceiling

CodeCombat 笛卡尔与天花板上的苍蝇 - codecombat.cn
图1:传说笛卡尔通过观察天花板上的苍蝇,想到了用两个数字定位的方法

在你踏入边际森林(Border Forest)之前,先听一个有趣的故事。三百多年前,法国数学家兼哲学家勒内·笛卡尔(René Descartes,1596–1650)有一天躺在床上,盯着天花板发呆。一只苍蝇在天花板上爬来爬去,他突然想到:我该怎样精确地描述这只苍蝇的位置呢?

他发现,只要说出苍蝇离左边墙有多远、离前面墙有多远,用两个数字就能唯一地确定它在天花板上的位置。这个看似简单的想法,最终发展成了改变数学历史的笛卡尔坐标系(Cartesian Coordinate System)

小历史:笛卡尔于 1637 年在他的著作《几何学》(La Géométrie)中发表了这个思想。"Cartesian(笛卡尔的)"这个词就来自他的名字。法国数学家费马(Fermat)也独立发现了类似的方法。

1.1.1.2 坐标系做了什么了不起的事 Why it was revolutionary

笛卡尔坐标系最伟大的贡献,是把几何(图形)代数(数字)连接了起来。在此之前,"形状"和"数字"是两个几乎不相干的世界。有了坐标系之后,一个点可以用一对数字表示,一条直线、一个圆都可以用方程描述。这门学问叫做解析几何(Analytic Geometry),它也是后来微积分诞生的基石。

而对你这位即将出发的英雄来说,坐标系还有一个更实在的用处:它能告诉你的英雄到底要走到哪里、在哪里建造围栏

1.1.2 为什么需要坐标(Why We Need Coordinates)

1.1.2.1 "向右走三步"的局限 The limitation of relative movement

在之前的暗影地牢里,你学过 hero.moveRight()hero.moveUp() 这样的相对移动方法——它们的意思是"相对当前位置,朝某个方向走"。这种方法在简单的关卡里很好用,但有两个明显的麻烦:

第一,当目标位置离你很远、路线很曲折时,你需要写一大堆移动指令,还得在脑子里一步步推算英雄当前面朝哪、走到了哪。第二,如果你想直接"瞬间锁定"地图上某个固定的位置(比如那棵特定的大树旁),相对移动就显得很笨拙了。

1.1.2.2 绝对坐标:给地图上每个点一个"门牌号" Absolute coordinates: an address for every point

CodeCombat 绝对坐标与相对移动对比 - codecombat.cn
图2:相对移动是"往那边走几步",绝对坐标是"去那个固定地址"

坐标的思路完全不同:它给地图上的每一个位置都分配一个固定的"门牌号",无论英雄当前站在哪里,这个门牌号都不会变。这种"基于固定参照系的位置"叫做绝对坐标(Absolute Coordinates)

有了门牌号,你就可以直接说:"英雄,去 (36, 59) 这个位置!"——而不用关心英雄现在站在哪。这正是本单元两个核心方法 moveXYbuildXY 的工作方式。

一句话记忆:相对移动是"往那边走几步",绝对坐标是"去那个固定地址"。

1.1.3 坐标与编程(Coordinates in Programming)

1.1.3.1 坐标无处不在 Coordinates are everywhere in computing

坐标系不只是数学课本里的东西,它是几乎所有计算机图形(Computer Graphics)的基础。你手机屏幕上的每一个像素、电子游戏里每个角色的位置、地图软件里的每个地点,背后都是一对对坐标在工作。学会用坐标思考,是你迈向更复杂编程的重要一步。

小提示:在屏幕和很多游戏里,y 轴有时是"向下为正"的。但在CodeCombat的边际森林地图中,遵循数学习惯:x 向右增大,y 向上增大

1.2 一维数轴

The One-Dimensional Number Line

1.2.1 数轴的定义(Definition of the Number Line)

1.2.1.1 一根带刻度的直线 A straight line with markings

在理解二维地图之前,我们先从最简单的一维数轴(Number Line)说起。数轴就是一根带方向、带刻度的直线。它上面的每一个点,都对应着一个数;反过来,每一个数,也都能在数轴上找到唯一的一个点。

-3 -2 -1 0 1 2 3 点 P (=2)
图3:一维数轴——原点为 0,向右为正,向左为负

1.2.2 数轴的三要素(Three Elements of a Number Line)

1.2.2.1 原点、正方向、单位长度 Origin, positive direction, unit length

一条完整的数轴必须有三样东西,缺一不可:

要素含义在图中的体现
原点(Origin)数轴的起点,代表 0标着 0 的那个点
正方向(Direction)规定哪边是"变大"的方向箭头指向的方向(通常向右)
单位长度(Unit)每一格代表多少相邻刻度之间的距离

原点右边是正数(1, 2, 3……),左边是负数(-1, -2, -3……)。这和你在暗影地牢里学过的"负数=反方向"是完全一致的道理。

1.2.3 数轴上的点(Points on the Number Line)

1.2.3.1 一个数字就能定位 One number locates a point

在一维数轴上,只需要一个数字就能确定一个点的位置。这就是"一维"的含义——只有一个方向、一个自由度。比如数字 2 就唯一对应数轴上原点右侧第二格的那个点。

💡 想一想:森林小路上的英雄

想象边际森林里有一条笔直的小路,英雄只能在这条路上前后移动。这时一条数轴就够用了:你告诉英雄"去 5 号位置",它就知道该走到哪。但真实的森林是一大片开阔地,英雄既能左右走、也能上下走——这就需要把一维数轴升级成二维坐标系了。

1.3 二维坐标系

The Two-Dimensional Coordinate System

1.3.1 从一维到二维(From 1D to 2D)

1.3.1.1 两条数轴的"交叉组合" Two number lines crossing

CodeCombat 从一维数轴到二维坐标系 - codecombat.cn
图4:把两条互相垂直的数轴组合在一起,就得到了二维坐标系

两条互相垂直的数轴放在一起,让它们在各自的原点处相交,就得到了二维坐标系(也叫平面直角坐标系)。其中一条水平放置,另一条竖直放置。这样一来,平面上的任何一个点都需要两个数字来描述:一个表示水平位置,一个表示竖直位置。

这就是边际森林地图的本质——它是一个铺满坐标的平面,地图上每一棵树、每一颗宝石、每一个食人魔的位置,都能用一对数字精确表示。

1.3.2 x 轴与 y 轴(The x-axis and y-axis)

1.3.2.1 水平的 x,竖直的 y Horizontal x, vertical y

两条轴各有名字:

x y O (2, 2) 第一象限 第二象限 第三象限 第四象限
图5:二维坐标系——x 向右、y 向上,原点 O 把平面分成四个象限

1.3.2.2 移动方法与坐标轴的关系 How movement relates to the axes

动作对坐标的影响
向右走(moveRight)x 值增大,y 不变
向左走(moveLeft)x 值减小,y 不变
向上走(moveUp)y 值增大,x 不变
向下走(moveDown)y 值减小,x 不变

1.3.3 原点与象限(Origin and Quadrants)

1.3.3.1 原点 (0, 0) The origin (0, 0)

两条轴相交的那个点叫做原点(Origin),它的坐标是 (0, 0)。原点是整个坐标系的"基准点",所有其他位置都是相对它来度量的。

1.3.3.2 四个象限 The four quadrants

两条轴把平面分成了四块区域,每一块叫做一个象限(Quadrant)。按照数学惯例,从右上角开始,逆时针依次编号为第一、二、三、四象限。第一象限里 x 和 y 都是正数——这也是CodeCombat地图最常用的区域。

好消息:在边际森林的关卡里,所有坐标都是正数(位于第一象限),所以你暂时不用担心负坐标。但理解象限的概念,会让你在更高级的地图里更从容。

1.3.4 CodeCombat的地图坐标(CodeCombat Map Coordinates)

1.3.4.1 地图就是一张大坐标纸 The map is a giant coordinate grid

CodeCombat 边际森林地图坐标网格 - codecombat.cn
图6:边际森林的每一关地图,本质上就是一张铺好的坐标纸

边际森林的每一关地图,本质上就是一张铺好的坐标纸。地图左下角附近接近原点,向右 x 增大、向上 y 增大。地图上常见的坐标范围大约从 0 到 80 不等。当你看到一个 X 标记或一颗宝石时,它都对应着一对确定的 (x, y) 坐标——你的任务,就是把这对坐标"喂"给 moveXYbuildXY 方法。

1.4 坐标 (x, y)

Coordinates (x, y)

1.4.1 有序数对(Ordered Pairs)

1.4.1.1 一对数字定位一个点 A pair of numbers locates a point

平面上一个点的位置,用一对写在圆括号里、用逗号隔开的数字表示,形如 (x, y)。数学上把它叫做有序数对(Ordered Pair)。"有序"两个字非常关键——它的意思是前后顺序不能调换,第一个数永远代表 x(水平),第二个数永远代表 y(竖直)。

💡 记忆口诀:先横后竖,先走廊后楼梯

读坐标时永远是"先 x 后 y"。一个经典的英文助记法是 "Walk along the hall, then up the stairs"——先沿着走廊走(横向 x),再爬楼梯上去(纵向 y)。坐标 (36, 59) 的意思就是:先到 x=36 的水平位置,再到 y=59 的竖直位置。

1.4.2 读写坐标(Reading and Writing Coordinates)

1.4.2.1 坐标的标准写法 Standard notation

坐标的标准写法是:圆括号 + 两个数字 + 中间一个逗号。例如 (40, 53)(8, 12)(66, 17)。在数学里它们带圆括号;而在 Python 代码里调用方法时,这两个数字会作为参数填进方法的括号中:hero.moveXY(40, 53)

数学写法含义Python 代码写法
(40, 53)x=40,y=53hero.moveXY(40, 53)
(8, 12)x=8,y=12hero.moveXY(8, 12)
(0, 0)原点hero.moveXY(0, 0)

1.4.3 顺序很重要(Order Matters)

1.4.3.1 (x, y) ≠ (y, x) (x, y) is not the same as (y, x)

CodeCombat 坐标顺序对比 (40,20) 与 (20,40) - codecombat.cn
图7:(40, 20) 和 (20, 40) 是地图上两个完全不同的位置

这是初学者最容易踩的坑:坐标里两个数字的顺序绝不能颠倒! (40, 20)(20, 40) 是地图上两个完全不同的位置。前者在偏右偏下,后者在偏左偏上。计算机严格按照"第一个数是 x、第二个数是 y"来理解,它不会替你纠错。

hero.moveXY(40, 20)   # ✓ 去 x=40, y=20 的位置
hero.moveXY(20, 40)   # ✗ 完全不同的位置!x=20, y=40
牢记:坐标是"有序"数对——x 在前,y 在后,顺序写反了,英雄就走错了地方。

1.4.4 悬停查看坐标(Hover to See Coordinates)

1.4.4.1 把鼠标移到地图上 Mouse over the map

CodeCombat 鼠标悬停查看坐标 - codecombat.cn
图8:把鼠标悬停在地图任意位置,即可看到该处的 x 和 y 坐标

你怎么知道一个目标的坐标是多少?非常简单:把鼠标悬停在地图上的任意位置,CodeCombat就会显示出那个位置的 x 和 y 坐标。 这是边际森林里你最常用的小技巧——想让英雄去哪、想在哪建围栏,先把鼠标移过去看一眼坐标,再把数字填进代码里。

实用流程:① 鼠标悬停目标位置 → ② 记下显示的 (x, y) → ③ 写进 moveXY(x, y)buildXY("类型", x, y) → ④ 运行检查。

1.5 buildXY 建造方法

The buildXY Method

1.5.1 buildXY 语法(Syntax of buildXY)

1.5.1.1 在指定坐标建造物体 Build something at a given coordinate

buildXY 是边际森林里你学到的第一个使用坐标的方法。它的作用是:在地图上你指定的 (x, y) 坐标处,建造一个物体(比如围栏)。它的基本语法是:

hero.buildXY("建造物类型", x, y)

1.5.2 三个参数详解(The Three Arguments)

1.5.2.1 类型 + x + y Type + x + y

buildXY 需要三个参数,按顺序分别是:

位置参数类型说明
第 1 个"fence"字符串(带引号)要建造的东西,如围栏"fence"
第 2 个40数字建造位置的 x 坐标
第 3 个53数字建造位置的 y 坐标

注意第一个参数是字符串——它表示"建什么",必须用引号括起来(单引号或双引号都行);后两个是数字——表示"建在哪",不加引号。三个参数之间用逗号分隔。

hero.buildXY("fence", 40, 53)
#         ^类型(字符串)  ^x   ^y
小提示:在森林保卫战里,建造 "fence"(围栏)类型比建造 "fire-trap"(火焰陷阱)类型容易得多——围栏直接挡住敌人,简单又可靠。

1.5.3 实战:平原森林保卫战(Plains Forest Defense)

1.5.3.1 用两段围栏保护村庄 Protect the village with two fences

CodeCombat 平原森林保卫战关卡 - codecombat.cn
图9:在两个 X 标记处建造围栏,堵住食人魔来袭的缺口

在"平原森林保卫战"中,食人魔从两个缺口来袭。你需要在两个 X 标记处分别建造一段围栏来堵住它们。把鼠标悬停在 X 标记上,得到坐标,然后写下:

# 在标记上建造两段围栏来保护村民。
# 把鼠标悬停在地图上,以得到 x, y 坐标。
hero.buildXY("fence", 40, 53)
hero.buildXY("fence", 40, 21)

注意这两段围栏的 x 坐标都是 40(在同一条竖直线上),只是 y 坐标不同(一个 53、一个 21)——一个堵上方缺口,一个堵下方缺口。这正体现了坐标系的威力:同一个 x、不同的 y,就是竖直方向上的两个不同位置

1.6 moveXY 移动方法

The moveXY Method

1.6.1 moveXY 语法(Syntax of moveXY)

1.6.1.1 移动到任意坐标 Move to any coordinate

buildXY 一样,moveXY 也使用坐标,但它的作用是让英雄移动到地图上任意一个 (x, y) 位置。它只需要两个参数:目标的 x 和 y。

hero.moveXY(x, y)

# 例如:移动到 x=36, y=59 的位置
hero.moveXY(36, 59)

1.6.2 moveXY 与 moveRight 对比(moveXY vs. moveRight)

1.6.2.1 绝对定位 vs 相对移动 Absolute positioning vs. relative movement

还记得暗影地牢里那双"又老又单一"的 moveRight 鞋子吗?现在你的新装备能让你用 moveXY 直接到达任何想去的地方。两者的核心区别在于:

对比项moveRight() 等moveXY(x, y)
定位方式相对当前位置地图绝对坐标
参数含义步数(走几格)目标的 x 和 y
方向只能上下左右单方向可斜着直奔目标
适合场景简单的直线小步远距离、精确定位
类比:moveRight(3) 像是对司机说"往前开三个路口";moveXY(36, 59) 像是直接输入导航地址"去 36 号大街 59 号"。

1.6.3 内置寻路(Built-in Pathfinding)

1.6.3.1 英雄会自己找路 The hero finds its own way

moveXY 还内置了一个很贴心的功能:寻路(Pathfinding)。这意味着只要你给出目标坐标,英雄会自动规划一条路线走过去,必要时还会绕开途中的障碍物。你不必再手动一格一格地指挥它——只管告诉它"终点在哪"就好。

1.6.4 实战:蜿蜒小径(Winding Trail)

1.6.4.1 依次移动并建造围栏 Move through waypoints, then build

在"蜿蜒小径"中,你要带着英雄穿过森林、依次移动到几个目标点,最后在路的尽头建一道围栏挡住食人魔。每到一个目标,就把鼠标悬停查看坐标,写一行 moveXY

# 到小路的尽头去,并在那儿修一个栅栏。
# 利用你的 moveXY(x, y) 坐标移动功能。
hero.moveXY(36, 59)
hero.moveXY(37, 12)
hero.moveXY(66, 17)
hero.buildXY("fence", 71, 24)

仔细观察这几行:英雄先到 (36, 59),再到 (37, 12)——注意 y 从 59 大幅降到 12,说明它向走了一大段;接着到 (66, 17),x 大幅增大,说明向走了一大段。代码依然是顺序执行的:一行走完,才走下一行。

1.7 坐标的修改与调试

Editing Coordinates and Debugging

1.7.1 修改坐标避开陷阱(Edit Coordinates to Avoid Traps)

1.7.1.1 代码是可以修改的 Code can be changed

CodeCombat 一步走错关卡——避开地雷 - codecombat.cn
图10:默认代码是食人魔写的,修改坐标让英雄避开地雷、收集宝石

在"一步走错"这一关里,默认代码是食人魔写的——它故意把坐标设成会让英雄踩中地雷的位置!你的任务是修改这些坐标,把英雄引到每一颗宝石那里,安全地走完全程。这一关传递了一个重要观念:示例代码不是命运,你完全可以也应该去修改它。

# 英雄完全糊涂了!
# 纠正路径,别让其踩到地雷。
hero.moveXY(11, 35)
hero.moveXY(35, 24)
hero.moveXY(40, 55)
hero.moveXY(77, 57)
通关要点:你必须拿到每一颗宝石才能过关。所以修改坐标时,要让英雄的路线刚好经过所有宝石。

1.7.2 收集路线规划(Planning a Collection Route)

1.7.2.1 用坐标差判断方向和距离 Use coordinate differences to plan

规划收集路线时,比较相邻两个坐标点,你就能预判英雄怎么走:x 增大表示向右,x 减小表示向左;y 增大表示向上,y 减小表示向下。在"宝石果子"概念挑战中,你要依次收集所有宝石、最后进入村庄(红色 X)。注意路线里有些坐标会重复出现——这是因为英雄需要"原路返回"经过某个安全的交叉点,再前往下一颗宝石:

# 移动到所有宝石处,然后移动到红色 X 标记。
hero.moveXY(8, 48)
hero.moveXY(8, 12)
hero.moveXY(12, 26)
hero.moveXY(24, 26)
hero.moveXY(34, 14)
hero.moveXY(24, 26)   # 回到交叉点
hero.moveXY(40, 56)
hero.moveXY(74, 34)   # 进入村庄(红色 X)

1.8 循环初步与坐标

A First Look at Loops with Coordinates

1.8.1 while True 循环(The while True Loop)

1.8.1.1 让一组动作不停重复 Repeating a set of actions forever

到目前为止,你的代码都是"每行执行一次"的顺序结构。但有时候你希望一段动作不停地重复。这时就用到 while True: 循环——它的意思是"永远重复下面缩进的这些代码"。

💡 缩进的重要性

注意 while True: 后面有个冒号,下一行开始的代码要向右缩进(通常 4 个空格)。缩进的代码才"属于"这个循环、会被反复执行。这是 Python 用缩进表示代码层级的独特设计——别忘了缩进!

1.8.2 实战:森林逃避(Forest Escape)

1.8.2.1 用循环绕圈躲避猎头者 Loop around to dodge the headhunter

致命的猎头者正盯着英雄的脑袋!只要它看不到你,就没法攻击你。解决办法是用 while True 循环,让英雄在森林里沿着一圈坐标不停地跑动,始终保持移动、不被锁定:

# 区域内有一名猎头者!
# 在森林附近跑动,以躲避他的视线。
while True:
    hero.moveXY(56, 44)
    hero.moveXY(40, 56)
    # 用 moveXY 在森林中保持移动,以确保存活。
    # 不要忘记缩进。
    hero.moveXY(24, 44)
    hero.moveXY(24, 24)
    hero.moveXY(40, 12)
    hero.moveXY(56, 24)

这六个坐标点围成了一个大致的环形路线。英雄跑完最后一个点 (56, 24) 后,循环又会从头开始回到 (56, 44),如此周而复始,绕圈奔跑——猎头者永远抓不住一个不停移动的目标!

观察:把这六个坐标在脑中连成线,你会发现它们围出了一个闭合的圈。这就是"路径规划"和"坐标"结合的巧妙之处。

本单元小结 ✨

恭喜你完成了边际森林第一单元!你已经从"相对移动"升级到了"坐标定位",掌握了用一对数字精确指挥英雄的能力。来回顾一下核心概念:

核心概念关键点对应关卡
笛卡尔坐标系笛卡尔发明,连接几何与代数
一维数轴原点、正方向、单位长度
二维坐标系x 轴水平、y 轴竖直、四象限全部
坐标 (x, y)有序数对,x 在前 y 在后全部
悬停查坐标鼠标移到地图即可看坐标全部
buildXYbuildXY("fence", x, y)平原森林保卫战
moveXYmoveXY(x, y),自带寻路蜿蜒小径
修改坐标调试纠正路径、避开陷阱一步走错
收集路线规划依次经过所有目标宝石果子
while True 循环重复动作,注意缩进森林逃避

现在你已经能给森林里的每个位置"指路"了。继续加油,勇敢的英雄!🌲🗡️

CodeCombat 编程知识 · 边际森林:第一单元

CodeCombat教研团队