第一单元:对象、方法、参数与数据类型基础

Unit 1: Objects, Methods, Arguments & Fundamental Data Types
对应关卡 Level 1–6 | 暗影地牢 Kithgard Dungeon

1.1 计算机程序与编程概述

Introduction to Computer Programs and Programming

1.1.1 什么是程序(What is a Program)

1.1.1.1 程序的定义:一组指令的有序集合 A program is an ordered collection of instructions

CodeCombat 程序的定义示意图 - codecombat.cn
图1:程序就像一份行动清单,英雄按照清单逐条执行

想象一下,安雅(Anya)站在 Kithgard 地牢的入口,前方是一条布满尖刺的走廊。她很聪明,但她不会自己行动——她需要你告诉她怎么走。

程序(Program),就是你写给计算机(或英雄)的一份"行动清单"。这份清单里的每一行,都是一条明确的指令,按照从上到下的顺序排列好。计算机会忠实地按照这个顺序,一条一条地执行。

就好比你给朋友写一张纸条:

hero.moveRight()
hero.moveDown()
hero.moveRight()

这三行代码就是一个完整的程序。它简单、明确、有序——这就是程序最本质的样子。

一句话记忆:程序 = 一组按顺序排列的指令集合。
One-liner: A program is an ordered collection of instructions.

1.1.1.2 程序的执行方式:逐行顺序执行 Programs execute line by line in sequence

CodeCombat 逐行执行示意图 - codecombat.cn
图2:程序像读书一样从第一行读到最后一行

计算机执行程序时,就像读一本书一样——从第一行开始,一行一行往下读,读完一行、做完一行,再去读下一行。

当安雅收到上面那三行指令时:

她绝不会跳过某一行,也不会先做第 3 行再做第 1 行。这种"从头到尾、逐行执行"的方式,就是顺序执行(Sequential Execution)

小提示:如果你把第 2 行和第 3 行的顺序调换,安雅走的路就完全不一样了——可能还会撞上尖刺!顺序很重要。

1.1.1.3 程序与计算机的关系 Relationship between programs and computers

CodeCombat 程序与计算机关系图 - codecombat.cn
图3:没有程序的计算机就像没有乐谱的钢琴

计算机本身其实是个"听话但不会思考"的家伙。它跑得飞快、算得精准,但有一个问题:它不知道自己该做什么

程序就是告诉计算机"该做什么"的东西。没有程序的计算机,就像没有乐谱的钢琴——钢琴再好,也发不出曲子。

在 CodeCombat 的世界里:

你就是那个写乐谱的作曲家!

1.1.1.4 源代码与可执行代码 Source code vs. executable code

CodeCombat 源代码与可执行代码对比 - codecombat.cn
图4:源代码经过解释器翻译后,计算机才能理解

你在编辑器里写的那些文字——hero.moveRight() 之类的——叫做源代码(Source Code)。源代码是给人看的,用人类能读懂的编程语言写成。

但计算机的"母语"其实是由 0 和 1 组成的机器语言。所以在你点击"运行"按钮后,背后会有一个翻译官把你的 Python 代码翻译成计算机能理解的指令——这个翻译后的东西就是可执行代码(Executable Code)

不过别担心!在 CodeCombat 和大多数 Python 开发中,这个翻译过程是全自动的。你只需要专注于写好源代码,剩下的交给 Python 解释器就好。

概念类比说明
源代码 Source Code你写的中文菜谱人类可读的指令
可执行代码 Executable Code厨师实际的操作计算机能理解的指令
解释器 Interpreter翻译官把源代码翻译给计算机

1.1.2 什么是编程(What is Programming)

1.1.2.1 编程的定义:编写计算机指令的过程 The process of writing instructions for a computer

CodeCombat 编程过程示意图 - codecombat.cn
图5:编程的四步循环——想、写、测、改

编程(Programming)就是把你脑子里的想法——"我要让安雅走到宝石那里"——翻译成计算机能执行的代码的过程。

编程的核心步骤是:

恭喜!当你在 Kithgard 地牢的第 1 关写下第一行 hero.moveRight() 并点击运行时,你就已经在编程了!

1.1.2.2 编程语言的作用 The role of programming languages

CodeCombat 编程语言作为桥梁 - codecombat.cn
图6:编程语言是人类与计算机之间的桥梁

人类说中文、英文、法文……计算机只懂 0 和 1。编程语言就是人类和计算机之间的"桥梁语言"。

编程语言有很多种(就像人类语言有很多种一样),比如 PythonJavaScriptJavaC++ 等等。它们各有特色,但都是为了同一个目的:让人类能方便地写出计算机能执行的指令。

在 CodeCombat 中,你使用的是 Python 语言。

1.1.2.3 Python 作为编程语言的特点 Python as a programming language

CodeCombat Python语言特点 - codecombat.cn
图7:Python——初学者最友好的编程语言之一

为什么我们选择 Python?因为它是对初学者最友好的编程语言之一:

看看这段 Python 代码有多自然:

hero.moveRight()
hero.moveDown()
hero.moveRight()

即使你从没学过编程,也大概能猜到它的意思——让英雄向右走、向下走、再向右走。

1.1.2.4 编程与问题解决 Programming and problem solving

CodeCombat 编程与问题解决 - codecombat.cn
图8:编程的核心是解决问题——理解、设计、编写、验证

编程不仅仅是"打字"——它的核心是解决问题(Problem Solving)

在第 3 关"幽影守卫"中,安雅不能直接冲过去,因为食人魔矮人挡在路上。你需要想出一条绕开它的路线,然后用代码实现这个计划。

这个过程就是:

编程教会你的不只是 Python 语法,更是一种系统化思考和解决问题的能力。这种能力在任何领域都有用!

1.1.3 编程环境(Programming Environment)

1.1.3.1 代码编辑器 Code editor

CodeCombat 代码编辑器界面 - codecombat.cn
图9:CodeCombat的代码编辑器位于游戏画面右侧

代码编辑器(Code Editor)是你写代码的地方。在 CodeCombat 中,它位于游戏画面的右侧。

代码编辑器和普通的文字处理软件(比如 Word)不同:

小技巧:在第 5b 关"健忘的宝石匠"中,你可以输入 r,然后按回车来自动补全 moveRight() 命令,写代码更快!

1.1.3.2 运行/执行按钮 Run/Execute button

CodeCombat 运行按钮示意 - codecombat.cn
图10:点击运行,英雄就会按照你的代码行动

写好代码后,点击"运行"按钮,你的代码就会开始执行。在 CodeCombat 中:

1.1.3.3 输出与反馈 Output and feedback

CodeCombat 输出与反馈示意 - codecombat.cn
图11:英雄的行为就是你的代码的可视化输出

当程序运行后,你能看到执行结果——这就是"输出"。

在 CodeCombat 中,输出是可视化的:你能看到英雄在地图上移动、是否撞到障碍物、任务是否完成。

在传统 Python 编程中,输出通常是文字信息,通过 print() 函数显示在屏幕上。不过在 CodeCombat 的早期关卡中,你的"输出"就是英雄的行为——这让学习变得直观又有趣!

1.1.3.4 集成开发环境 IDE 简介 Introduction to Integrated Development Environment

CodeCombat IDE简介 - codecombat.cn
图12:CodeCombat 界面就是一个简化版的 IDE

CodeCombat 的界面其实就是一个简化版的 IDE(集成开发环境,Integrated Development Environment)

