使用决策树 实现智能游戏 AI
1. 简介
在游戏开发中,人工智能(AI) 扮演着至关重要的角色。本教程将介绍如何利用 Dora SSR 引擎提供的 C4.5 决策树 算法来创建智能的游戏 AI。我们将通过一个简单的示例,逐步学习这一过程。
1.1 什么是决策树?
决策树是一种类似于流程图的结构,用于辅助决策。想象一下我们在玩“猜动物”的游戏:
这就是一个简单的决策树示例。在游戏 AI 中,我们可以使用类似的结构来做出智能决策。
2. 准备工作
首先,我们需要准备训练数据。假设我们正在开发一个简单的格斗游戏 AI,需要决定何时攻击、防守或逃跑。
2.1 准备训练数据(CSV 格式)
训练数据的格式说明:
- 第一行:包含所有特征的名称,例如“距离”、“敌人血量”等。
- 第二行:定义每个特征的数据类 型,其中:
C
表示分类(Categorical)数据,如“近”、“远”等离散值。N
表示数值(Numerical)数据,如具体的血量数值。
- 第三行开始:实际的训练数据,每行代表一个训练样本。
- 最后一列:决策结果,即 AI 应采取的行动,这是决策树要学习预测的目标值,可以是分类值或数值。
距离,敌人血量,我方血量,行为
C,C,C,C
近,高,高,攻击
近,低,高,攻击
远,高,低,逃跑
中,中,低,防守
远,低,高,攻击
3. 基础代码实现
让我们通过这组训练数据训练并生成一个决策树,以实现简单的战斗 AI:
- Lua
- Teal
- TypeScript
- YueScript
local thread <const> = require("thread")
local ML <const> = require("ML")
-- 准备训练数据
local trainingData = [[
距离,敌人血量,我方血量,行为
C,C,C,C
近,高,高,攻击
近,低,高,攻击
远,高,低,逃跑
中,中,低,防守
远,低,高,攻击
]]
-- 构建决策树
function buildDecisionTreeAsync()
local trainingResult = {}
-- 最大深度设置为 3
local accuracy, err = ML.BuildDecisionTreeAsync(trainingData, 3, function(depth, name, op, value)
-- 根据深度添加缩进
local line = string.rep("\t", depth + 1)
-- 处理叶子节点(结果节点)
if op == "return" then
line = line .. 'return "' .. value .. '"'
else
-- 构建条件语句
local valueStr = (op == '==' and '"' .. value .. '"' or value)
line = line .. "if " .. name .. " " .. op .. " " .. valueStr
end
table.insert(trainingResult, line)
end)
if err then
print("构建决策树时出错:", err)
return
end
print("决策树准确度:", accuracy)
print("决策树结构:\n" .. table.concat(trainingResult, "\n"))
return trainingResult
end
-- 用下面的代码测试异步构建决策树
thread(buildDecisionTreeAsync)
local thread <const> = require("thread")
local ML <const> = require("ML")
-- 准备训练数据
local trainingData = [[
距离,敌人血量,我方血量,行为
C,C,C,C
近,高,高,攻击
近,低,高,攻击
远,高,低,逃跑
中,中,低,防守
远,低,高,攻击
]]
-- 构建决策树
local function buildDecisionTreeAsync(): {string}
local trainingResult: {string} = {}
-- 最大深度设置为 3
local accuracy, err = ML.BuildDecisionTreeAsync(trainingData, 3, function(depth: integer, name: string, op: ML.Operator, value: string)
-- 根据深度添加缩进
local line = string.rep("\t", depth + 1)
-- 处理叶子节点(结果节点)
if op == "return" then
line = line .. 'return "' .. value .. '"'
else
-- 构建条件语句
local valueStr = (op == '==' and '"' .. value .. '"' or value)
line = line .. "if " .. name .. " " .. op .. " " .. valueStr
end
table.insert(trainingResult, line)
end)
if err then
print("构建决策树时出错:", err)
return
end
print("决策树准确度:", accuracy)
print("决策树结构:\n" .. table.concat(trainingResult, "\n"))
return trainingResult
end
-- 用下面的代码测试异步构建决策树
thread(buildDecisionTreeAsync)
import { ML, thread } from "Dora";
// 准备训练数据
const trainingData = `
距离,敌人血量,我方血量,行为
C,C,C,C
近,高,高,攻击
近,低,高,攻击
远,高,低,逃跑
中,中,低,防守
远,低,高,攻击
`;
// 构建决策树
const buildDecisionTreeAsync = () => {
const trainingResult: string[] = [];
// 最大深度设置为 3
const [accuracy, err] = ML.BuildDecisionTreeAsync(trainingData, 3, (depth, name, op, value) => {
// 根据深度添加缩进
let line = "\t".repeat(depth + 1);
// 处理叶子节点(结果节点)
if (op === "return") {
line += `return "${value}"`;
} else {
// 构建条件语句
const valueStr = (op === "==" ? `"${value}"` : value);
line += `if ${name} ${op} ${valueStr}`;
}
trainingResult.push(line);
});
if (err) {
print("构建决策树时出错:", err);
return trainingResult;
}
print("决策树准确度:", accuracy);
print("决策树结构:\n" + trainingResult.join("\n"));
return trainingResult;
};
// 用下面的代码测试异步构建决策树
thread(buildDecisionTreeAsync);
_ENV = Dora
-- 准备训练数据
trainingData = [[
距离,敌人血量,我方血量,行为
C,C,C,C
近,高,高,攻击
近,低,高,攻击
远,高,低,逃跑
中,中,低,防守
远,低,高,攻击
]]
-- 构建决策树
buildDecisionTreeAsync = ->
trainingResult = []
-- 最大深度设置为 3
accuracy, err = ML.BuildDecisionTreeAsync trainingData, 3, (depth, name, op, value) ->
-- 根据深度添加缩进
line = string.rep "\t", depth + 1
-- 处理叶子节点(结果节点)
if op == "return"
line ..= "return \"#{value}\""
else
-- 构建条件语句
valueStr = (op == "==" and "\"#{value}\"" or value)
line ..= "if #{name} #{op} #{valueStr}"
table.insert trainingResult, line
if err
print "构建决策树时出错: #{err}"
return
print "决策树准确度: #{accuracy}"
print "决策树结构:\n" .. table.concat trainingResult, "\n"
trainingResult
-- 用下面的代码测试异步构建决策树
thread buildDecisionTreeAsync
3.1 可视化生成的决策树
生成的决策树结构如下: