2つのアセンブラプログラムが戦うゲームを魔改造。

# 概要
2つのアセンブラプログラムが戦うゲームを見つけたので魔改造してみた。

# 参考にしたページ

https://qiita.com/tetsutakamurata76/items/6f0943fe8b6ff4673440

# cpuの仕様

レジスタ　３個8bit
Acc		アキュムレータ
adr		アドレスレジスタ
pc		プログラムカウンタ
命令セット　１４個１２ビット
オペコード４ビット、値８ビット
メモリー　256個１２ビット

|ニーモニック	|		意味|	コード
|:--|:--|:--|
|hlt		|pc <- pc				|000
|ld 12     	|acc <- 12			|10c
|ldr 		|acc <- adr			|200
|str 		|adr <- acc			|300
|ldm		|acc <- [adr]		|400
|stm		|[adr] <- acc		|500
|add 12		|acc <- acc + 12		|60c
|sub 12		|acc <- acc - 12		|70c
|gt 12		|(acc < 12) ? acc <- 1 : acc <- 0	|80c
|if	12		|(acc = 1) ? pc <- 12 : pc <- pc + 1		|90c
|jmp 12		|pc <- 12		|a0c
|api    |alert    |b00
    

# ゲームの仕様
メモリー上に、プログラムを配置して、起動し、相手のプログラムを破壊した方が、勝ち。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/61d1503e-11b9-4a8c-adf6-1d6ac00082ae.png)


# ブルーのプログラム

９０番地に配置、０番地から５０番地を２で埋める攻撃。

```
ld 2
stm
ldr
add 1
str
gt 50
if 90
api
hlt
```

# レッドのプログラム

６０番地に配置、８０番地から１００番地を３で埋める攻撃。
```
ld 80
str
ld 3
stm
ldr
add 1
str
gt 100
if 62
api
hlt
```

# サンプルコード