一个 IDE 通常包含:代码编辑器(写代码)、运行按钮(执行程序)、输出区域(显示结果)、调试工具(帮你找错误,比如 CodeCombat 中的回放进度条)。

常见的 Python IDE 有:PyCharm、VS Code、IDLE(Python 自带)等。CodeCombat 把这些功能包装在了一个游戏界面里,让你边玩边学。核心流程是一样的:写代码 → 运行 → 查看结果 → 修改 → 重复

1.2 对象与方法

Objects and Methods

1.2.1 对象的概念(The Concept of Objects)

1.2.1.1 对象的定义:具有属性和行为的实体 An entity with attributes and behaviors

CodeCombat 对象的定义 - codecombat.cn
图13:对象 = 属性(特征)+ 方法(本领)

在编程世界里,对象(Object)是一个核心概念。简单来说,对象就是一个"东西"——一个拥有特征本领的东西。

在 CodeCombat 中,hero(英雄)就是一个对象。让我们看看塔林(Tharin)有什么:

类别举例
属性(特征)生命值、速度、位置
方法(本领)向右走、向左走、向上走、向下走

对象 = 属性 + 方法,就是这么简单!

1.2.1.2 对象的类比:现实世界中的事物 Real-world analogy of objects

CodeCombat 现实世界中的对象类比 - codecombat.cn
图14:猫、手机、英雄——都是对象!

其实你身边到处都是"对象"!来看几个例子:

一只猫

一部手机

游戏中的英雄塔林

看出规律了吗?任何有特征、会做事的东西,在编程中都可以被看作一个"对象"。

1.2.1.3 Python 中一切皆对象 Everything in Python is an object

CodeCombat Python中一切皆对象 - codecombat.cn
图15:在 Python 中,数字、字符串、英雄……全都是对象

Python 有一个很酷的设计哲学:一切皆对象(Everything is an object)

不仅仅是英雄是对象——数字 3 是对象、字符串 "Hello" 是对象、甚至你写的函数也是对象。

不过现在你只需要记住一个对象就好:hero——你在 CodeCombat 中的英雄。其他的以后慢慢认识!

1.2.1.4 对象的标识符/名称 Object identifier/name,如 hero

CodeCombat 对象的名称hero - codecombat.cn
图16:无论选择安雅还是塔林,在代码中都叫 hero

每个对象都需要一个名字(标识符 / Identifier),这样我们才能在代码中引用它。

在 CodeCombat 中,你的英雄的名字就是 hero。无论你选择安雅还是塔林,在代码中都用 hero 来称呼他们。

hero.moveRight()   # "hero" 就是对象的名字

就像你在教室里喊"塔林,向右走!"一样,在代码里你写 hero.moveRight() 就是在对英雄下达指令。

注意:hero 这个名字是 CodeCombat 预先设定好的,不能随便改。

1.2.1.5 对象的属性 Object attributes/properties

CodeCombat 对象的属性 - codecombat.cn
图17:属性描述对象"是什么样的"

属性(Attributes / Properties)描述了对象"是什么样的"——它的特征、状态、数据。

英雄的属性例如:当前生命值、当前位置(在地图上的哪个格子)、移动速度。

虽然在前 6 关中我们不需要直接读取属性值,但了解它们的存在很重要:属性是对象携带的信息

1.2.1.6 对象的行为/动作 Object behaviors/actions

CodeCombat 对象的行为 - codecombat.cn
图18:方法是对象能执行的动作

行为(Behaviors)描述了对象"会做什么"——它能执行的动作。在编程中,我们把对象的行为叫做方法(Method)

在第 1–6 关中,英雄能做的动作是四个方向的移动:moveRight()moveLeft()moveUp()moveDown()

1.2.2 方法的概念(The Concept of Methods)

1.2.2.1 方法的定义:对象能执行的动作 Actions that an object can perform

CodeCombat 方法的定义 - codecombat.cn
图19:对象是"谁",方法是"做什么"

方法(Method)是附属于对象的一段可执行代码,代表对象能够执行的一个动作。

当你写 hero.moveRight() 时:

翻译成人话就是:"嘿英雄,请向右移动!"

1.2.2.2 方法与函数的关系 Relationship between methods and functions

CodeCombat 方法与函数的关系 - codecombat.cn
图20:方法是属于对象的函数

你可能会在学习中听到两个词:方法(Method)函数(Function)。它们非常相似,核心区别是:

类比:

在 CodeCombat 中,moveRight()hero 的方法——只有英雄能做这个动作。

1.2.2.3 方法的调用/执行 Calling/invoking a method

CodeCombat 调用方法 - codecombat.cn
图21:调用方法就像呼唤英雄去做某件事

写下一个方法并让它执行,叫做调用方法(Calling a method)

hero.moveRight()  # 调用 moveRight 方法

当 Python 读到这一行时,它会:① 找到 hero 这个对象 → ② 在 hero 身上找到 moveRight 这个方法 → ③ 执行这个方法(让英雄向右移动)。

1.2.2.4 方法调用的语法:圆括号 () Syntax of method calls: parentheses

CodeCombat 圆括号的重要性 - codecombat.cn
图22:圆括号的意思是"现在就做!"

注意到方法名后面那对圆括号 () 了吗?它非常重要!

hero.moveRight()   # ✓ 正确:有括号,调用方法
hero.moveRight     # ✗ 错误:没括号,不执行

圆括号的意思是:"现在就做!"。把它想象成按门铃——moveRight 是门铃按钮本身,moveRight() 是按下门铃的动作。

牢记:没有那对括号,方法就不会执行。这是初学者常见的坑!

1.2.2.5 方法的命名规范 Method naming conventions

CodeCombat 方法命名规范 - codecombat.cn
图23:好的方法名一看就知道它做什么

在 CodeCombat 中,方法名使用驼峰命名法(camelCase):第一个单词小写,后面每个单词首字母大写。

方法名命名分析
moveRightmove(移动)+ Right(右边)→ 向右移动
moveLeftmove(移动)+ Left(左边)→ 向左移动
moveUpmove(移动)+ Up(上面)→ 向上移动
moveDownmove(移动)+ Down(下面)→ 向下移动

好的方法名本身就能告诉你它做什么——代码像读英语一样自然。

CodeCombat 方法命名规范1 - codecombat.cn
图24:蛇形命名法与驼峰命名法对比

小知识:Python 官方推荐函数和方法使用 snake_case(蛇形命名法,如 move_right),但 CodeCombat 使用了 camelCase(驼峰命名法,如 moveRight)。两种风格都很常见,关键是在同一个项目中保持一致。

1.2.2.6 内置方法与自定义方法 Built-in methods vs. custom methods

CodeCombat 内置方法 - codecombat.cn
图25:内置方法是游戏已经写好的,直接用就行

在 CodeCombat 中,四个移动方法都是内置方法(Built-in Methods)——游戏已经帮你写好了,你直接用就行。在未来的学习中,你还会学到如何自己创建方法。

1.2.3 点表示法(Dot Notation)

1.2.3.1 点表示法的语法:对象.方法() Syntax: object.method()

CodeCombat 点表示法语法 - codecombat.cn
图26:点表示法——对象 + 点 + 方法 + 括号

点表示法(Dot Notation)是 Python 中让对象做事情的方式:

hero.moveRight()
# ^      ^         ^
# 对象   点号     方法()

1.2.3.2 点号 . 的含义:访问对象的成员 The dot means "access a member of"

