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.
This commit is contained in:
376
frontend/src/lib/levels.js
Normal file
376
frontend/src/lib/levels.js
Normal file
@@ -0,0 +1,376 @@
|
||||
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 × 2³)',
|
||||
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],
|
||||
},
|
||||
]
|
||||
Reference in New Issue
Block a user