```

const hex3 = (opcode) => ('000' + opcode.toString(16)).slice(-3);

let memory = Array(256).fill(0); 
let programBlue = {
    name: "プログラムブルー",
    adr: 0,
    acc: 0,
    pc: 90,   
    code: [
        "ld 2",   
        "stm",    
        "ldr",  
        "add 1",     
        "str",  
        "gt 50",    
        "if 90",     
        "api",   
        "hlt"       
    ]
};
let programRed = {
    name: "プログラムレッド",
    adr: 0,
    acc: 0,
    pc: 60,    
    code: [
        "ld 80",   
        "str",    
        "ld 3",   
        "stm",    
        "ldr",  
        "add 1",     
        "str",  
        "gt 100",    
        "if 62",     
        "api",   
        "hlt"       
    ]
};
function updateMemoryDisplay() {
    var h = '<table>';
	for (i = 0; i < 256; i = i + 16)
	{
       	h += '<tr>';
        h += '<td>' + hex3(memory[i + 0]) + '<\/td>';
        h += '<td>' + hex3(memory[i + 1]) + '<\/td>';
        h += '<td>' + hex3(memory[i + 2]) + '<\/td>';
        h += '<td>' + hex3(memory[i + 3]) + '<\/td>';
        h += '<td>' + hex3(memory[i + 4]) + '<\/td>';
        h += '<td>' + hex3(memory[i + 5]) + '<\/td>';
        h += '<td>' + hex3(memory[i + 6]) + '<\/td>';
        h += '<td>' + hex3(memory[i + 7]) + '<\/td>';
        h += '<td>' + hex3(memory[i + 8]) + '<\/td>';
        h += '<td>' + hex3(memory[i + 9]) + '<\/td>';
        h += '<td>' + hex3(memory[i + 10]) + '<\/td>';
        h += '<td>' + hex3(memory[i + 11]) + '<\/td>';
        h += '<td>' + hex3(memory[i + 12]) + '<\/td>';
        h += '<td>' + hex3(memory[i + 13]) + '<\/td>';
        h += '<td>' + hex3(memory[i + 14]) + '<\/td>';
        h += '<td>' + hex3(memory[i + 15]) + '<\/td>';
        h += '<\/tr>';
	}
	h += '<\/table>';
	document.getElementById('memory').innerHTML = h;    					
}
function updateProgramDisplay() {
    document.getElementById("blueStatus").innerHTML = `
        現在位置: ${programBlue.pc}, acc: ${programBlue.acc}, adr:  ${programBlue.adr}
        `;
    document.getElementById("redStatus").innerHTML = `
        現在位置: ${programRed.pc}, acc: ${programRed.acc}, adr: ${programRed.adr}
        `;
    document.getElementById("blueInstructions").innerText = programBlue.code.join("\n");
    document.getElementById("redInstructions").innerText = programRed.code.join("\n");
}
function executeInstruction(program) {
    let instruction = memory[program.pc];  
    let opcode = instruction & 0xf00; 
    let opland = instruction & 0xff; 
    switch (opcode) 
    {
    case 0:     //"hlt":
        program.pc--;
    break;
    case 0x100: //"ld":
        program.acc = opland;  
    break;
    case 0x200: //"ldr":
        program.acc = program.adr;  
    break;
    case 0x300: //"str":
        program.adr = program.acc;  
    break;
    case 0x400: //"ldm":
        program.acc = memory[program.adr];  
    break;
    case 0x500: //"stm":
        memory[program.adr] = program.acc;  
    break;
    case 0x600: //"add":
        program.acc += opland;  
    break;
    case 0x700: //"sub":
        program.acc -= opland;  
    break;
    case 0x800: //"gt":
        if (program.acc < opland) 
        {
            program.acc = 1;
        }
        else
        {
            program.acc = 0;
        }
    break;
    case 0x900: //"if":
        if (program.acc == 1) 
        {
            program.pc = opland - 1;  
        }
    break;
    case 0xA00: //"jmp":
        program.pc = opland - 1;  
    break;
    case 0xB00: //"api":
        alert(`${program.name} がゴールしました!`);
    break;
    }
    program.pc++;  
}
function setmem(program) {
    let opcode;
    let adr = program.pc;
    for (i = 0; i < program.code.length; i++)
    {
        let instruction = program.code[i];  
        let parts = instruction.split(" ");  
        let opland = parseInt(parts[1]) & 0xff;
        switch (parts[0]) 
        {
        case "hlt":
            opcode = 0;
            memory[adr] = opcode;
        break;
        case "ld":
            opcode = 1 << 8 | opland;
            memory[adr] = opcode;
        break;
        case "ldr":
            opcode = 2 << 8; 
            memory[adr] = opcode;
        break;
        case "str":
            opcode = 3 << 8;
            memory[adr] = opcode;
        break;
        case "ldm":
            opcode = 4 << 8;
            memory[adr] = opcode;
        break;
        case "stm":
            opcode = 5 << 8;
            memory[adr] = opcode;
        break;
        case "add":
            opcode = 6 << 8 | opland;
            memory[adr] = opcode;
        break;
        case "sub":
            opcode = 7 << 8 | opland;
            memory[adr] = opcode;
        break;
        case "gt":
            opcode = 8 << 8 | opland;
            memory[adr] = opcode;
        break;
        case "if":
            opcode = 9 << 8 | opland;
            memory[adr] = opcode;
        break;
        case "jmp":
            opcode = 10 << 8 | opland;
            memory[adr] = opcode;
        break;
        case "api":
            opcode = 11 << 8;
            memory[adr] = opcode;
        break;
        default:
            alert(instruction);
        }
        adr++;
    }
}
let battleInterval;
function runBattle() {
    battleInterval = setInterval(() => {
        executeInstruction(programBlue);
        executeInstruction(programRed);
        updateMemoryDisplay();
        updateProgramDisplay();
    }, 300);
}
function stopBattle() {
    clearInterval(battleInterval);  
    alert(`終了しました!`);
}
setmem(programBlue);
setmem(programRed);
updateMemoryDisplay();
updateProgramDisplay();




```

# 成果物

https://embed.plnkr.co/plunk/KsG5RqzLKOLUDu8V


# 対戦結果
ブルーのプログラムは、レッドに消された。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/c02fb6fb-fb6c-14f7-1604-fbf5599870be.png)


以上。