CodeCombat 点号的含义 - codecombat.cn
图27:点号 = "的"——表示方法属于这个对象

那个小小的 . 的意思是"的"——就像中文里的"的"或英文里的 's

1.2.3.3 点表示法的读法 How to read dot notation

CodeCombat 如何读点表示法 - codecombat.cn
图28:三种读法——正式、口语、英文

当你看到 hero.moveRight() 时,可以这样读:

1.2.3.4 链式调用的概念 Concept of method chaining,初步了解

CodeCombat 链式调用概念 - codecombat.cn
图29:链式调用——多个点号连在一起(未来会学到)

在某些编程场景中,你可以把多个点号连在一起用,像一串链条——这叫链式调用(Method Chaining)。虽然前 6 关不会用到,先知道这个概念存在就好。

1.2.3.5 实例:hero.moveRight() Example: hero.moveRight()

CodeCombat hero.moveRight()拆解 - codecombat.cn
图30:将 hero.moveRight() 拆解为四个部分
部分含义类比
hero要行动的对象"安雅"
."安雅动作"
moveRight方法名:向右移动"向右走"
()执行这个方法"现在就做!"

1.2.3.6 实例:hero.moveDown() Example: hero.moveDown()

CodeCombat 第1关解法示例 - codecombat.cn
图31:第1关 Kithgard 地牢——三行代码拿到宝石

在第 1 关 "Kithgard 地牢"中,塔林需要先向右走,再向下走,最后向右走到宝石处:

hero.moveRight()   # 第1步:向右走,避开入口处的尖刺
hero.moveDown()    # 第2步:向下走到安全通道
hero.moveRight()   # 第3步:向右走到宝石处!

1.2.4 常用移动方法(Common Movement Methods)

1.2.4.1 hero.moveRight() —— 向右移动 Move right

CodeCombat moveRight方法 - codecombat.cn
图32:moveRight() 让英雄向右移动一格

让英雄向移动一个格子。地面上的小瓷砖就是移动的单位——每次调用 moveRight() 英雄就移动到右边下一个瓷砖的位置。

1.2.4.2 hero.moveLeft() —— 向左移动 Move left

CodeCombat moveLeft方法 - codecombat.cn
图33:moveLeft() 让英雄向左移动——有时退一步是为了更好地前进

让英雄向移动一个格子。在第 3b 关"狭路相逢"中,moveLeft() 用来"退回去"配合时机:

hero.moveRight()    # 先探一步
hero.moveLeft()     # 退回来!等矮人走开
hero.moveRight(2)   # 趁机快速冲过去

1.2.4.3 hero.moveUp() —— 向上移动 Move up

CodeCombat moveUp方法 - codecombat.cn
图34:moveUp() 让英雄向上移动一格

让英雄向移动一个格子。在第 2 关"深藏的宝石"中需要向上走两步:

hero.moveUp()    # 向上走一步
hero.moveUp()    # 再向上走一步(到达顶端)

1.2.4.4 hero.moveDown() —— 向下移动 Move down

CodeCombat moveDown方法 - codecombat.cn
图35:moveDown() 让英雄向下移动一格

让英雄向移动一个格子。这四个方向的方法构成了英雄在二维地图上移动的基础,就像遥控器上的上下左右四个按钮。

1.2.4.5 方法执行的效果与反馈 Effect and feedback of method execution

CodeCombat 方法执行的反馈 - codecombat.cn
图36:每条语句执行后都能看到英雄的行为变化

每次你调用一个移动方法后:英雄会可视地在地图上移动一步;移动需要一小段时间(不是瞬移);英雄必须移动完毕后,才会执行下一行代码。

如果安雅走到了你不期望的位置,那说明某行代码有问题——这时候可以拖动下方的回放进度条,看看她是在哪一步走错的。

1.2.4.6 多次调用相同方法 Calling the same method multiple times

CodeCombat 多次调用相同方法 - codecombat.cn
图37:重复调用同一方法——写几次就走几步

在第 4 关"细心脚步"中,路线更复杂,你需要大量重复调用移动方法(12 行代码!)。有点累对吧?别急,下面的"参数"就是来解决这个问题的!

1.3 参数

Arguments / Parameters

1.3.1 参数的概念(The Concept of Arguments)

1.3.1.1 参数的定义:传递给方法的附加信息 Additional information passed to a method

CodeCombat 参数的定义 - codecombat.cn
图38:参数就是给方法的"补充说明"

参数(Argument)是你在调用方法时,额外提供给它的信息,放在圆括号里面。

打个比方:

1.3.1.2 参数(Argument)与形参(Parameter)的区别 Argument vs. Parameter

CodeCombat Argument与Parameter的区别 - codecombat.cn
图39:Parameter 是空槽位,Argument 是你填进去的值

Parameter(形参):方法定义时的"占位符",像是一个空槽。
Argument(实参):调用方法时,你实际填进去的值。

类比:点外卖时,表单上写着"份数:________"(Parameter),你填上"3"(Argument)。

在日常学习中,大家通常统一叫"参数",不用太纠结。

1.3.1.3 参数的作用:改变方法的行为 How arguments modify method behavior

CodeCombat 参数改变行为 - codecombat.cn
图40:同一方法 + 不同参数 = 不同行为

没有参数的 moveRight():英雄走 1 步。
有参数的 moveRight(3):英雄走 3 步。

在第 5 关"敌人的陷阱"中,安雅需要一次向右走 3 格穿过火焰陷阱区域:

hero.moveRight(3)   # 一次走3步,快速穿过!

1.3.1.4 有参数与无参数的方法调用对比 Method calls with vs. without arguments

💡 对比说明:有参数 vs 无参数

想象你在叫出租车。"师傅,走吧"(无参数)= 默认往前开一段。"师傅,往前走3公里"(有参数)= 明确告诉他走多远。参数让你的指令更精确、更高效。下面的表格清楚地展示了这种差异:

调用方式含义效果
hero.moveRight()向右移动(默认 1 步)走 1 格
hero.moveRight(1)向右移动 1 步走 1 格(同上)
hero.moveRight(2)向右移动 2 步走 2 格
hero.moveRight(3)向右移动 3 步走 3 格
hero.moveDown(2)向下移动 2 步走 2 格

来看第 3a 关"逆时针回转":

hero.moveDown(2)    # 一口气向下走2步
hero.moveRight()    # 向右走1步
hero.moveUp()       # 向上走1步
hero.moveRight()    # 向右走1步

1.3.2 参数的语法(Syntax of Arguments)

1.3.2.1 参数写在圆括号内 Arguments are placed inside parentheses

CodeCombat 参数位置 - codecombat.cn
图41:参数必须在圆括号里面
hero.moveRight(3)     # ✓ 参数在括号里
hero.moveRight 3      # ✗ 错误!参数不在括号里

1.3.2.2 单参数传递:moveRight(3) Single argument: moveRight(3)

CodeCombat 单参数示例 - codecombat.cn
图42:第5关完整解法——每个移动方法都用了参数

来看第 5 关"火中取宝"的完整解法,全都用了参数:

hero.moveRight(3)   # 快速穿过右侧火焰区
hero.moveUp()       # 向上绕过陷阱
hero.moveRight()    # 继续前进
hero.moveDown(3)   # 向下穿过另一段
hero.moveRight(2)   # 到达宝石!

1.3.2.3 多参数传递 Multiple arguments

💡 多参数的概念

