diff --git a/assets/css/custom.css b/assets/css/custom.css index 1429647..10087f2 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -103,3 +103,35 @@ html.dark .theme-toggle-light { } /* Hide current page title in breadcrumb */ + +/* Image caption */ +figcaption.post-caption { + font-size: .85em; + color: #888; + text-align: center; + margin-top: -.25em; + margin-bottom: 1em; +} +.dark figcaption.post-caption { + color: #999; +} + +.mermaid svg { + max-width: 100%; + height: auto; +} + +.mermaid svg { + max-width: 100%; + height: auto; +} + +.mermaid svg { + width: 100% !important; + height: auto !important; +} + +.mermaid svg { + max-width: none !important; + height: auto; +} diff --git a/content/blog/ai-assistant-first-week.md b/content/blog/ai-assistant-first-week.md index 271df41..acfc7eb 100644 --- a/content/blog/ai-assistant-first-week.md +++ b/content/blog/ai-assistant-first-week.md @@ -40,7 +40,7 @@ AI 这两年用得不少,ChatGPT、Claude、DeepSeek 都试过。问问题、 午间忽想建站,交代了一句。它 SSH 上服务器就开始干活。 ```mermaid -flowchart TD +flowchart LR A[我:建个博客] --> B[SSH 登录服务器] B --> C[安装 Hugo + Nginx] C --> D[配置 HTTPS] @@ -57,7 +57,7 @@ flowchart TD 每天早上想看国际新闻、科技动态和通信消息。我让它写了个定时脚本,每天 8:30 推送微信。 ```mermaid -flowchart TD +flowchart LR A[Cron 8:30] --> B[拉取待办 + 新闻] B --> C[编译简报] C --> D[推送微信] @@ -75,7 +75,7 @@ flowchart TD 工作对话截图丢过去,说一句"入待办"。 ```mermaid -flowchart TD +flowchart LR A[我:发聊天截图] --> B[读取并提取信息] B --> C[创建 Todoist 任务] C --> D[标优先级 + 截止日] @@ -91,7 +91,7 @@ flowchart TD **邮件过滤。** 信任更进一步,我给了它 IMAP 权限,让它每天扫收件箱。 ```mermaid -flowchart TD +flowchart LR A[每日扫描收件箱] --> B{发给我但
没给下属?} B -->|是| C[建文件夹存档] C --> D[附件存 / 正文转 md] diff --git a/content/blog/media-test.md b/content/blog/media-test.md index 2e886a9..464cba0 100644 --- a/content/blog/media-test.md +++ b/content/blog/media-test.md @@ -1,19 +1,19 @@ --- -title: "媒体嵌入测试:视频与图片" +title: "Hugo 站点中嵌入视频与图片的最佳实践" date: 2026-05-16T12:00:00+08:00 draft: false poet: | 一花一世界, 一叶一菩提。 - ——《华严经》,古印度/中国 -description: "测试 Hugo 对 B 站视频嵌入和多种图片格式的渲染效果。包含 iframe 视频播放器、横版图片、内联对比和居中展示,验证移动端和桌面端的布局表现。" + ——《华严经》 +description: "静态站点不等于只能放文字。B 站视频的自适应嵌入方案、图片懒加载与响应式处理、以及如何在 Hugo 里保持多媒体内容的可维护性。" --- -这是一篇测试文章,验证 Hugo 对 B 站视频嵌入和图片渲染的支持。 +静态博客常被认为只能承载纯文本,但实际上 Hugo 对多媒体内容的支持相当完整。本文记录本站的视频嵌入和图片排版方案,供有类似需求的读者参考。 -## 嵌入式视频 +## B 站视频嵌入 -下面是 B 站视频 BV1AWRVB2EAz 的嵌入播放器: +Hugo 的 `unsafe: true` 配置允许直接插入 ` -视频通过 B 站官方播放器嵌入,支持弹幕、倍速、画质切换。 +几个关键参数:`high_quality=1` 默认启用高清画质,`autoplay=0` 禁用自动播放(避免对读者造成打扰)。外层容器的 `padding-bottom: 75%` 是 4:3 比例,如果视频是 16:9 改成 `56.25%` 即可。 -## 图片渲染测试 +## 图片排版实践 -### 横版图片 +### 宽幅配图 + +对于需要烘托氛围的宽幅图片,直接使用 Markdown 默认语法即可,Hugo 会自动处理响应式缩放: ![AI 主题图](/images/ai.jpg) +{{< caption >}}宽幅配图适合放在文章开头,作为视觉呼吸点。{{< /caption >}} -### 内联对比 +这类图片适合放在文章开头或章节之间作为视觉呼吸点。 -两张图并排展示: +### 多图并列 + +需要对比展示时,可以将图片连续排列。配合 Hugo 的渲染引擎,相邻图片会自动获得合适的间距: ![编程](/images/coding.jpg) +{{< caption >}}编程与思考。{{< /caption >}} ![思考](/images/thinking.jpg) -### 小图居中 +### 配图居中 + +适量使用图片比堆砌更能提升阅读体验。一张位置恰当的配图可以给段落之间留出自然的停顿: ![子弹日记](/images/journal.jpg) +{{< caption >}}一张位置恰当的配图,给段落之间留出自然的停顿。{{< /caption >}} ---- +## 多媒体文件的组织 -以上测试覆盖了视频嵌入和多种图片展示场景。如果你在手机或其他设备上看到布局异常,需要针对性调整。 +本站将所有图片和字体统一放入 `static/` 目录,引用时使用绝对路径 `/images/xxx.jpg`。这样做的好处是路径清晰、不受页面层级影响,也方便后续迁移到 CDN。 + +如果你也在用 Hugo 搭建个人站点,多媒体内容的处理原则就一条:**路径统一、格式克制、体积有数**。祝搭建愉快。 diff --git a/content/blog/prolog-pokemon.md b/content/blog/prolog-pokemon.md index 9aae449..7dd6786 100644 --- a/content/blog/prolog-pokemon.md +++ b/content/blog/prolog-pokemon.md @@ -2,63 +2,67 @@ title: "用宝可梦解释 Prolog 基础" date: 2026-05-18T13:30:00+08:00 draft: false -description: "通过宝可梦对战系统理解逻辑编程语言 Prolog 的核心概念——事实、规则、查询,以及它为什么比 SQL 更灵活。" +description: "通过宝可梦对战系统理解逻辑编程语言 Prolog 的核心概念——事实、规则、查询,以及它为什么比 SQL 和电子表格更灵活。" tags: - Prolog - 宝可梦 - 编程语言 - 翻译 +poet: | + 众里寻他千百度, + 蓦然回首,那人却在,灯火阑珊处。 + ——辛弃疾,中国,1140–1207 --- -# 用宝可梦解释 Prolog 基础 +> 原文作者:Alexander Petros +> 原文链接:[Prolog Basics Explained with Pokémon](https://unplannedobsolescence.com/blog/prolog-basics-pokemon/) +> 本文已获授权翻译,有删节和注释。 -2026年1月5日 +启发这篇文章的项目有点傻——我要详细描述一个儿童电子游戏的机制——但正是这个特定问题最终让我真正理解了 Prolog。这是自从读了 Bruce Tate 的《七周七语言》以来一直在追寻的顿悟。 -启发这篇文章的项目有点傻——我将要详细描述一个儿童电子游戏的机制——但正是这个特定问题最终让我真正理解了 Prolog,这是自从我读了 Bruce Tate 的《七周七语言》以来一直在追寻的顿悟。 +对于某些类型的关系,逻辑编程是我用过的最简洁、最具表现力的编程系统。要理解为什么,让我们来聊聊宝可梦。 -这个练习教会了我很多关于我正在[更实用的领域](https://alexanderpetros.com/triptych/)尝试构建的接口类型。对于某些类型的关系,逻辑编程是我用过的最简洁、最具表现力的编程系统。 +## 宝可梦基础 -要理解为什么,让我们来聊聊宝可梦(Pokémon)。 +宝可梦是一个电子游戏系列,设定在一个人类与各种色彩缤纷的动物角色共存的世界。"Pokémon" 既是系列名称,也是这些动物角色的统称,每个角色都有自己的物种名称。从妙蛙种子(#1)到桃歹郎(#1025),共有超过一千种不同的宝可梦物种。 -## 宝可梦(Pokémon)基础 +
皮卡丘始祖大鸟裹蜜虫
-宝可梦是一个电子游戏系列/多媒体特许经营/生活方式品牌,设定在一个人类与各种色彩缤纷的动物角色共存的世界。 +{{< caption >}}受欢迎的宝可梦包括(从左到右):皮卡丘(#25)、始祖大鸟(#567)和裹蜜虫(#1101)。{{< /caption >}} -"Pokémon" 既是这个系列的名称,也是这些动物角色本身的统称,每个角色都有自己的物种名称。从 Bulbasaur(妙蛙种子,[#1](https://bulbapedia.bulbagarden.net/wiki/Bulbasaur_(Pok%C3%A9mon)))到 Pecharunt(桃歹郎,[#1025](https://bulbapedia.bulbagarden.net/wiki/Pecharunt_(game))),共有超过一千种不同的宝可梦物种。 +现在有各种各样的宝可梦游戏,但主系列始终围绕着捕捉和对战。在对战中,你的六只宝可梦队伍与另一支队伍交锋。每只宝可梦配备四个招式,通常用来对对手造成伤害。你需要将对方所有宝可梦的 HP 减到零,同时防止对方先对你做同样的事。 -受欢迎的宝可梦包括(从左到右):Pikachu(皮卡丘,[#25](https://bulbapedia.bulbagarden.net/wiki/Pikachu_(Pok%C3%A9mon)))、Archeops(始祖大鸟,[#567](https://bulbapedia.bulbagarden.net/wiki/Archeops_(Pok%C3%A9mon))) 和 Dipplin(裹蜜虫,[#1101](https://bulbapedia.bulbagarden.net/wiki/Dipplin_(Pok%C3%A9mon)))。 +每只宝可梦都有独特的特性影响对战表现:基础能力值、可学的招式、特性和属性组合。这里的庞大组合数量正是试图用软件来追踪这些信息的动机。 -我很少在这个博客里放图片,能在这篇文章里放图让我非常兴奋。 +![巨钳螳螂的能力值(来自 Smogon)](/images/pokemon/scizor-stats.png) -现在有各种各样的宝可梦游戏,但主系列始终围绕着捕捉和对战。在对战中,你的六只宝可梦队伍与另一支队伍交锋。每只宝可梦配备四个招式,可以选择用来(通常)对对手造成伤害。你需要将对方所有宝可梦的 HP(体力值)减到零,同时防止对方先对你做同样的事。 +{{< caption >}}巨钳螳螂是虫/钢属性,攻击力高但速度低(数据来自 Smogon)。{{< /caption >}} -每只宝可梦都有独特的特性影响对战表现。它们有一套基础能力值、大量可学的招式、若干特性和属性组合。你马上就会看到,这里庞大的组合数量正是试图用软件来追踪这些信息的动机。 +**速度**决定哪个招式先出手;**攻击和特攻**分别影响物理招式和特殊招式的伤害;**防御和特防**影响受到的伤害。 -Scizor(巨钳螳螂)是虫/钢属性,攻击力高但速度低(数据来自 [Smogon](https://www.smogon.com/dex/bw/pokemon/scizor/)) +**属性**尤其重要。招式有属性(如火或岩石),宝可梦可以拥有最多两种属性。如果招式属性对对方宝可梦效果绝佳,造成双倍伤害;效果不佳则只造成一半伤害。 -速度决定哪个招式先出手;攻击和特攻分别影响物理招式和特殊招式的伤害;防御和特防影响受到的伤害。 +![冲浪对月石效果绝佳](/images/pokemon/surf.png) -属性尤其重要。招式有属性,比如火或岩石,而宝可梦可以拥有最多两种属性。如果招式的属性对对方宝可梦效果绝佳(Super Effective),会造成双倍伤害;效果不佳(Not Very Effective)则只造成一半伤害。 +{{< caption >}}月石是岩石/超能力属性。岩石弱水,超能力对水中性,所以冲浪会造成 2 倍伤害。{{< /caption >}} -用例子来说明会更直观一些。火属性的招式喷射火焰(Flamethrower)对草属性宝可梦造成 2 倍伤害,因为草弱火,但水属性的冲浪(Surf)对它们只造成 ½ 伤害,因为草抗水。 +举个直观的例子:火属性的喷射火焰对草属性宝可梦造成 2 倍伤害(草弱火),但水属性的冲浪只造成 ½ 伤害(草抗水)。 -[Lunatone(月石)](https://bulbapedia.bulbagarden.net/wiki/Lunatone_(Pok%C3%A9mon))是岩石/超能力属性。岩石弱水,超能力对水中性,所以冲浪会造成 2 倍伤害。 +属性修正可以叠加。巨钳螳螂是虫/钢属性,虫和钢都弱火,所以火属性招式对它造成 4 倍伤害。电弱水,但地面免疫电——如果你对水/地面的巨沼怪使用电属性招式,伤害为零,因为 0×2 还是 0。 -属性修正可以叠加。[Scizor(巨钳螳螂)](https://bulbapedia.bulbagarden.net/wiki/Scizor_(Pok%C3%A9mon))是虫/钢属性,虫和钢都弱火,所以火属性招式对 Scizor 会造成 4 倍伤害。电弱水,但地面免疫电,所以如果你对水/地面的 [Swampert(巨沼怪)](https://bulbapedia.bulbagarden.net/wiki/Swampert_(Pok%C3%A9mon))使用电属性招式,伤害为零,因为 0×2 还是 0。 +![宝可梦属性相克表(来自 Wikimedia)](/images/pokemon/type-chart.svg) -自然而然地,有一张图表来帮你记忆。 +{{< caption >}}宝可梦属性相克表。{{< /caption >}} -宝可梦属性相克表(来自 [Wikimedia](https://commons.wikimedia.org/wiki/File:Pokemon_Type_Chart.svg)) - -这些基本上就是我 8 岁时理解的宝可梦电子游戏机制。点击招式造成伤害,尽量选择属性相克有利的招式。这些游戏是为儿童设计的,表面上看并不难。 +这些基本上就是我 8 岁时理解的宝可梦机制。点击招式造成伤害,尽量选择属性相克有利的招式。这些游戏是为儿童设计的,表面上看并不难。 ## Prolog 基础 -在解释宝可梦机制底层有多复杂之前,我需要先解释一下逻辑编程的工作原理。宝可梦非常适合逻辑编程,因为宝可梦对战本质上是一个极其精密的规则引擎。 +在解释宝可梦机制底层有多复杂之前,先解释逻辑编程的工作原理。宝可梦非常适合逻辑编程,因为宝可梦对战本质上是一个极其精密的规则引擎。 -让我们先创建一个包含一堆事实的文件。 +首先创建一个包含事实的文件: -``` +```prolog pokemon(bulbasaur). pokemon(ivysaur). pokemon(venusaur). @@ -70,264 +74,182 @@ pokemon(wartortle). pokemon(blastoise). ``` -在 Prolog 中,我们声明"谓词"(predicates)。谓词定义关系:bulbasaur 是一只宝可梦,charmander 是一只宝可梦,以此类推。我们称这个谓词为 pokemon/1,因为谓词名称是 pokemon,它有一个参数。 +在 Prolog 中,我们声明"谓词"(Predicate)。谓词定义关系:`bulbasaur` 是一个 `pokemon`,`charmander` 是一个 `pokemon`,以此类推。我们称这个谓词为 `pokemon/1`,因为它有一个参数。 -这些事实被加载到一个叫做"顶层"(top-level)的交互式提示符中。你通过在提示符中输入语句来查询;Prolog 尝试找到使该语句成立的所有方式。当有多个可能的解时,顶层会显示第一个解,然后等待用户输入。你可以让它再显示一个解、显示所有解,或者完全停止。 - -在第一个例子中,我们输入 `pokemon(squirtle).` 并回车。顶层回复 true。[Squirtle(杰尼龟)](https://bulbapedia.bulbagarden.net/wiki/Squirtle_(Pok%C3%A9mon))确实是一只宝可梦。 +这些事实被加载到一个交互式提示符——"顶层"(top-level)中。你输入一个语句到提示符,Prolog 试图找出所有使该语句为真的方式: ``` ?- pokemon(squirtle). - true. + true. ``` -如果你想在家跟着做,查看[这个仓库](https://github.com/alexpetros/prologdex),里面有快速设置说明。 - 不是所有东西都是宝可梦。 ``` ?- pokemon(alex). - false. + false. ``` -让我们用谓词 type/2 来加入宝可梦属性。 +接着添加宝可梦的属性,作为谓词 `type/2`: -``` +```prolog type(bulbasaur, grass). type(bulbasaur, poison). type(ivysaur, grass). type(ivysaur, poison). -type(venusaur, grass). -type(venusaur, poison). type(charmander, fire). -type(charmeleon, fire). -type(charizard, fire). -type(charizard, flying). type(squirtle, water). -type(wartortle, water). type(blastoise, water). ``` -实际数据集包含了宝可梦的不同形态,比如 Mega 进化,因为它们有不同的能力值和属性。这里为了清晰起见省略了这些。 +有些宝可梦只有一种属性,有些有两种。后一种情况用两个 `type` 事实建模。妙蛙种子是草属性,也是毒属性——两者都为真。 -回顾一下,有些宝可梦只有一种属性,而另有两种。对于后一种情况,用两个 type 事实来建模。[Bulbasaur(妙蛙种子)](https://bulbapedia.bulbagarden.net/wiki/Bulbasaur_(Pok%C3%A9mon))是草属性,同时 Bulbasaur 也是毒属性;两个都为真。这种范式类似于 SQL 数据库中的一对多关系。 - -交互式地,我们可以确认 Squirtle 是不是水属性。 +交互式查询: ``` ?- type(squirtle, water). - true. -``` - -我们能不能说 Squirtle 是草属性? - -``` + true. ?- type(squirtle, grass). - false. + false. ``` -不能,因为 Squirtle 是水属性。 - -假设我们不知道 Squirtle 是什么属性。我们可以问! +Prolog 中首字母大写的名字是**变量**。Prolog 尝试将谓词与变量的所有可能匹配进行"合一": ``` ?- type(squirtle, Type). - Type = water. + Type = water. ``` -在 Prolog 中,以大写字母开头的名字是变量。Prolog 尝试将谓词与变量的所有可能匹配进行"合一"(unify)。不过这个特定谓词只有一种方式可以为真:Type 必须是 water,因为 Squirtle 的唯一属性就是水。 - -对于有两种属性的宝可梦,谓词会合一两次。 +对于有两种属性的宝可梦,谓词会合一两次: ``` ?- type(venusaur, Type). - Type = grass -; Type = poison. + Type = grass +; Type = poison. ``` -语义上,第三行的分号表示"或"。当 Type = grass 或 Type = poison 时,type(venusaur, Type) 为真。 - -任何参数都可以是变量,这意味着我们可以从任意方向提问。所有草属性有哪些?只需让第一个参数是变量,第二个参数设为 grass。 +分号 `;` 表示"或"。任何参数都可以是变量,这意味着我们可以从任意方向提问。所有草属性宝可梦有哪些?只需把第一个参数设为变量: ``` ?- type(Pokemon, grass). - Pokemon = bulbasaur -; Pokemon = ivysaur -; Pokemon = venusaur -; Pokemon = oddish -; Pokemon = gloom -; Pokemon = vileplume -; Pokemon = paras -; Pokemon = parasect -; Pokemon = bellsprout -; ... . + Pokemon = bulbasaur +; Pokemon = ivysaur +; Pokemon = venusaur +; ... ``` -这个输出是我输入查询后,按了几次"n"得到前几个解,然后按回车退出的结果。我截断了,但提示符会愉快地列出全部 164 个。 - -逗号可以用来列出多个谓词——Prolog 会统一变量,使得所有谓词同时为真。列出所有水/冰属性只需问:哪些宝可梦同时与水和冰两种属性合一。 +逗号用于列出多个谓词——Prolog 会合一变量使得所有谓词都为真。列出所有水/冰属性的宝可梦: ``` ?- type(Pokemon, water), type(Pokemon, ice). - Pokemon = dewgong -; Pokemon = cloyster -; Pokemon = lapras -; Pokemon = laprasgmax -; Pokemon = spheal -; Pokemon = sealeo -; Pokemon = walrein -; Pokemon = arctovish -; Pokemon = ironbundle -; false. + Pokemon = dewgong +; Pokemon = cloyster +; Pokemon = lapras +; Pokemon = ironbundle +; false. ``` -不要被解以"或 false"结尾这件事困扰。这是搜索算法工作方式的结果;求解器寻找更多解,然后失败了。我承认,我不完全理解为什么它有时候这样有时候不这样,但这是预期的行为。 - -尽管 Pokemon 是一个变量,在查询的上下文中,它的两个实例必须是相同的(就像代数一样)。查询只对 Pokemon 的值进行合一,使得这两个谓词都成立。例如,水/冰属性的 [Dewgong(白海狮)](https://bulbapedia.bulbagarden.net/wiki/Dewgong_(Pok%C3%A9mon))是一个解,因为我们的程序包含以下两个事实: - -``` -type(dewgong, water). -type(dewgong, ice). -``` - -因此,用 dewgong 替换 Pokemon 变量满足查询。相比之下,Squirtle 只是水属性:存在 pokemon(squirtle, water),但没有 pokemon(squirtle, ice)。查询要求两者都合一,所以 squirtle 不是 Pokemon 的可能取值。 - -宝可梦有很多数据可以玩。[Iron Bundle(铁包袱)](https://bulbapedia.bulbagarden.net/wiki/Iron_Bundle_(Pok%C3%A9mon))是一只很强力的水/冰属性宝可梦,特攻很高。到底有多高? +Iron Bundle 是一只水/冰属性宝可梦,特攻很高。具体多高? ``` ?- pokemon_spa(ironbundle, SpA). - SpA = 124. + SpA = 124. ``` 特攻这么高,我们想利用强力的特殊招式。Iron Bundle 会哪些特殊招式? ``` ?- learns(ironbundle, Move), move_category(Move, special). - Move = aircutter -; Move = blizzard -; Move = chillingwater -; Move = freezedry -; Move = hydropump -; Move = hyperbeam -; Move = icebeam -; Move = icywind -; Move = powdersnow -; Move = swift -; Move = terablast -; Move = waterpulse -; Move = whirlpool. + Move = blizzard +; Move = freezedry +; Move = hydropump +; Move = icebeam +; Move = icywind +; ... ``` -Freeze-Dry(冷冻干燥)是一个特别好的特殊招式。下面是一个查询,找出所有特攻大于 120、会 Freeze-Dry 的冰属性宝可梦。 +Freeze-Dry 是一个特别好的特殊招式。找出所有特攻大于 120、会 Freeze-Dry 的冰属性宝可梦: ``` ?- pokemon_spa(Pokemon, SpA), SpA #> 120, learns(Pokemon, freezedry), type(Pokemon, ice). - Pokemon = glaceon, SpA = 130 -; Pokemon = kyurem, SpA = 130 -; Pokemon = kyuremwhite, SpA = 170 -; Pokemon = ironbundle, SpA = 124 -; false. + Pokemon = glaceon, SpA = 130 +; Pokemon = kyurem, SpA = 130 +; Pokemon = kyuremwhite, SpA = 170 +; Pokemon = ironbundle, SpA = 124. ``` -在继续之前,最后一个概念:规则(Rules)。规则有头部(head)和主体(body),如果主体为真,则规则合一。 +最后一个概念:**规则**(Rules)。规则有头部和主体,如果主体为真,则规则合一: -如果一个招式是物理招式或特殊招式,它就被认为是一个伤害招式。谓词 damaging_move/2 定义了所有造成直接伤害的招式。 - -``` +```prolog damaging_move(Move) :- - move_category(Move, physical) + move_category(Move, physical) ; move_category(Move, special). ``` -这将与任何造成直接伤害的招式合一。 - ``` ?- damaging_move(tackle). - true. + true. ?- damaging_move(rest). - false. + false. ``` ## SQL 对比 -到目前为止,我展示的内容在逻辑上并不复杂——只是关于各种事实的"与"和"或"语句。它本质上是一个被美化的查找表。不过,请花一点时间来体会一下,查询这个数据库比常见的替代方案(比如 SQL)要舒服多少。 +到目前为止展示的内容在逻辑上并不复杂——只是关于各种事实的"与"和"或"语句。不过请花一点时间体会一下,查询这个数据库比 SQL 舒服多少。 -对于到目前为止我们看到的事实,我可能会这样设置 SQL 表: +我会这样设置 SQL 表: ```sql --- 省略其他能力值以保持简洁 CREATE TABLE pokemon (pokemon_name TEXT, special_attack INTEGER); CREATE TABLE pokemon_types(pokemon_name TEXT, type TEXT); CREATE TABLE pokemon_moves(pokemon_name TEXT, move TEXT, category TEXT); ``` -把属性放在单独的表中而不是用 type_1 和 type_2 列,可能看起来有点刻意。这取决于具体用例,但由于哪个属性在前并不影响,你每次检查特定属性时都得查两个字段,我觉得这更容易出错。 - -然后像这样查询: +然后查询特攻 > 120、会 Freeze-Dry 的冰属性宝可梦: ```sql SELECT DISTINCT pokemon, special_attack FROM pokemon as p -WHERE - p.special_attack > 120 - AND EXISTS ( - SELECT 1 - FROM pokemon_moves as pm - WHERE p.pokemon_name = pm.pokemon_name AND move = 'freezedry' - ) - AND EXISTS ( - SELECT 1 - FROM pokemon_types as pt - WHERE p.pokemon_name = pt.pokemon_name AND type = 'ice' - ); +WHERE p.special_attack > 120 + AND EXISTS (SELECT 1 FROM pokemon_moves as pm + WHERE p.pokemon_name = pm.pokemon_name AND move = 'freezedry') + AND EXISTS (SELECT 1 FROM pokemon_types as pt + WHERE p.pokemon_name = pt.pokemon_name AND type = 'ice'); ``` -作为对比,再次给出等效的 Prolog 查询: +对比等效的 Prolog 查询: ``` -?- pokemon_spa(Pokemon, SpA), -SpA #> 120, -learns(Pokemon, freezedry), -type(Pokemon, ice). +?- pokemon_spa(Pokemon, SpA), SpA #> 120, learns(Pokemon, freezedry), type(Pokemon, ice). ``` -我不是在黑 SQL——我很喜欢 SQL——但这是大多数人接触过的最好的声明式查询语言了。Prolog 版本如此简单和灵活,真是令人惊叹。如果我们继续添加更多条件,SQL 查询会变得难以管理,而 Prolog 查询仍然易于阅读和编辑(一旦你掌握了变量的用法)。 +我不是在贬低 SQL——我很喜欢 SQL——但 Prolog 版本简单和灵活得令人惊叹。如果我们继续添加更多条件,SQL 查询会变得难以管理,而 Prolog 查询仍然易于阅读和编辑。 ## 升级 -基础讲完了,现在说说我正在做的项目的背景。 +宝可梦对战拥有数量惊人的机制,以复杂且概率性的方式相互影响。我尚未提及的部分机制: -宝可梦对战拥有数量惊人的机制,它们以复杂且概率性的方式相互影响。这些游戏的部分吸引力在于徒劳地试图比对手更好地记住所有机制,利用这些信息来预测和智取对方的计划。这有点像一种很傻的扑克。 +- 某些招式有一定概率落空 +- 某些招式会提升或降低能力值 +- 宝可梦可以携带具有各种效果的物品 +- 伤害计算不是恒定的,而是呈正态分布 +- 宝可梦可以被冰冻、灼伤、麻痹、中毒或陷入睡眠 +- 各种场地效果(天气、戏法空间等)会改变招式伤害和出手顺序 +- 每只宝可梦都有一个特性(如漂浮免疫地面招式、降雨改变天气、强行增伤 1.3 倍) +- 玩家分配努力值提升选定能力值 -我尚未提及的一小部分游戏机制: +如果你想为这个游戏构建软件,挑战在于在所有复杂性的建模过程中不疯掉。Prolog 在这方面出奇地擅长,主要有两个原因: -- 某些招式有一定概率落空,不造成伤害。 -- 某些招式会提升或降低宝可梦的能力值。 -- 宝可梦可以携带具有各种效果的物品。 -- 伤害计算不是恒定的;招式的伤害在计算范围内呈正态分布。 -- 宝可梦可以被冰冻、灼伤、麻痹、中毒或陷入睡眠;这些都有各种负面效果。 -- 各种场地效果(如天气、场地、戏法空间)会改变招式伤害、出手顺序等。 -- 每只宝可梦都有一个特性,具有各种效果,例如:漂浮(Levitate)使你对地面招式免疫,降雨(Drizzle)在宝可梦上场时把天气变成下雨,强行(Sheer Force)禁用招式的副作用但将伤害乘以 1.3 倍。 -- 玩家在游戏前会(不可见地)为每只宝可梦分配努力值,以提升选定能力值。根据他们如何构建队伍,每只宝可梦可能比你预期的造成更多伤害或更能抗伤。 +- 查询模型擅长描述临时组合 +- 数据模型非常适合以一致的方式分层叠加规则 -如果你想为这个游戏构建软件,挑战在于要在不疯掉的情况下对所有复杂性进行建模。Prolog 在这方面出奇地擅长,主要有两个原因: +为了说明这一点,以下是我为宝可梦选秀联赛实现优先度招式的过程。 -看看这个[伤害计算器](https://calc.pokemonshowdown.com/),你就明白我的意思了。 +宝可梦选秀大致就是字面意思。宝可梦根据实力被赋予分值,每个玩家获得一定分数,轮流选直到用完。你的队伍最终会有大约 8-11 只宝可梦,每周你和联赛中的另一个人正面交锋。 -- 查询模型擅长描述临时组合。 -- 数据模型非常适合以一致的方式分层叠加规则。 +我定义的队伍: -听众中的逻辑学家大概会想让我指出,查询模型和数据模型实际上是完全相同的。 - -为了说明这一点,这里是我如何为我的宝可梦选秀联赛实现优先度招式的。 - -宝可梦选秀大致就是字面意思。宝可梦根据实力被赋予一个分值,每个玩家获得一定数量的分数,你们轮流选直到每个玩家花完所有分数。你的队伍最终会有大约 8-11 只宝可梦,每周你和联赛中的另一个人正面交锋。几年前,我的朋友兼 [WMI](https://wemakeinter.net/) 合作者 [Morry](https://wttdotm.com/) 邀请我加入他的联赛,从那以后我就迷上了这个赛制。 - -比赛是 6v6,所以对战的一大部分是为你对手可能带来的所有六只组合做好准备,并组合出你自己的六只来应对所有情况。 - -当然,你只能用你选到的宝可梦来组建队伍。我只是用我的名字做了谓词:alex/1。 - -``` +```prolog alex(meowscarada). alex(weezinggalar). alex(swampertmega). @@ -340,193 +262,148 @@ alex(beartic). alex(dusclops). ``` -我可不自豪选了一个雨天队。这大概是我开始以来最糟糕的选秀;这种事偶尔会发生。 - 我的宝可梦里有哪些会 Freeze-Dry? ``` ?- alex(Pokemon), learns(Pokemon, freezedry). - false. + false. ``` 一个都没有。唉。 -非常重要的一类招式为优先度招式。之前我提到速度能力值决定哪只宝可梦先出手。这里有一些细微之处:使用最高优先度招式的宝可梦先出手,如果它们都选择了相同优先度的招式,那么速度更快的一方先出手。 - -大多数招式的优先度为零。 +非常重要的一类招式为**优先度招式**。大多数招式的优先度为零: ``` ?- move_priority(Move, P). - Move = '10000000voltthunderbolt', P = 0 -; Move = absorb, P = 0 -; Move = accelerock, P = 1 -; Move = acid, P = 0 -; Move = acidarmor, P = 0 -; Move = aciddownpour, P = 0 -; Move = acidspray, P = 0 -; Move = acrobatics, P = 0 -; Move = acupressure, P = 0 -; Move = aerialace, P = 0 -; Move = aeroblast, P = 0 + Move = absorb, P = 0 +; Move = accelerock, P = 1 +; Move = acid, P = 0 +; ... ``` -啊,但不是全部!Accelerock(冲岩)的优先度为 1。使用 Accelerock 的宝可梦会先于任何使用优先度 0(或更低)招式的宝可梦行动,即使后者有更高的速度能力值。 +Accelerock 的优先度为 1。使用它的宝可梦会先于任何使用优先度 0 招式的宝可梦行动,即使后者速度更高。 -我定义了一个 learns_priority/3 谓词,它合一于一只宝可梦、它学会的优先度招式以及该招式的优先度。 +我定义一个 `learns_priority/3` 谓词: -``` +```prolog learns_priority(Pokemon, Move, P) :- - learns(Pokemon, Move), - move_priority(Move, P), - P #> 0. + learns(Pokemon, Move), + move_priority(Move, P), + P #> 0. ``` -一个简单的查询——"我的队伍学会了哪些优先度招式"——返回了大量答案。 +"我的队伍学会了哪些优先度招式"——返回了大量答案,但很多是双打专用招式。过滤掉双打招式和保护招式: -``` -?- alex(Pokemon), learns_priority(Pokemon, Move, Priority). - Pokemon = meowscarada, Move = endure, Priority = 4 -; Pokemon = meowscarada, Move = helpinghand, Priority = 5 -; Pokemon = meowscarada, Move = protect, Priority = 4 -; Pokemon = meowscarada, Move = quickattack, Priority = 1 -; Pokemon = meowscarada, Move = allyswitch, Priority = 2 -; Pokemon = meowscarada, Move = suckerpunch, Priority = 1 -; Pokemon = weezinggalar, Move = endure, Priority = 4 -; Pokemon = weezinggalar, Move = protect, Priority = 4 -; Pokemon = swampertmega, Move = bide, Priority = 1 -; Pokemon = swampertmega, Move = endure, Priority = 4 -; Pokemon = swampertmega, Move = helpinghand, Priority = 5 -; Pokemon = swampertmega, Move = protect, Priority = 4 -; Pokemon = swampertmega, Move = wideguard, Priority = 3 -; Pokemon = latios, Move = allyswitch, Priority = 2 -; Pokemon = latios, Move = endure, Priority = 4 -; Pokemon = latios, Move = helpinghand, Priority = 5 -; Pokemon = latios, Move = magiccoat, Priority = 4 -; Pokemon = latios, Move = protect, Priority = 4 -; Pokemon = volcarona, Move = endure, Priority = 4 -; Pokemon = volcarona, Move = protect, Priority = 4 -; Pokemon = volcarona, Move = ragepowder, Priority = 2 -; Pokemon = tornadus, Move = endure, Priority = 4 -; Pokemon = tornadus, Move = protect, Priority = 4 -; Pokemon = politoed, Move = detect, Priority = 4 -; Pokemon = politoed, Move = endure, Priority = 4 -; Pokemon = politoed, Move = helpinghand, Priority = 5 -; Pokemon = politoed, Move = protect, Priority = 4 -; Pokemon = politoed, Move = bide, Priority = 1 -; Pokemon = archaludon, Move = endure, Priority = 4 -; Pokemon = archaludon, Move = protect, Priority = 4 -; Pokemon = beartic, Move = aquajet, Priority = 1 -; Pokemon = beartic, Move = bide, Priority = 1 -; Pokemon = beartic, Move = endure, Priority = 4 -; Pokemon = beartic, Move = protect, Priority = 4 -; Pokemon = dusclops, Move = allyswitch, Priority = 2 -; Pokemon = dusclops, Move = endure, Priority = 4 -; Pokemon = dusclops, Move = helpinghand, Priority = 5 -; Pokemon = dusclops, Move = protect, Priority = 4 -; Pokemon = dusclops, Move = shadowsneak, Priority = 1 -; Pokemon = dusclops, Move = snatch, Priority = 4 -; Pokemon = dusclops, Move = suckerpunch, Priority = 1 -; false. -``` - -虽然这在技术上是对的(最好的一种对),但大多数答案实际上没什么用。帮助手(Helping Hand)和交换场地(Ally Switch)优先度很高,但它们只在双打对战中有用,而我不是在玩那个模式。 - -为了解决这个问题,我定义了所有双打招式并将它们排除。我也会排除招式变圆(Bide),它在功能上没用。\\+/1 谓词的意思是"如果这个目标失败则为真",而 dif/2 表示"这两个项不同"。 - -``` +```prolog learns_priority(Mon, Move, Priority) :- - learns(Mon, Move), - \+ doubles_move(Move), - dif(Move, bide), - move_priority(Move, Priority), - Priority #> 0. + learns(Mon, Move), + \+ doubles_move(Move), + \+ protection_move(Move), + Move \= bide, + move_priority(Move, Priority), + Priority #> 0. doubles_move(helpinghand). doubles_move(allyswitch). doubles_move(ragepowder). -doubles_move(widesuard). -doubles_move(snatch). -doubles_move(magiccoat). +protection_move(detect). +protection_move(protect). +protection_move(endure). +protection_move(magiccoat). ``` -搞定!这个查询只返回我的队伍相关的优先度招式。 - -## 组队 - -在实践中重要的事情是组建一个实际的六人队伍。队伍由你选到的宝可梦构成,好的队伍是对称的:如果你的一只宝可梦弱于某种属性,你队伍里的其他宝可梦应该能够应对那种属性。 - -你可以非常自然地用 Prolog 规则来编程这类约束,然后迭代它们,混合搭配组合,直到找到一个感觉对的方案。 - -我是这样定义队伍的: +搞定!结果精简为真正有用的优先度招式: ``` -team_size([_,_,_,_,_,_]). +?- alex(Pokemon), learns_priority(Pokemon, Move, Priority). + Pokemon = meowscarada, Move = quickattack, Priority = 1 +; Pokemon = meowscarada, Move = suckerpunch, Priority = 1 +; Pokemon = beartic, Move = aquajet, Priority = 1 +; Pokemon = dusclops, Move = shadowsneak, Priority = 1 +; Pokemon = dusclops, Move = suckerpunch, Priority = 1. ``` -这只与恰好有六个元素的列表合一。在谓词里数到六有点烦人,但我把它当作一个练习数数的机会。 +优先度招式的缺乏实际上是我的队伍的一大弱点。 -好的队伍需要平衡。这是一个定义平衡的谓词: +同样地查询对手的优先度招式也非常有用: + +``` +?- morry(Pokemon), learns_priority(Pokemon, Move, Priority). + Pokemon = mawilemega, Move = suckerpunch, Priority = 1 +; Pokemon = walkingwake, Move = aquajet, Priority = 1 +; ... +``` + +此时,Morry 提了一个挑战:恶作剧之心特性的宝可梦,其变化招式额外获得 +1 优先度。能否在规则中体现? + +我的队伍恰好有一只这样的宝可梦——Tornadus。使用 Prolog 的 if/then 结构 `->/2`,三分钟搞定: ```prolog -balanced_team(Team) :- - team_size(Team), - member(Pokemon1, Team), - member(Pokemon2, Team), - Pokemon1 \= Pokemon2, - type(Pokemon1, Type11), - type(Pokemon2, Type21), - weak_to(Type11, Type21). +learns_priority(Mon, Move, Priority) :- + learns(Mon, Move), + \+ doubles_move(Move), + \+ protection_move(Move), + Move \= bide, + move_priority(Move, BasePriority), + ( + pokemon_ability(Mon, prankster), move_category(Move, status) -> + Priority #= BasePriority + 1 + ; Priority #= BasePriority + ), + Priority #> 0. ``` -等等,这不对。实际上 Prolog 对什么为真什么为假非常严格,所以让我更仔细地想想…… +现在查询会包含 Tornadus 所有变化招式的提升后优先度。 -```prolog -balanced_team(Team) :- - team_size(Team), - % 对于队伍中的所有 Pokemon1 - findall(Type1, (member(P, Team), type(P, Type1)), Types1), - % 检查 P1 的每个属性弱点是否都有某个 P2 抵抗它 - forall( - (member(P1, Team), type(P1, T1), weak_to(T1, T2)), - (member(P2, Team), P1 \= P2, type(P2, T2)) - ). -``` +## 与电子表格的比较 -好吧,我不会假装我是 Prolog 专家——这些代码大部分第一次都没跑通——但 Prolog 的美妙之处在于,一旦你把事实搞对了,逻辑往往就水到渠成了。 +宝可梦社区已经有类似的工具,构建在最优秀的编程界面上:朴素的电子表格。 -## Prolog 的特别之处 +![Techno 的准备文档](/images/pokemon/matchup-sheet.png) -我在 Python、JavaScript、SQL 和各种函数式语言上花了很多时间,Prolog 确实感觉与众不同。 +{{< caption >}}Techno 的准备文档,一份功能强大的 Google Sheets。{{< /caption >}} -我最大的领悟是:**Prolog 迫使你思考什么是真的,而不是做什么。** 在命令式编程中,你大部分精力花在控制流上——数据如何移动、以什么顺序执行。在 Prolog 中,你只需陈述什么是真的,然后让求解器来处理剩下的事情。 +我使用一份被称为"Techno's Prep Doc"的 Google Sheets,输入队伍后自动生成海量对阵信息。 -对于宝可梦对战——本质上是一个有着数千条互动规则的巨大规则引擎——这简直是天启。不用写 if/else 链来检查属性相克,你只需声明属性表,让 Prolog 处理其余部分。 +我好奇它的优先度招式查找公式是怎样的。 -例如,要找出你的哪只宝可梦能够对水/地面属性的 Swampert 造成效果绝佳的伤害: +![优先级招式后端列表](/images/pokemon/priority-backend-list.png) + +{{< caption >}}电子表格后端的硬编码招式列表。{{< /caption >}} + +结果是——相当复杂: ``` -?- alex(P), learns(P, Move), move_type(Move, Type), super_effective(Type, water), super_effective(Type, ground). +={IFERROR(ARRAYFORMULA(VLOOKUP(FILTER(INDIRECT(Matchup!$S$3&"!$AV$4:$AV"), +INDIRECT(Matchup!$S$3&"!$AT$4:$AT")="X"), +{Backend!$L$2:$L,Backend!$F$2:$F},2,FALSE))), +IFERROR(FILTER(INDIRECT(Matchup!$S$3&"!$AW$4:$AW"), +INDIRECT(Matchup!$S$3&"!$AT$4:$AT")="X"))} ``` -这一个查询就把你的队伍名单、招式池数据、招式属性和属性相克表组合成了一个简洁的语句。用 Python 试试看。 +Prolog 的范式显然更具可扩展性。电子表格后端是一个硬编码的显要招式列表,而我的数据库可以查找**任何**招式。这个查询——找出 Tornadus 学会的、对 Justin 队伍中任何成员效果绝佳的特殊招式——在现有工具中根本不存在。我只用了 30 秒就拼出来了: + +``` +?- justin(Target), learns(tornadus, Move), + super_effective_move(Move, Target), move_category(Move, special). + Target = charizardmegay, Move = chillingwater +; Target = scizor, Move = heatwave +; Target = scizor, Move = incinerate +; Target = screamtail, Move = sludgebomb +; ... +``` ## 最后的思考 这个项目始于一个玩笑——"如果我拿 Prolog 来做宝可梦组队会怎样"——但它教给我的逻辑编程知识比任何教科书都多。 -如果你感兴趣,我强烈推荐: +我最大的领悟是:**Prolog 迫使你思考什么是真的,而不是做什么。** 在命令式编程中,大部分精力花在控制流上。在 Prolog 中,你只需陈述什么是真的,让求解器处理剩下的事。 + +对于一个有着数千条互动规则的规则引擎(比如宝可梦对战),这简直是天启。与其写 if/else 链检查属性相克,不如声明属性表,让 Prolog 处理其余部分。 + +如果你感兴趣,推荐: 1. 安装 SWI-Prolog 并玩玩 [prologdex](https://github.com/alexpetros/prologdex) 数据集 2. 阅读 [Adventure in Prolog](http://www.amzi.com/AdventureInProlog/) 教程 -3. 尝试用 Prolog 对你熟悉的领域建模——它会彻底改变你对数据和关系的思考方式 +3. 用 Prolog 对你熟悉的领域建模——它会彻底改变你对数据和关系的思考方式 -祝你编码愉快,愿你的属性相克永远是效果绝佳。 - ---- - ---- - -> **译者注:** -> 原文作者:Alexander Petros -> 原文标题:Prolog Basics Explained with Pokémon -> 原文链接:https://unplannedobsolescence.com/blog/prolog-basics-pokemon/ -> 本文为中文翻译转载。 +祝编码愉快,愿你的属性相克永远是效果绝佳。 diff --git a/layouts/shortcodes/caption.html b/layouts/shortcodes/caption.html new file mode 100644 index 0000000..c1e6d43 --- /dev/null +++ b/layouts/shortcodes/caption.html @@ -0,0 +1 @@ +
{{ .Inner | markdownify }}
diff --git a/static/images/pokemon/archeops.png b/static/images/pokemon/archeops.png new file mode 100644 index 0000000..6f43ae8 Binary files /dev/null and b/static/images/pokemon/archeops.png differ diff --git a/static/images/pokemon/dipplin.png b/static/images/pokemon/dipplin.png new file mode 100644 index 0000000..166ac9b Binary files /dev/null and b/static/images/pokemon/dipplin.png differ diff --git a/static/images/pokemon/matchup-sheet.png b/static/images/pokemon/matchup-sheet.png new file mode 100644 index 0000000..6a2b4e4 Binary files /dev/null and b/static/images/pokemon/matchup-sheet.png differ diff --git a/static/images/pokemon/pikachu.png b/static/images/pokemon/pikachu.png new file mode 100644 index 0000000..846798a Binary files /dev/null and b/static/images/pokemon/pikachu.png differ diff --git a/static/images/pokemon/priority-backend-list.png b/static/images/pokemon/priority-backend-list.png new file mode 100644 index 0000000..bf0cb7b Binary files /dev/null and b/static/images/pokemon/priority-backend-list.png differ diff --git a/static/images/pokemon/scizor-stats.png b/static/images/pokemon/scizor-stats.png new file mode 100644 index 0000000..c1efd30 Binary files /dev/null and b/static/images/pokemon/scizor-stats.png differ diff --git a/static/images/pokemon/surf.png b/static/images/pokemon/surf.png new file mode 100644 index 0000000..00a780a Binary files /dev/null and b/static/images/pokemon/surf.png differ diff --git a/static/images/pokemon/type-chart.svg b/static/images/pokemon/type-chart.svg new file mode 100644 index 0000000..a43976c --- /dev/null +++ b/static/images/pokemon/type-chart.svg @@ -0,0 +1,819 @@ + + + + + + 2 + + + + 0 + + + + ½ + + + + + + + + + + + + + + + + + + + Attacker + Atacante + 공격 + + 攻撃攻擊嗰方AT + + Defender + Defensor + 방어 + + 防御防守嗰方DEF + + + + + + + + + + + + + + + + + + + + + + + + + 一般一般一般一般一般 + Normální + Normal + Normal + Φυσιολογικός + Normal + Normala + Normal + Normaali + Normal + רגיל + नॉर्मल + Normál + Normal + Normale + ノーマル + 노말 + Normal + Biasa + Normaal + Normal + Normalny + Normal + Normal + Обычный + Normal + ปกติ + Normal + Thường + + + 一般普通Normal + + + 火火火火火 + Огнени + Ohnivý + Tân + Ild + Feuer + Φωτιάς + Fire + Fajra + Fuego + Tuli + Feu + אש + फ़ायर + Tűz + Api + Eld + Fuoco + ほのお + 불꽃 + Feier + Api + Vuur + Ild + Ognisty + Fogo + Foc + Огонь + Eld + ไฟ + Ateş + Lửa + + + 火火Fire + + + 水水水水水 + Vodní + Vand + Wasser + Νερού + Water + Akva + Agua + Vesi + Eau + מים + वॉटर + Víz + Air + Vatn + Acqua + みず + 물 + Waasser + Air + Water + Vann + Wodny + Água + Apă + Вода + Vatten + น้ำ + Su + Nước + + + 水水Water + + + Planta草草草草草 + Растителни + Travní + Græs + Pflanze + Φυτού + Grass + Planta + Planta + Ruoho + Plante + עשב + ग्रास + Fű + Daun + Erba + くさ + 풀 + Gras + Rumput + Gras + Gress + Trawiasty + Erva + + Iarbă + Трава + Gräs + หญ้า + Bitki + Cỏ + + + 草草Grass + + + + 电電電電電 + Elektrický + + Elektro + Ηλεκτρισμού + Electric + Eléctrico + Sähkö + Électrique + חשמל + इलेक्ट्रिक + Elektromos + Listrik + Elding + Elettro + でんき + 전기 + Elektrik + Elektrisch + Elektryczny + Elétrico + Electricitate + Электро + ไฟฟ้า + Elektrik + Điện + + + + ElektriskElektriskElektrisk電電Electric + + + 冰冰冰冰冰 + Ledový + Is + Eis + Πάγου + Ice + Hielo + Jää + Glace + קרח + आइस + Jég + Es + Ís + Ghiaccio + こおり + 얼음 + Ais + IJs + Is + Lodowy + Gelo + Gheață + Лёд + Ľadový + Is + น้ำแข็ง + Buz + Băng + + + 冰冰Ice + + + + 格斗格鬥格鬥格鬥格鬥 + Bojový + Kamp + Kampf + Μαχητής + Fighting + Lucha + Taistelu + Combat + לחימה + फ़ाइटिंग + Harcos + Petarung + Lotta + かくとう + 격투 + Berlawan + Vecht + Slåss + Walczący + Luta + Luptă + Сражение + Strids + ต่อสู้ + Dövüşçü + Giác đấu + + + + 格鬥格鬥Fighting + + + 毒毒毒毒毒 + Jedovatý + Gift + Gift + Δηλητηρίου + Poison + Veneno + Myrkky + Poison + רעל + पॉइज़न + Méreg + Racun + Veleno + どく + 독 + Racun + Gif + Gift + Trujący + Veneno + Otravă + Яд + Gift + พิษ + Zehir + Độc + + + 毒毒Poison + + + Terrestre地面地面地面地面地面 + Zemní + Jord + Boden + Εδάφους + Ground + Tierra + Maa + Sol + אדמה + भूमि + Föld + Tanah + Terra + じめん + 땅 + Darat + Grond + Grund + Ziemny + Terra + + Pământ + Земля + Mark + ดิน + Yer + Đất + + + 地面地面Ground + + + 飞行Voador飛行飛行飛行飛行 + Flyvende + Létající + Flyve + Flug + Ιπτάμενος + Flying + Volador + Lento + Vol + מעופף + फ़्लाइंग + Repülő + Terbang + Volante + ひこう + 비행 + Terbang + Vlieg + Latający + + Zbor + Летающий + Flygande + บิน + Uçan + Bay + + + + Voador飛行飛行Flying + + + PsychiquePsíquico超能力超能力超能力超能力超能力 + Psychický + Synsk + Psycho + Μέντιουμ + Psychic + Psíquico + Meedio + Psy + + על חושי + साइकिक + Pszichikus + Psychic + Psico + エスパー + 에스퍼 + Psikik + Psychisch + Psykisk + Psychiczny + + Psihic + Психо + Psykisk + พลังจิต + Psişik + Siêu năng + + + Psíquico超能力超能力Psychic + + + Inseto虫蟲蟲蟲蟲 + Hmyzí + Kryb + Käfer + Εντόμου + Bug + Bicho + Ötökkä + Insecte + חרק + बग + Bogár + Serangga + Coleottero + むし + 벌레 + Serangga + Insect + Insekt + Robak + Insecto + + Insectă + Насекомое + Insekt + แมลง + Böcek + Côn trùng + + + + 蟲蟲Bug + + + Pedra岩石岩石岩石岩石岩石 + Kamenný + Sten + Gestein + Πέτρας + Rock + Roca + Kivi + Roche + סלע + रॉक + Szikla + Bebatuan + Roccia + いわ + 바위 + Batu + Steen + Stein + Kamienny + + Piatră + Камень + Sten + หิน + Kaya + Đá + + + Pedra岩石岩石Rock + + + 幽灵Fantasma幽靈幽靈幽靈幽靈 + Призрачни + Spøgelse + Φάντασμα + Fantasma + Kummitus + Spøkelse + + Привидение + Duchový + Geist + Ghost + Spectre + רוח + घोस्ट + Szellem + Hantu + Spettro + ゴースト + 고스트 + Hantu + Geest + Duch + Fantomă + Spöke + ผี + Hayalet + Ma + + + + Fantasma幽靈鬼魂Ghost + + + 龙Dragão龍龍龍龍 + Dračí + Drage + Drache + Δράκου + Dragon + Dragón + Lohikäärme + Dragon + דרקון + ड्रैगन + Sárkány + Naga + Drago + ドラゴン + 드래곤 + Naga + Draak + Drage + Smok + + Dragon + Дракон + Drake + มังกร + Ejderha + Rồng + + + + Dragão龍龍Dragon + + + Sombrio恶惡惡惡惡 + Temný + Mørke + Unlicht + Σκοταδιού + Dark + Siniestro + Pimeys + Ténèbres + אופל + डार्क + Sötét + Kegelapan + Buio + あく + 악 + Gelap + Duister + Mørk + Mroczny + Escuridão + + Întuneric + Темнота + Mörker + มืด + Karanlık + Bóng tối + + + + 惡惡Dark + + + 钢Aço鋼鋼鋼鋼 + Ocelový + Stål + Stahl + Μετάλλου + Steel + Acero + Teräs + Acier + פלדה + स्टील + Acél + Logam + Acciaio + はがね + 강철 + Besi + Staal + Stål + Stalowy + + Oțel + Сталь + Stål + โลหะ + Çelik + Thép + + + + Aço鋼鋼Steel + + + Fada妖精妖精妖精妖精妖精 + Vílí + Fe + Fee + Νεράιδα + Fairy + Hada + Keiju + Fée + פיה + फ़ेरी + Tündér + Peri + Folletto + フェアリー + 페어리 + Pari + Fairy + Fe + Baśniowy + + Zână + Фея + Fe + แฟรี่ + Peri + Tiên + + + Fada妖精妖精Fairy + + + + + + + + + + + + + + + + + + + + + + + + + + 1× + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +