Files
simpleasm/frontend/src/lib/levels.js
Fam Zheng e465b1cf71 Initial commit: Simple ASM - ARM assembly learning game
10-level progressive game teaching ARM assembly basics:
registers, arithmetic, bitwise ops, memory, branching, loops.
Vue 3 + FastAPI + SQLite with K8s deployment.
2026-04-07 10:17:15 +01:00

377 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export const levels = [
// ===== Level 1: 认识寄存器 =====
{
id: 1,
title: '认识寄存器',
subtitle: '小机器人的记忆槽',
icon: '🤖',
description: '学习 MOV 指令给寄存器赋值',
tutorial: [
{
title: '什么是寄存器?',
text: 'CPU 是计算机的大脑,而**寄存器**是它手边的小抽屉 —— 速度最快的存储空间!我们的机器有 8 个寄存器:**R0** 到 **R7**。',
},
{
title: 'MOV 指令',
text: '`MOV` 把一个数字放进寄存器。注意数字前面要加 **#** 号,表示"这是一个数值"',
code: 'MOV R0, #42 ; 把 42 放进 R0\nMOV R1, #100 ; 把 100 放进 R1',
},
{
title: 'HLT 指令',
text: '程序最后要写 `HLT`halt = 停止),告诉机器"运行结束!"',
code: 'MOV R0, #42\nHLT',
},
],
goal: '把数字 **42** 放进 **R0** 寄存器',
initialState: {},
testCases: [{ init: {}, expected: { registers: { R0: 42 } } }],
hints: [
'MOV 的格式MOV 寄存器, #数字',
'试试MOV R0, #???',
'答案MOV R0, #42 然后 HLT',
],
starThresholds: [2, 3, 5],
starterCode: '; 把 42 放进 R0 寄存器\n; 提示:数字前面要加 # 号\n\n\nHLT',
showMemory: false,
},
// ===== Level 2: 数据搬运工 =====
{
id: 2,
title: '数据搬运工',
subtitle: '寄存器之间的复制',
icon: '📦',
description: '学习在寄存器之间复制数据',
tutorial: [
{
title: '寄存器间复制',
text: 'MOV 也能把一个寄存器的值**复制**到另一个(这时不需要 # 号):',
code: 'MOV R1, R0 ; 把 R0 的值复制到 R1',
},
{
title: '复制,不是移动!',
text: '虽然叫 "MOV"(移动),但其实是**复制**。执行后 R0 的值不变R1 变成和 R0 一样。',
},
],
goal: 'R0 已经有值 **7**,把它复制到 **R1** 和 **R2**',
initialState: { registers: { R0: 7 } },
testCases: [{ init: {}, expected: { registers: { R0: 7, R1: 7, R2: 7 } } }],
hints: [
'MOV 寄存器, 寄存器 —— 把右边复制到左边',
'MOV R1, R0 可以把 R0 复制到 R1',
'答案MOV R1, R0 / MOV R2, R0 / HLT',
],
starThresholds: [3, 4, 6],
starterCode: '; R0 = 7\n; 把 R0 复制到 R1 和 R2\n\n\nHLT',
showMemory: false,
},
// ===== Level 3: 加减法 =====
{
id: 3,
title: '加减法',
subtitle: '三操作数的威力',
icon: '',
description: '学习 ADD 和 SUB 指令',
tutorial: [
{
title: 'ADD —— 加法(三操作数)',
text: 'ARM 风格的加法很酷:**三个操作数**!第一个放结果,后两个是被运算的值:',
code: 'ADD R2, R0, R1 ; R2 = R0 + R1\nADD R0, R0, #10 ; R0 = R0 + 10',
},
{
title: 'SUB —— 减法',
text: 'SUB 同理,也是三操作数:',
code: 'SUB R2, R0, R1 ; R2 = R0 - R1\nSUB R0, R0, #5 ; R0 = R0 - 5',
},
{
title: '好处',
text: '三操作数的好处:可以直接把结果放到新的寄存器,**不用先复制**',
},
],
goal: 'R0=**15**R1=**27**,计算 R0+R1 存入 **R2**R0和R1不变',
initialState: { registers: { R0: 15, R1: 27 } },
testCases: [{ init: {}, expected: { registers: { R0: 15, R1: 27, R2: 42 } } }],
hints: [
'ADD 第一个参数放结果,后两个参数相加',
'ADD R2, R0, R1 —— 结果存入 R2',
'答案ADD R2, R0, R1 / HLT',
],
starThresholds: [2, 3, 5],
starterCode: '; R0=15, R1=27\n; 计算 R0 + R1结果存入 R2\n\n\nHLT',
showMemory: false,
},
// ===== Level 4: 乘法与除法 =====
{
id: 4,
title: '乘法与除法',
subtitle: '更强的算术能力',
icon: '✖️',
description: '学习 MUL 和 DIV 指令',
tutorial: [
{
title: 'MUL —— 乘法',
text: 'MUL 也是三操作数:',
code: 'MOV R0, #6\nMOV R1, #7\nMUL R2, R0, R1 ; R2 = 6 × 7 = 42',
},
{
title: 'DIV —— 除法(取整)',
text: 'DIV 做整数除法(只留整数部分):',
code: 'MOV R0, #100\nMOV R1, #4\nDIV R2, R0, R1 ; R2 = 100 ÷ 4 = 25',
},
],
goal: '计算 **6 × 7** 存入 R0**100 ÷ 4** 存入 R1',
initialState: {},
testCases: [{ init: {}, expected: { registers: { R0: 42, R1: 25 } } }],
hints: [
'先 MOV 数字到寄存器,再 MUL/DIV',
'MUL R0, R2, R3 可以把 R2×R3 的结果放到 R0',
'答案MOV R2, #6 / MOV R3, #7 / MUL R0, R2, R3 / MOV R2, #100 / MOV R3, #4 / DIV R1, R2, R3 / HLT',
],
starThresholds: [7, 9, 12],
starterCode: '; 计算 6×7 存入 R0\n; 计算 100÷4 存入 R1\n\n\nHLT',
showMemory: false,
},
// ===== Level 5: 位运算魔法 =====
{
id: 5,
title: '位运算魔法',
subtitle: '0和1的秘密',
icon: '🔮',
description: '学习 AND、ORR、EOR、MVN 指令',
tutorial: [
{
title: '二进制世界',
text: '计算机内部用 **0** 和 **1** 存储一切。42 的二进制是 `00101010`。右边面板会显示每个寄存器的二进制值!',
},
{
title: 'AND —— 都是1才是1',
text: 'AND 逐位比较,两个都是 1 结果才是 1。可以用来"提取"某些位:',
code: '; 11111111 (255)\n; AND 00001111 (15)\n; = 00001111 (15)\nAND R0, R0, #15',
},
{
title: '其他位运算',
text: '**ORR** = 有一个1就是1 (OR)\n**EOR** = 不同才是1 (XOR)\n**MVN** = 全部翻转 (NOT)',
code: 'ORR R0, R0, #240 ; 设置高4位\nEOR R0, R0, #255 ; 翻转低8位\nMVN R0, R0 ; 翻转所有位',
},
],
goal: 'R0 = **255** (二进制 11111111),用 AND 提取**低4位**,使 R0 变成 **15**',
initialState: { registers: { R0: 255 } },
testCases: [{ init: {}, expected: { registers: { R0: 15 } } }],
hints: [
'AND 用来保留某些位,把其他位清零',
'低4位的掩码是 15二进制 00001111',
'答案AND R0, R0, #15 / HLT',
],
starThresholds: [2, 3, 5],
starterCode: '; R0 = 255 (二进制 11111111)\n; 用 AND 提取低4位\n\n\nHLT',
showMemory: false,
},
// ===== Level 6: 移位操作 =====
{
id: 6,
title: '移位操作',
subtitle: '位的舞蹈',
icon: '↔️',
description: '学习 LSL 和 LSR 指令',
tutorial: [
{
title: 'LSL —— 逻辑左移',
text: '所有位向左移右边补0。**左移1位 = 乘以2**左移3位 = 乘以8',
code: '; 5 = 00000101\nLSL R0, R0, #1 ; 00001010 = 10 (×2)\nLSL R0, R0, #1 ; 00010100 = 20 (×2)',
},
{
title: 'LSR —— 逻辑右移',
text: '所有位向右移左边补0。**右移1位 = 除以2**',
code: 'MOV R0, #40\nLSR R0, R0, #1 ; 20 (÷2)\nLSR R0, R0, #2 ; 5 (÷4)',
},
{
title: '程序员的技巧',
text: '在真实的 ARM 处理器中,移位比乘除快得多!`LSL R0, R0, #3` 比 `MUL R0, R0, #8` 高效。',
},
],
goal: 'R0 = **5**,只用**移位操作**把它变成 **40**40 = 5 × 8 = 5 ×',
initialState: { registers: { R0: 5 } },
testCases: [{ init: {}, expected: { registers: { R0: 40 } } }],
hints: [
'8 = 2³乘以8就是左移3位',
'LSL R0, R0, #3',
'就这一条指令!',
],
starThresholds: [2, 3, 5],
blockedOps: ['MUL', 'DIV'],
starterCode: '; R0 = 5\n; 用 LSL 让 R0 变成 40不能用 MUL\n\n\nHLT',
showMemory: false,
},
// ===== Level 7: 内存读写 =====
{
id: 7,
title: '内存读写',
subtitle: '打开更大的空间',
icon: '💾',
description: '学习 LDR 和 STR 指令',
tutorial: [
{
title: '什么是内存?',
text: '寄存器只有8个太少了**内存**像一排256格的柜子每格有编号(0-255)。',
},
{
title: 'LDR —— 从内存读取',
text: '先把地址放进寄存器,再用 `LDR` 从那个地址读数据:',
code: 'MOV R1, #0 ; 地址 = 0\nLDR R0, [R1] ; R0 = 内存[0]',
},
{
title: 'STR —— 写入内存',
text: '`STR` 把寄存器的值写到内存:',
code: 'MOV R1, #5 ; 地址 = 5\nSTR R0, [R1] ; 内存[5] = R0',
},
{
title: '偏移寻址',
text: '还可以加偏移量:`[R1, #4]` 表示地址 R1+4',
code: 'MOV R1, #0\nLDR R0, [R1, #0] ; 内存[0]\nLDR R2, [R1, #1] ; 内存[1]',
},
],
goal: '内存[0]=**10**,内存[1]=**20**,计算它们的和存入 **内存[2]**',
initialState: { memory: { 0: 10, 1: 20 } },
testCases: [{ init: {}, expected: { memory: { 2: 30 } } }],
hints: [
'先用 LDR 把内存值读到寄存器,算完用 STR 写回',
'MOV R3, #0 设基地址LDR R0, [R3, #0] 读第一个值',
'答案MOV R3, #0 / LDR R0, [R3, #0] / LDR R1, [R3, #1] / ADD R2, R0, R1 / STR R2, [R3, #2] / HLT',
],
starThresholds: [6, 8, 10],
starterCode: '; 内存[0]=10, 内存[1]=20\n; 计算它们的和,存入内存[2]\n;\n; 提示:先 MOV 一个地址到寄存器\n; 然后用 LDR/STR 读写内存\n\n\nHLT',
showMemory: true,
memoryRange: [0, 15],
},
// ===== Level 8: 比较与跳转 =====
{
id: 8,
title: '比较与跳转',
subtitle: '让程序会做决定',
icon: '🔀',
description: '学习 CMP 和条件分支指令',
tutorial: [
{
title: '到目前为止...',
text: '程序都是从头到尾顺序执行。但有了**分支**,程序就能做决定了!',
},
{
title: 'CMP —— 比较',
text: '`CMP` 比较两个值,记住比较结果(不会改变它们的值):',
code: 'CMP R0, #10 ; 比较 R0 和 10',
},
{
title: '条件分支',
text: '比较后用 **B** (Branch=分支) 跳转:',
code: 'BEQ label ; 等于则跳Equal\nBNE label ; 不等则跳Not Equal\nBGT label ; 大于则跳Greater Than\nBLT label ; 小于则跳Less Than\nB label ; 无条件跳',
},
{
title: '标签',
text: '**标签**是代码里的记号,分支指令跳到标签位置。标签后面加冒号:',
code: 'CMP R0, #10\nBGT big\nMOV R1, #0 ; R0 <= 10\nB done ; 跳过下面\nbig:\nMOV R1, #1 ; R0 > 10\ndone:\nHLT',
},
],
goal: 'R0=**15**。如果 R0 > 10 则 R1 = **1**;否则 R1 = **0**',
initialState: { registers: { R0: 15 } },
testCases: [
{ init: { registers: { R0: 15 } }, expected: { registers: { R1: 1 } } },
{ init: { registers: { R0: 5 } }, expected: { registers: { R1: 0 } } },
{ init: { registers: { R0: 10 } }, expected: { registers: { R1: 0 } } },
],
hints: [
'先设 R1=#0默认再比较 R0 和 10',
'如果 R0 > 10跳到标签把 R1 改成 1',
'答案MOV R1, #0 / CMP R0, #10 / BLE done / MOV R1, #1 / done: HLT',
],
starThresholds: [5, 7, 9],
starterCode: '; 如果 R0 > 10则 R1 = 1\n; 否则 R1 = 0\n\n\nHLT',
showMemory: false,
},
// ===== Level 9: 循环 =====
{
id: 9,
title: '循环',
subtitle: '重复的力量',
icon: '🔄',
description: '用分支指令创建循环',
tutorial: [
{
title: '什么是循环?',
text: '循环让一段代码**反复执行**。在汇编中,循环就是**跳回前面的标签**',
},
{
title: '循环结构',
text: '①初始化 ②做事 ③更新计数器 ④判断+跳回:',
code: 'MOV R4, #0 ; ① 初始化\nloop: ; 循环开始\n ADD R4, R4, #1 ; ②③ 计数+1\n CMP R4, #5 ; ④ 到5了吗\n BLE loop ; 没到就跳回\nHLT',
},
{
title: '注意!',
text: '忘了更新计数器 = **死循环**别担心超过10000步会自动停止。',
},
],
goal: '计算 **1+2+3+...+10** 的和存入 **R0**答案是55',
initialState: {},
testCases: [{ init: {}, expected: { registers: { R0: 55 } } }],
hints: [
'R0 累加结果R4 做计数器1到10',
'循环体ADD R0, R0, R4 / ADD R4, R4, #1 / CMP R4, #10 / BLE loop',
'完整MOV R0, #0 / MOV R4, #1 / loop: ADD R0, R0, R4 / ADD R4, R4, #1 / CMP R4, #10 / BLE loop / HLT',
],
starThresholds: [7, 9, 12],
starterCode: '; 计算 1+2+3+...+10\n; 结果存入 R0\n;\n; 提示:用一个寄存器做计数器\n\n\nHLT',
showMemory: false,
},
// ===== Level 10: 终极挑战 =====
{
id: 10,
title: '终极挑战',
subtitle: '寻找最大值',
icon: '🏆',
description: '综合运用所有技能!',
tutorial: [
{
title: '最后一关!',
text: '你已经学会了寄存器、算术、位运算、内存、分支和循环。现在把**所有技能**结合起来!',
},
{
title: '挑战说明',
text: '内存地址 0-4 存了5个数字。你要找到**最大值**和它的**位置**。需要:循环 + 内存读取 + 比较分支。',
},
{
title: '解题思路',
text: '1. 假设第一个数最大R0=内存[0]R1=位置0\n2. 循环检查剩余的数\n3. 如果发现更大的,更新最大值和位置\n4. 直到检查完全部5个数',
code: '; 伪代码:\n; R0 = max = mem[0]\n; R1 = maxIdx = 0\n; for R4 = 1 to 4:\n; R5 = mem[R4]\n; if R5 > R0: R0=R5, R1=R4',
},
],
goal: '内存[0..4] 有5个数找出**最大值**存入 **R0**,其**位置**存入 **R1**',
initialState: { memory: { 0: 5, 1: 3, 2: 8, 3: 1, 4: 7 } },
testCases: [
{
init: { memory: { 0: 5, 1: 3, 2: 8, 3: 1, 4: 7 } },
expected: { registers: { R0: 8, R1: 2 } },
},
{
init: { memory: { 0: 1, 1: 9, 2: 4, 3: 9, 4: 2 } },
expected: { registers: { R0: 9, R1: 1 } },
},
],
hints: [
'R0=最大值, R1=位置, R4=循环计数器, R5=当前值, R3=基地址',
'用 LDR R5, [R3, R4] 不行的话,可以用 R3 当地址MOV R3, R4 / LDR R5, [R3]',
'循环体:把 R4 当地址读内存 → CMP R5, R0 → BLE skip → 更新 R0,R1 → skip: ADD R4, R4, #1 → CMP R4, #5 → BLT loop',
],
starThresholds: [12, 15, 20],
starterCode: '; 内存[0..4] = [5, 3, 8, 1, 7]\n; 找最大值存入 R0位置存入 R1\n;\n; 提示:用 R4 做循环变量\n; 用 MOV + LDR 读取内存\n\n\nHLT',
showMemory: true,
memoryRange: [0, 15],
},
]