有些方法需要一次性接收多个信息。就像点外卖时你要同时告诉系统:菜品名称、数量、口味偏好。每个信息就是一个参数,多个参数之间用逗号隔开。虽然前 6 关只用到单参数(步数),但在后面的关卡中,你会遇到类似 hero.buildXY("fence", 36, 34) 这样的多参数写法——第一个是建造物类型(字符串),第二、三个是坐标位置(数字)。

虽然在前 6 关中我们只用到了单参数,但有些方法需要多个参数(用逗号隔开)。你在后续关卡中会遇到。

1.3.2.4 参数之间用逗号分隔 Arguments separated by commas

当方法有多个参数时,使用逗号 , 分隔。当前只需记住规则,后面用到时会很自然。

💡 逗号分隔参数示意

想象一份快递单上要填收件人姓名、电话、地址三个字段,每个字段之间用逗号隔开。在代码中也是一样的格式:method(参数1, 参数2, 参数3)。注意逗号后面通常加一个空格,这不是必须的,但能让代码更美观易读。

1.3.2.5 参数的顺序 Order of arguments matters

参数的位置决定含义。对于移动方法来说只有一个参数(步数),暂时不涉及顺序问题。

💡 参数顺序为什么重要?

假如某个方法需要两个参数 method(宽度, 高度),你写 method(3, 5) 表示宽3高5,但如果写成 method(5, 3) 就变成了宽5高3——完全不一样的结果!计算机是按照位置来理解每个参数含义的,而不是按"名字"。所以永远要按照方法要求的正确顺序传递参数。

1.3.3 参数的类型(Types of Arguments)

1.3.3.1 数字参数 Numeric arguments,如步数

CodeCombat 数字参数 - codecombat.cn
图43:数字参数直接写数字,不加引号

在前 6 关中,移动方法接受的参数都是数字——表示步数:

hero.moveRight(3)    # 3 是整数参数
hero.moveUp(2)       # 2 是整数参数
hero.moveDown(3)     # 3 是整数参数

有趣的是,这个数字还可以是小数(Float)(如 1.5)或负数(如 -1,表示反方向移动)。

1.3.3.2 字符串参数 String arguments,如名称

💡 字符串参数预览

字符串参数就是用引号括起来的文字内容。例如在后面的关卡中,hero.attack("Brak") 里的 "Brak" 就是一个字符串参数——它告诉英雄要攻击哪个敌人。又如 hero.say("Hello") 让英雄说出一句话。字符串参数必须加引号(单引号 ' 或双引号 " 都可以),而数字参数不加引号。记住这个区别:3 是数字,"3" 是字符串——它们对计算机来说完全不同!

在后面的关卡中你会遇到字符串参数——用引号包围的文字。现在只需知道:参数不只有数字一种类型

1.3.3.3 参数的类型必须匹配方法的要求 Argument type must match method requirement

💡 类型匹配——方法的"口味偏好"

每个方法对参数的类型有明确要求,就像自动售货机的投币口:它要硬币,你塞纸条进去是不行的。moveRight() 方法期望一个数字(告诉它走几步),如果你给它一个文字 "三",它就会困惑并报错。这是初学者常犯的错误之一,一定要注意数字不加引号、文字必须加引号!

hero.moveRight(3)        # ✓ 正确:3 是数字
hero.moveRight("三")     # ✗ 错误:"三" 是文字,不是数字!

1.3.4 使用参数优化代码(Using Arguments to Optimize Code)

1.3.4.1 参数减少代码行数 Arguments reduce lines of code

CodeCombat 参数减少行数 - codecombat.cn
图44:3行代码 vs 1行代码——效果完全相同
# 不用参数:3行
hero.moveUp()
hero.moveUp()
hero.moveUp()

# 用参数:1行
hero.moveUp(3)

效果完全一样,但代码从 3 行变成了 1 行!

1.3.4.2 moveRight(3) 等价于三次 moveRight() Equivalence of parameterized calls

来对比第 5a 关"虚幻干扰"的两种写法:

# 不用参数的写法(8行):
hero.moveRight()
hero.moveDown()
hero.moveDown()
hero.moveUp()
hero.moveUp()
hero.moveRight()
hero.moveRight()
hero.moveRight()

# 用参数的写法(4行):
hero.moveRight()
hero.moveDown(2)
hero.moveUp(2)
hero.moveRight(3)

1.3.4.3 代码简洁性与可读性 Code conciseness and readability

CodeCombat 简洁性与可读性 - codecombat.cn
图45:好代码 = 简洁 + 可读

好的代码应该追求简洁(Concise)但同时保持可读(Readable)hero.moveRight(3) 一眼就能看出"向右走 3 步"。

编程名言:"代码是写给人读的,只是顺便能被机器执行。" — Harold Abelson

1.3.4.4 语句数量限制挑战 Statement count optimization challenges

CodeCombat 语句数量挑战 - codecombat.cn
图46:第6关挑战——7条语句完成!

在第 6 关"漫长脚步"中:使用少于 8 条语句完成关卡。

hero.moveRight(1)   # 语句1
hero.moveUp(3)      # 语句2
hero.moveRight(2)   # 语句3
hero.moveDown(3)    # 语句4
hero.moveLeft(1)    # 语句5
hero.moveUp(2)      # 语句6
hero.moveRight(3)   # 语句7 ← 低于8条!

不用参数需要 15 行!参数就是你的"秘密武器"。

1.4 基本数据类型

Fundamental Data Types

1.4.1 数据类型概述(Overview of Data Types)

1.4.1.1 数据类型的定义:数据的分类 Classification of data

CodeCombat 数据类型概述 - codecombat.cn
图47:数据的分类——数字、文字、布尔值

数据类型(Data Type)就是数据的分类方式:数字类型可以做加减乘除(如 32.5-1);字符串类型表示文字(如 "Hello");布尔类型只有真或假(如 TrueFalse)。

1.4.1.2 为什么需要数据类型 Why data types matter

CodeCombat 为什么需要数据类型 - codecombat.cn
图48:类型搞混了,程序就不知道该怎么办

数据类型帮助计算机理解数据是什么、能做什么、怎么存储。在 CodeCombat 中,hero.moveRight(3) 里的 3 必须是数字——你不能写 hero.moveRight("三")

1.4.1.3 Python 是动态类型语言 Python is dynamically typed

💡 动态类型 vs 静态类型

有些编程语言(如 Java、C++)要求你在使用变量之前先"声明"它的类型,比如写 int steps = 3; 来告诉计算机 steps 是整数——这叫静态类型。而 Python 是动态类型语言,意思是你直接写 steps = 3 就行,Python 会自动识别出 3 是整数。这就像去餐厅点餐:有的餐厅要求你先声明"我要一份主食类的饭"(静态类型),而 Python 餐厅只需要你直接说"来碗米饭",服务员自己就知道这是主食(动态类型)。

Python 是动态类型语言——它会自动判断数据的类型,你不需要事先声明。

1.4.1.4 使用 type() 函数查看数据类型(以后会学习如何使用,现在先了解) Using type() to check data types

💡 type() 函数是你的"身份识别器"

type() 函数就像一个"身份识别器"——你把任何数据放进去,它就会告诉你这个数据是什么类型的。虽然在 CodeCombat 里暂时用不到,但在传统 Python 编程中,当你不确定一个数据是什么类型时,type() 就是你最好的朋友。下面的代码演示了如何使用它:

print(type(3))        # <class 'int'>     → 整数
print(type(2.5))      # <class 'float'>   → 浮点数
print(type(-1))       # <class 'int'>     → 整数
print(type(True))     # <class 'bool'>    → 布尔值

1.4.2 整数(Integer / int)

1.4.2.1 整数的定义:没有小数部分的数 Whole numbers without decimal part

CodeCombat 整数的定义 - codecombat.cn
图49:整数就是没有小数点的数

整数(Integer,简称 int)就是没有小数点的数:1, 2, 3, 100, -5, 0。在 CodeCombat 中,你传给移动方法的参数大多是整数。

1.4.2.2 正整数 Positive integers,如 1, 2, 3

💡 正整数——你最常用的参数类型

正整数就是大于零的整数:1、2、3、4、5……在前 6 关的所有关卡解法中,你传给 moveRight()moveUp() 等方法的参数基本都是正整数。比如 hero.moveRight(3) 中的 3,意思就是"向右走 3 步"。正整数在编程中无处不在——计数、循环次数、数组索引等都离不开它。

大于零的整数叫做正整数。前 6 关中所有参数都是正整数。

1.4.2.3 负整数 Negative integers,如 -1, -2, -3

💡 负整数——"反方向"的秘密武器

负整数就是小于零的整数,前面带一个减号:-1、-2、-3……在数学中,负数表示与正数相反的方向。在 CodeCombat 的移动方法中,负数参数同样表示反方向移动。这就像走路时向前走 3 步是正数,而向后退 3 步就是负数。理解负数=反方向的概念,对将来学习坐标系统、物理引擎等都很有帮助。

小于零的整数叫做负整数。有趣的是,给移动方法传入负数,英雄会朝反方向移动:

hero.moveDown(-1)    # 等同于 hero.moveUp(1)  —— 向上走!
hero.moveRight(-2)   # 等同于 hero.moveLeft(2) —— 向左走!
hero.moveLeft(-1)    # 等同于 hero.moveRight(1) —— 向右走!
想一想:hero.moveLeft(-1) 会怎样?答案:向走 1 步!因为"向左的反方向"就是向右。虽然实际编码时我们用正确方向+正数更清楚,但理解负数=反方向的原理很重要。

1.4.2.4 零 Zero, 0

💡 零——"什么都不做"的指令

零是一个特殊的数,它既不是正数也不是负数,处于数轴的正中央。在移动方法中传入 0 表示"不移动"——hero.moveRight(0) 就是让英雄原地不动。虽然在实际游戏中你不太会故意写这种代码,但理解 0 的含义有助于你理解参数和方向的关系:正数向前,负数向后,零不动。

零既不是正数也不是负数。hero.moveRight(0) = 原地不动!

1.4.2.5 整数在编程中的用途 Uses of integers in programming

💡 整数的典型使用场景

整数是编程中使用最广泛的数据类型之一。除了在 CodeCombat 中表示移动步数之外,整数还常用于:计数("循环执行 5 次")、索引("获取列表中第 3 个元素")、表示数量("背包里有 10 颗宝石")、表示状态码("HTTP 200 表示成功")等。在未来的学习中,你会发现几乎所有程序都离不开整数运算。

用途示例
向右移动3步hero.moveRight(3)
向上移动2步hero.moveUp(2)
向下移动3步hero.moveDown(3)
向左移动1步hero.moveLeft(1)

1.4.2.6 Python 中整数的表示 Integer representation in Python

💡 数字 vs "数字"——不加引号 vs 加引号

在 Python 中写整数非常简单:直接写数字就行。关键点是不要加引号3 是一个数字(整数类型),可以做数学运算、可以当步数;但 "3" 是一个字符串(文字类型),在计算机看来它只是一个字符,不能直接用来做加减法或当作步数。这就像现实中"三"字和 3 个苹果的区别——前者只是文字描述,后者才是真正的数量。

在 Python 中,整数直接写数字即可,不需要引号3(整数,能当步数)和 "3"(字符串,只是一个字符)是完全不同的东西!

1.4.2.7 整数的范围 Range of integers:Python 中无固定上限

💡 Python 整数的"超能力"

在很多编程语言(如 C、Java)中,整数有大小限制(比如 32 位整数最大只能到约 21 亿)。但 Python 的整数没有固定上限!你可以写出超级大的数字,Python 都能处理。不过在 CodeCombat 的前 6 关中,你用到的数字通常是 1 到 5 之间的小整数——毕竟地图就那么大,不需要走几百步。

Python 的整数没有大小限制!不过在 CodeCombat 中你用到的数字通常不超过 10。

1.4.3 浮点数 / 小数(Float / Floating-point number)

1.4.3.1 浮点数的定义:带小数点的数 Numbers with a decimal point

CodeCombat 浮点数定义 - codecombat.cn
图50:浮点数就是带小数点的数

浮点数(Float)就是带小数点的数:3.14, 2.5, 0.1, -7.8, 1.0

在 CodeCombat 中,浮点数也可以作为移动参数:

hero.moveRight(1.5)   # 向右移动1.5个单位
hero.moveUp(2.5)      # 向上移动2.5个单位

1.4.3.2 正浮点数 Positive floats,如 3.14

💡 正浮点数——更精确的步数

正浮点数就是大于零的小数。当你需要英雄移动"半步"或其他非整数距离时就会用到它们。比如 hero.moveRight(1.5) 会让英雄向右移动一个半格子的距离。在精确定位(如对准某个坐标点)时,浮点数特别有用。常见的正浮点数例子:3.14(圆周率π的近似值)、2.51.50.5(半步)。

大于零的浮点数:3.142.51.50.5

1.4.3.3 负浮点数 Negative floats,如 -2.5

💡 负浮点数——精确的反向移动

负浮点数结合了"小数精度"和"反方向"两个特性。hero.moveRight(-1.5) 会让英雄向移动 1.5 个单位——既精确到半格,又是反方向。它的原理和负整数完全一致:负号代表反方向,数值大小代表移动距离。

和负整数一样,负浮点数作为参数时也表示反方向移动:hero.moveRight(-1.5) = 向左移动1.5个单位。

1.4.3.4 整数与浮点数的区别 Difference between int and float

💡 整数 vs 浮点数——如何选择?

简单的判断方法:如果你的数据是"整个"的(1步、2步、3个苹果),用整数;如果你的数据需要精确到小数(1.5米、3.14圆周率),用浮点数。在 CodeCombat 中,大多数情况下整数参数就够用了(因为地图格子通常是整数距离),只有需要精确移动到两格之间的位置时才用浮点数。

特点整数(int)浮点数(float)
小数点没有
例子3, -5, 03.0, -5.5, 0.1
精确性完全精确可能有微小误差
常见用途步数、计数精确距离

1.4.3.5 浮点数的精度问题简介 Introduction to floating-point precision

💡 为什么 0.1 + 0.2 ≠ 0.3?

计算机使用二进制(0 和 1)来存储所有数据,包括小数。但就像十进制无法精确表示 1/3(只能写 0.333...),二进制也无法精确表示某些十进制小数(如 0.1)。这导致浮点运算会产生极其微小的误差。这不是 Python 的 bug,所有编程语言都有这个问题。好消息是:在 CodeCombat 的前 6 关中,你主要使用整数参数,完全不会遇到这个问题!

print(0.1 + 0.2)   # 输出: 0.30000000000000004

这不是 bug,是计算机用二进制存储小数时的微小误差。前 6 关中通常用整数参数,不太会遇到这个问题。

1.4.3.6 浮点数在坐标中的应用 Floats in coordinate systems

💡 浮点数与坐标——精确定位

在游戏地图上,每个位置都可以用坐标 (x, y) 来描述。有时候目标位置恰好在两个整数格子之间,比如 (3.5, 2.0)——这时就需要用浮点数来精确表示。在后面的关卡中,你会遇到 buildXY 等方法,它们的坐标参数经常是浮点数。理解浮点数可以帮助你在更高级的关卡中精确地定位建筑物或移动到特定位置。

游戏地图上的位置可以用浮点数精确描述。理解这一点有助于你在未来处理更精确的坐标计算。

1.4.4 正数与负数(Positive and Negative Numbers)

1.4.4.1 正数的概念 Numbers greater than zero

💡 正数——"正常方向"的参数

正数是大于零的数(包括正整数和正浮点数),如 1、2、3.5、100。在 CodeCombat 的移动方法中,正数参数表示按照方法名指定的方向移动。moveRight(3) = 向右走 3 步,moveUp(2) = 向上走 2 步。前 6 关的所有标准解法中使用的参数全部是正数——简单直接,容易理解。

正数是大于零的数。前 6 关关卡解法中使用的参数全部是正数。

1.4.4.2 负数的概念 Numbers less than zero

💡 负数——减号开头的"反向"指令

负数是小于零的数,写法是在正数前面加一个减号 -。在数学中,负数表示与正数相反的方向或概念:温度 -5°C 表示零下五度,海拔 -100m 表示在海平面以下 100 米。在编程中,负数同样表示"反向"。当你对 moveDown 传入 -1 时,它的效果就是"反方向"——即向上移动 1 步。

负数是小于零的数,用减号 - 表示。

1.4.4.3 数轴与坐标系中的正负数 Positive/negative numbers on number line and coordinate system

CodeCombat 数轴与坐标系 - codecombat.cn
图51:数轴——左负右正;坐标系——右正上正

在二维坐标系中:x 轴右正左负,y 轴上正下负。moveRight() 增加 x 值,moveUp() 增加 y 值。

1.4.4.4 正负数在移动方向中的应用 Application in directional movement

💡 正负数与移动方向的完整对照

正数参数 = 按照方法名的方向移动;负数参数 = 与方法名相反的方向移动。这个规律适用于所有四个移动方法。可以把每个方法想象成一条"路",正数表示沿着路走,负数表示掉头走。虽然实际编程中我们通常直接用正确方向的方法名(比如想向左走就直接用 moveLeft(正数)),但理解负数原理能帮助你在更复杂的坐标运算中游刃有余。

方法正数参数负数参数
moveRight(n)走 n 步走 |n| 步
moveLeft(n)走 n 步走 |n| 步
moveUp(n)走 n 步走 |n| 步
moveDown(n)走 n 步走 |n| 步
本质规律:负数 = 反方向。这和现实中"前进-3米"="后退3米"是一个道理。

1.4.5 数字类型的基本运算(Basic Numeric Operations)

1.4.5.1 加法 + Addition

💡 加法运算符 +

加法是最基础的算术运算。在 Python 中,加号 + 用于将两个数相加。结果的类型取决于参与运算的数:两个整数相加得整数(如 3 + 2 = 5),如果有一个是浮点数则结果为浮点数(如 3 + 0.5 = 3.5)。虽然前 6 关中你不需要直接做运算,但了解这些为后面用变量做计算打基础。

3 + 2      # 结果是 5
10 + 20    # 结果是 30

1.4.5.2 减法 - Subtraction

💡 减法运算符 -

减法用减号 - 表示。当结果小于零时会得到负数(如 10 - 20 = -10)。减法在编程中常用于计算差值、剩余数量、距离等。比如将来你可能需要计算"目标在英雄右边几步":目标x坐标 - 英雄x坐标

5 - 2      # 结果是 3
10 - 20    # 结果是 -10

1.4.5.3 乘法 * Multiplication

💡 乘法运算符 *

Python 使用星号 * 表示乘法(不是 ×!)。如果一个整数乘以一个浮点数,结果是浮点数。乘法在编程中用于缩放、计算面积、重复倍数等场景。

3 * 4      # 结果是 12
2 * 2.5    # 结果是 5.0

1.4.5.4 除法 / Division

💡 除法运算符 /

Python 3 中的除法 / 总是返回浮点数结果,即使两个整数能整除。例如 10 / 2 的结果是 5.0 而不是 5。如果需要整数除法(向下取整),可以使用双斜杠 //,如 7 // 2 = 3。这些细节以后会更深入地学到。

10 / 2     # 结果是 5.0(Python 3 中 / 总是返回浮点数)
7 / 2      # 结果是 3.5

1.4.5.5 运算符的概念 Concept of operators

💡 运算符——数据之间的"动作词"

运算符就是告诉计算机"对这些数据做什么操作"的符号。+-*/ 是最基本的算术运算符。将来你还会学到比较运算符(==><)和逻辑运算符(andornot)。有趣的是,你甚至可以在参数中使用运算表达式!比如 hero.moveRight(2 + 1) 等价于 hero.moveRight(3)——Python 会先计算 2 + 1 的值,再把结果 3 传给方法。

+-*/ 这些符号叫做运算符(Operators)。虽然前 6 关中不直接使用运算符做计算,但它们是 Python 的基础。将来你可以写 hero.moveRight(2 + 1) 等价于 hero.moveRight(3)

1.5 坐标系统

Coordinate System

1.5.1 二维坐标系(Two-dimensional Coordinate System)

1.5.1.1 x 轴与 y 轴 x-axis and y-axis

CodeCombat x轴与y轴 - codecombat.cn
图52:CodeCombat 地图的坐标系——x水平,y垂直

CodeCombat 的地图有两条轴:x 轴(水平方向,从左到右)和 y 轴(垂直方向,从下到上)。

理解坐标系有助于你理解英雄的位置和移动方向:moveRight() 让 x 值增大,moveLeft() 让 x 值减小;moveUp() 让 y 值增大,moveDown() 让 y 值减小。地图上每个位置都可以用 (x, y) 坐标来精确描述,比如英雄的起始位置可能是 (10, 10),宝石可能在 (13, 8)。通过计算坐标差值,你可以算出英雄需要走几步:向右 13-10=3 步,向下 10-8=2 步。

1.6 顺序执行

Sequential Execution

1.6.1 顺序结构的定义(Definition of Sequential Structure)

1.6.1.1 代码按书写顺序从上到下执行Code executes from top to bottom

CodeCombat 从上到下执行 - codecombat.cn
图53:顺序结构——代码从第一行到最后一行,绝不跳行

顺序结构(Sequential Structure)就是代码从第一行开始,按照书写顺序,一行一行向下执行。前 6 关的所有解法都是纯顺序结构。

1.6.1.2 每条语句执行一次Each statement executes once

💡 "一次且仅一次"——顺序结构的特征

在纯顺序结构中,每一行代码只会被执行恰好一次——不会多也不会少。这意味着如果你写了 5 行代码,程序运行时就会精确地执行 5 个动作。想让英雄做 10 个动作?那你就得写 10 行代码(或者用参数优化,但总的移动"次数"不变)。后面学到循环结构后,你就能让一段代码重复执行多次——那就不再是纯顺序结构了。

1.6.1.3 前一条语句完成后才执行下一条Next statement executes after previous completes

💡 "排队执行"——不会插队

顺序执行意味着代码是"排队"的:第 1 行必须完全执行完毕后,第 2 行才会开始执行。在 CodeCombat 中,这表现为英雄必须走完一步后才会走下一步——你不会看到英雄同时做两件事。这种"阻塞式"执行方式让程序行为完全可预测:你可以准确地知道在任意时刻英雄在哪里、在做什么。这个特性对于时机策略非常重要,如下面第 3b 关的例子所示。

在第 3b 关"狭路相逢"中,严格的顺序执行让时机策略成为可能:

hero.moveRight()    # 时刻1:走到门廊处
hero.moveLeft()     # 时刻2:退回来!
hero.moveRight(2)   # 时刻3:趁机冲过去!

1.6.1.4 顺序结构是最基本的控制结构Sequential structure is the most basic control structure

💡 三大控制结构——程序的"骨架"

所有计算机程序,无论多复杂,都是由三种基本控制结构组合而成的:顺序(从上到下依次执行)、选择(根据条件选择不同路径,如 if/else)、迭代(循环重复执行某段代码,如 while/for)。前 6 关只用到了顺序结构——这是最基础的,也是另外两种结构的"地基"。后面的关卡会逐步引入循环(Unit 3)和条件判断,让你写出更强大的程序。

所有程序都由三种控制结构组成:顺序(Sequence)、选择(Selection)、迭代(Iteration)。前 6 关只用到了最简单的顺序结构。

1.6.2 顺序结构的特点(Characteristics of Sequential Structure)

1.6.2.1 确定性:执行顺序固定Deterministic: fixed execution order

💡 确定性——每次运行结果都一样

顺序结构的第一个重要特点是确定性:代码的执行顺序是固定的,不会随机改变。这意味着同样的代码每次运行都会产生完全相同的结果。在 CodeCombat 中,只要你不修改代码,英雄每次走的路线都一模一样。这个特性让程序变得可预测、可调试——如果代码有错,错误也是稳定复现的,方便你找到并修复它。

1.6.2.2 可预测性:结果可预知Predictable: results are foreseeable

💡 可预测性——你可以"脑中运行"代码

因为顺序结构是确定性的,你可以在脑子里"模拟运行"代码——逐行阅读,想象英雄的每一步,就能预知最终结果。这是一个非常有用的能力,叫做"代码追踪"(Code Tracing)或"干运行"(Dry Run)。在点击运行按钮之前,先用脑子走一遍代码,可以帮你提前发现错误。试试在纸上画出地图,然后用铅笔跟着代码一步步画出英雄的路线。

1.6.2.3 语句顺序影响结果Order of statements affects outcome

💡 顺序不同,结果天差地别!

想象你做饭的步骤:先切菜再炒菜(正确!),如果改成先炒菜再切菜(怎么炒一整棵白菜?)。编程也是一样——调换语句的顺序可能导致完全不同的结果。比如在第 3 关中,安雅需要先向右走到雕像旁,再向上走躲起来。如果你把两行调换,她会先向上撞墙,然后向右暴露在食人魔面前——结果完全不同!

来看第 3 关"幽影守卫"。如果调换前两行的顺序,安雅可能撞墙或被食人魔发现!

记住:写代码就像给人导航——"先左转再直行"和"先直行再左转"可能带你去完全不同的地方。

1.6.3 多行代码的组织(Organizing Multiple Lines of Code)

1.6.3.1 一行一条语句One statement per line

💡 一行一指令——Python 的基本格式

Python 的基本规则之一:每行写一条语句。不要把多条指令挤在同一行。虽然 Python 在技术上允许用分号 ; 把多条语句写在一行(如 hero.moveRight(); hero.moveDown()),但这样做会让代码难以阅读。就像写作文要分段一样,每行一条语句让代码清晰、整洁、容易理解。

1.6.3.2 语句的分解与组合Decomposing and combining statements

💡 分解与组合——灵活运用参数

同一个任务可以用不同的语句组合来完成。"向右走 3 步"既可以分解为 3 行 hero.moveRight(),也可以组合成 1 行 hero.moveRight(3)——效果相同。学会灵活地分解(让每步清晰)和组合(让代码简洁)语句,是编程的基本功。通常的原则是:在不牺牲可读性的前提下,尽量用参数来减少重复的行。

1.6.3.3 代码的逻辑分组Logical grouping of code

💡 逻辑分组——给代码"分段落"

当代码行数较多时(比如第 4 关有 12 行),可以按照逻辑意义将代码分组。例如:"第一段:从入口走到拐角"、"第二段:从拐角走到宝石"。你可以用空行或注释来分隔这些逻辑组,让代码读起来像一篇结构清晰的短文。

1.6.3.4 空行的使用提高可读性Using blank lines for readability

💡 空行——代码中的"呼吸空间"

空行不会被 Python 执行(它什么都不做),但对人类阅读代码帮助巨大。在不同的逻辑段落之间加一个空行,就像文章中的段落间距一样,让读者能轻松分辨代码的不同部分。好习惯从现在开始培养!

空行不会被执行,但能让人类读代码时"喘口气"。就像写文章要分段一样,写代码也要适当留白!

1.8 问题分解与路径规划

Problem Decomposition and Path Planning

1.8.1 问题分解(Problem Decomposition)

1.8.1.1 将大问题分解为小步骤Breaking a big problem into smaller steps

CodeCombat 问题分解 - codecombat.cn
图54:大问题看起来复杂,分解后每步都很简单

问题分解(Decomposition)是编程最重要的思维方式之一。面对第 4 关复杂的路线时,把"收集所有宝石并返回出口"拆解成每一小步,每步都不难!

AP CSP 核心概念:分解(Decomposition)是计算思维的四大支柱之一。

1.8.1.2 确定起点与终点Identifying start and end points

💡 起点与终点——问题的"边界"

解决任何问题的第一步是搞清楚:现在在哪?要去哪?在 CodeCombat 中,起点是英雄的初始位置(通常在地图左侧),终点是目标位置(宝石或出口)。明确了起点和终点,你就能开始规划中间的路径了。在纸上画出地图格子,标出起点和终点,然后再填充中间步骤——这是一种很好的问题解决习惯。

1.8.1.3 规划中间步骤Planning intermediate steps

💡 中间步骤——"沿路设置检查点"

从起点到终点之间,设置几个"检查点"——比如拐角处、需要避开障碍物的位置、需要改变方向的地方。每到一个检查点,确认方向对了再继续下一段。这就像导航软件给你标注的"在A路口左转、经过B大桥、在C出口驶出"——把长距离分成几个短距离,每段都简单明了。

# 第3关"幽影守卫"的路径规划:
hero.moveRight()   # 到雕像旁
hero.moveUp()      # 躲到雕像后面
hero.moveRight()   # 从食人魔身后通过
hero.moveDown()    # 回到通道
hero.moveRight()   # 到达宝石!

1.8.1.4 AP CSP 概念:算法设计AP CSP: Algorithm Design

💡 算法设计——有限步骤解决问题

在 AP 计算机科学原理课程中,算法被定义为"为解决特定问题或完成特定任务而设计的有限步骤序列"。你在 CodeCombat 中写的每一关的解法,本质上就是一个小型算法!它具备算法的所有特征:有明确的输入(地图布局)、有限的步骤(你的代码行数是有限的)、确定的输出(英雄到达目标位置)、以及正确性(通过关卡验证)。从第 1 关开始,你就在进行算法设计了。

1.8.2 路径规划(Path Planning)

1.8.2.1 在网格/地图上规划路线Planning a route on a grid/map

💡 网格规划——把地图想象成棋盘

CodeCombat 的地图可以看作一个网格(棋盘),英雄每次移动一格。规划路线时,你可以在脑中(或纸上)把地图画成格子,标出障碍物(墙壁、尖刺、敌人的巡逻范围),然后找出一条从起点到终点的安全路径。每个格子只有四个方向可以走(上下左右),这让问题简化了很多。

1.8.2.2 避障策略Obstacle avoidance strategy

💡 避障——绕开不能走的格子

地图上有些格子是不能走的:墙壁会挡住你、尖刺会伤害你、食人魔的视线范围内会被发现。避障策略就是:先识别所有不能走的格子,然后规划一条避开它们的安全路线。常见的策略包括"紧贴墙壁绕行"、"从障碍物的上方/下方绕过"、"等待巡逻敌人走开后再通过"等。第 3 关的雕像路线和第 3b 关的时机等待都是避障策略的经典应用。

1.8.2.3 最短路径思维Shortest path thinking

💡 最短路径——用最少的步数达到目标

在满足安全要求的前提下,尽量走最短的路径。这不仅让代码更短(特别是有语句数量限制时),也让程序更高效。判断最短路径的简单方法:计算起点和终点的坐标差值,看看是否能找到一条直达路线。如果中间有障碍,就找绕行距离最短的替代路线。第 6 关要求 7 条语句以内完成,正是对最短路径思维的考验。

1.8.2.4 时机与顺序的考虑Timing and order considerations

💡 时机——"什么时候走"和"走哪里"同样重要

在某些关卡(如第 3b 关"狭路相逢")中,除了规划路线,你还需要考虑时机。食人魔矮人在巡逻——如果你在错误的时刻通过它的面前,就会被发现。解决方法是先走一步引起它注意,然后退回来等它走开,最后趁它背对你时快速冲过去。这里的关键是利用顺序执行的特性(每步花费时间)来"消耗"时间,配合敌人的巡逻节奏。

1.9 本单元相关 Python 语法总结

Python Syntax Summary for This Unit

1.9.1 方法调用语法(Method Call Syntax)

1.9.1.1 基本格式:object.method()Basic format

💡 方法调用的三种格式

本单元学到的方法调用有三种基本格式:① 无参数:hero.moveRight(),英雄按默认行为执行;② 单参数:hero.moveRight(3),用参数自定义行为;③ 多参数(预告):hero.method(arg1, arg2, arg3),用多个信息控制更复杂的行为。无论哪种格式,核心结构都是 对象.方法名(参数列表)——这是 Python 面向对象编程的基本语法。

# 基本格式:无参数
hero.moveRight()

# 带参数格式
hero.moveRight(3)

# 多参数格式(后续关卡会用到)
hero.someMethod(arg1, arg2, arg3)

1.9.1.2–1.9.1.3 带参数与多参数格式

(已在上面的代码示例中展示)

1.9.1.4 大小写敏感Case sensitivity

💡 大小写敏感——一个字母大小写不同就报错!

Python 是大小写敏感(Case Sensitive)的语言,这意味着 heroHeroHERO 是三个完全不同的名字!同样地,moveRightMoveRightmoveright 也是完全不同的。这是初学者最常犯的错误之一。记住 CodeCombat 中的规则:对象名 hero 全小写,方法名第一个单词小写、后面每个单词首字母大写(驼峰命名法)。

hero.moveRight()    # ✓ 正确
Hero.moveRight()    # ✗ 错误!"Hero" ≠ "hero"
hero.MoveRight()    # ✗ 错误!"MoveRight" ≠ "moveRight"
hero.moveright()    # ✗ 错误!"moveright" ≠ "moveRight"
记忆技巧:hero 全小写,move 小写,方向首字母大写(RightLeftUpDown)。

1.9.2 Python 基本规则(Basic Python Rules)

1.9.2.1 每行一条语句One statement per line

💡 一行一语句——Python 的书写规范

Python 使用换行符来分隔不同的语句。这意味着每写完一条指令就按一次回车,开始新的一行。这个规则让 Python 代码看起来干净整洁,每行只做一件事,阅读时一目了然。如果你在其他语言(如 JavaScript)中见过 ; 结尾的语句,在 Python 中不需要——换行本身就标志着一条语句的结束。

1.9.2.2 缩进的重要性预告Preview: importance of indentation

💡 缩进预告——Unit 3 的重要准备

在前 6 关中,你的所有代码都是顶格写的(没有缩进)。但在后面学到循环(while True:)和条件判断(if)时,你就需要用缩进(通常是 4 个空格)来表示"哪些代码属于循环/条件内部"。Python 用缩进来标识代码块的层级关系——这是 Python 的独特设计。现在先记住:缩进在 Python 中不只是美观,它有语法意义!

1.9.2.3 Python 关键字Python keywords,初步了解

💡 关键字——Python "保留"的特殊单词

Python 有一些被"保留"的单词,叫做关键字(Keywords),如 whileTrueFalseifelsefordefreturn 等。这些词在 Python 中有特殊含义,你不能用它们作为变量名或自定义标识符。在前 6 关中你还不会直接使用这些关键字,但了解它们的存在可以避免将来踩坑——比如你不能写 True = 3 这样的代码。

1.9.2.4 标识符命名规则Identifier naming rules

💡 标识符命名——给"东西"取名的规则

在 Python 中,标识符(变量名、函数名、方法名等)需要遵循这些规则:① 只能包含字母、数字和下划线 _;② 不能以数字开头(1hero 不行,hero1 可以);③ 不能使用 Python 关键字;④ 区分大小写(Herohero 是不同的名字)。好的命名习惯:名字应该有意义(moveRightmr 好)、保持一致的风格(全用 camelCase 或全用 snake_case)。在 CodeCombat 中,hero 已经帮你取好了名字,但在将来的编程中你需要自己给变量取名。

本单元小结 ✨

CodeCombat 单元总结 - codecombat.cn
图55:第一单元核心概念全景图

恭喜你完成了第一单元!来看第 6 关"漫长脚步"的完整解法,回顾所有核心概念:

hero.moveRight(1)    # 对象.方法(参数) → 向右走1步
hero.moveUp(3)       # 正整数参数 → 向上走3步
hero.moveRight(2)    # 顺序执行 → 第3个执行的语句
hero.moveDown(3)     # 不同方向的方法 → 向下走3步
hero.moveLeft(1)     # moveLeft方法 → 向左走1步
hero.moveUp(2)       # 参数优化 → 比写2行更简洁
hero.moveRight(3)    # 7条语句完成!低于8条限制 🎉
核心概念关键代码首次出现
对象与方法hero.moveRight()第1关
点表示法对象.方法()第1关
四个移动方法moveRight/Left/Up/Down第1关
顺序执行代码从上到下逐行执行第1关
参数的使用hero.moveRight(3)第2关概念/第5关正式
整数参数1, 2, 3第2关
负数=反方向hero.moveDown(-1)=向上概念扩展
代码优化用参数减少语句数第5关/第6关
问题分解大问题 → 小步骤第3关/第4关
路径规划与时机避障、选择时机第3关/第3a/第3b关

安雅和塔林正在地牢中等着你的下一步指令。
准备好了吗?让我们继续前往第二单元,学习字符串、攻击方法和调试吧!🗡️

CodeCombat 编程知识 · 计算机科学入门(暗影地牢):第一单元

CodeCombat教研团队