25
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

アセンブラのコード同士が戦い、競い合う。二つのプログラムが同じメモリ領域を奪い合うゲーム。

Last updated at Posted at 2024-10-23

前回のあらすじ。

ショートストーリー:「メモリの戦場」

主人公
佐藤涼(さとう りょう)は、東京で働くプログラマ。彼は日々の喧騒から逃れるように、深夜の静けさの中でコードに没頭するのが好きだった。ある夜、彼はデスクに座り、ノートパソコンの前でコーヒーをすすりながら、ふと不思議な考えに取り憑かれた。

「プログラムが意志を持ったらどうなるだろう?」
佐藤は長年、抽象的なアイデアを駆使してシステムを作り上げてきた。しかし、コード同士が戦い、競い合うようなプログラムを書いたことはなかった。そこで、彼は試しに小さなゲームを作ってみることにした。それは、二つのプログラムが同じメモリ領域を奪い合うシミュレーション。

彼はまず「ブループログラム」と「レッドプログラム」を書き始めた。ブループログラムはメモリを支配しようとし、次々と「2」を書き込んでいく。対してレッドプログラムは「1」をメモリに書き込み、ブルーに対抗しようとする。両者は互いに、メモリの領域を巡って絶え間なく戦う。

スクリーンショット 2024-10-24 042712.png

実行結果。(ちょっとだけ知的なゲームです。)

プログラムブルー は、メモリに 2 を順番に書き込み、さらに自身のコードをメモリ内にコピーしていく動作を行います。
プログラムレッド は、メモリに 1 を順番に書き込み続けます。

プログラムバトルゲームの実行マシンの仕様を以下に示します。このマシンは、2つの異なるプログラム(プログラムブルーとプログラムレッド)が共有メモリに対してアクセスし、指定された操作を実行する仕組みです。(とりあえずの完成。)

実行マシンの仕様
  1. メモリ
    メモリサイズ: 100バイト
    メモリは100個のスロットを持ち、各スロットは整数値(0~255)のデータを格納できる。
    初期値はすべて 0。
    プログラムブルーとプログラムレッドは、このメモリに対して読み書きを行う。

  2. レジスタ
    各プログラムには1つのレジスタが与えられます。レジスタは1つの整数値を保持し、メモリへの読み込みや書き込みに使用されます。
    レジスタの役割:
    メモリからの読み込み (LOAD)、メモリへの書き込み (STORE) に利用。
    INC によってポインタを操作する際、レジスタはメモリ位置の計算に使われます。

  3. 命令セット
    以下は実行マシンでサポートされている命令の一覧です。

命令 説明

LOAD <値> 指定した値(メモリ内のアドレスまたは即値)をレジスタにロードします。

STORE レジスタの値をメモリの現在のアドレスに書き込みます。

INC メモリアドレスポインタを1増やします。アドレスが100に達したら、次は0に戻ります。

JUMP <ラベル> 指定したラベルにジャンプして、そこからプログラムを再開します。

COPY_START コピー開始アドレスを設定します。プログラムの増殖などに使用されます。

COPY メモリ内の指定範囲をコピーします。プログラム自体の増殖やデータの複製を行う際に使われます。

  1. プログラムの動作
    各プログラムは独自の命令セットを使用して、メモリ上で動作します。

プログラムブルー: メモリに 2 を書き込み、次に自分のコードをメモリ上にコピーして増殖します。
プログラムレッド: メモリに 1 を書き込み続けます。

  1. プログラムの実行
    各プログラムは1命令ずつ実行され、交互に処理されます。
    時間ステップ: プログラムブルーとプログラムレッドは、1秒ごとに1命令を実行します。時間が経過するにつれて、メモリの状態が変化します。
    終了条件: バトルは停止ボタンが押されるまで実行され続けます。

  2. メモリアクセスと競合
    両プログラムは同じメモリ空間を共有します。これにより、メモリ上のデータが競合する可能性があります。
    例: プログラムブルーが 2 を書き込んだ直後に、プログラムレッドが 1 に上書きする可能性がある。

  3. インターフェースの構成
    プログラムエディタ:
    プログラムブルーおよびプログラムレッドのコードは、テキストエリアに編集可能な形で表示され、ユーザーがプログラムを修正できます。

メモリの表示:
メモリの状態は画面中央に表示され、リアルタイムで変化します。

実行制御:
バトル開始ボタンで両プログラムを実行し、停止ボタンで実行を中止できます。
この仕様に基づいて、プログラムの挙動や競合状態をシミュレートすることができます。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>プログラムバトルゲーム</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f4f4f4;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
        }
        #game {
            width: 1000px;
            padding: 20px;
            background-color: white;
            border: 1px solid #ccc;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            display: flex;
            flex-direction: column;
            align-items: center;
        }
        .program {
            width: 30%;
            padding: 10px;
            margin: 10px;
            border: 1px solid #ccc;
            background-color: #f9f9f9;
        }
        #blueProgram {
            background-color: #e0f7fa;
        }
        #redProgram {
            background-color: #ffebee;
        }
        #memory {
            margin-top: 20px;
            font-family: monospace;
            background-color: #eee;
            padding: 10px;
            white-space: pre-wrap;
            overflow-x: auto;
            max-height: 200px;
            width: 100%;
        }
        #programs {
            display: flex;
            justify-content: space-between;
            width: 100%;
        }
        button {
            margin-top: 20px;
        }
        textarea {
            width: 100%;
            height: 200px;
        }
    </style>
</head>
<body>

<div id="game">
    <h1>プログラムバトルゲーム</h1>
    <div id="programs">
        <div class="program" id="blueProgram">
            <h2>プログラムブルー</h2>
            <textarea id="blueCode">START:
LOAD 2
STORE
INC
COPY_START
INC
JUMP COPY

COPY:
LOAD MEM[COPY_START]
STORE
INC
COPY_START = COPY_START + 1
JUMP COPY</textarea>
        </div>
        <div id="memory"></div>
        <div class="program" id="redProgram">
            <h2>プログラムレッド</h2>
            <textarea id="redCode">START:
LOAD 1
STORE
INC
JUMP START</textarea>
        </div>
    </div>
    <button onclick="runBattle()">バトル開始</button>
    <button onclick="stopBattle()">バトル停止</button>
</div>

<script>
    let memory = Array(100).fill(0);  // メモリ(100番地)

    let programBlue = {
        name: "プログラムブルー",
        register: 0,
        pointer: 0,   // 現在の命令ポインタ
        code: document.getElementById("blueCode").value.split("\n"),
        copyStart: 0
    };

    let programRed = {
        name: "プログラムレッド",
        register: 1,  // レジスタの初期値
        pointer: 0,    // 現在の命令ポインタ
        code: document.getElementById("redCode").value.split("\n")
    };

    function updateMemoryDisplay() {
        // メモリ内容を表示
        let memDisplay = '';
        for (let i = 0; i < memory.length; i++) {
            memDisplay += `メモリ ${i + 1}: ${memory[i]} `;
            if ((i + 1) % 10 === 0) memDisplay += '\n';
        }
        document.getElementById("memory").textContent = memDisplay;
    }

    function updateProgramDisplay() {
        // 各プログラムの状態を表示
        document.getElementById("blueCode").value = programBlue.code.join("\n");
        document.getElementById("redCode").value = programRed.code.join("\n");
    }

    function executeInstruction(program) {
        let instruction = program.code[program.pointer];  // 現在の命令を取得
        let parts = instruction.split(" ");  // 命令を分割

        switch (parts[0]) {
            case "LOAD":
                program.register = parseInt(parts[1]);  // レジスタに値をロード
                break;
            case "STORE":
                memory[program.pointer] = program.register;  // メモリにレジスタの値を保存
                break;
            case "INC":
                program.pointer = (program.pointer + 1) % memory.length;  // ポインタをインクリメント
                break;
            case "COPY_START":
                program.copyStart = program.pointer;  // コピー開始位置をセット
                break;
            case "JUMP":
                let targetLabel = parts[1];
                program.pointer = findLabel(program, targetLabel);  // ジャンプ先のラベルを探して移動
                break;
        }
        program.pointer = (program.pointer + 1) % program.code.length;  // 次の命令へ
    }

    function findLabel(program, label) {
        for (let i = 0; i < program.code.length; i++) {
            if (program.code[i].startsWith(label)) {
                return i;
            }
        }
        return 0;  // ラベルが見つからない場合は最初に戻る
    }

    let battleInterval;

    function runBattle() {
        battleInterval = setInterval(() => {
            // プログラムブルーを実行
            executeInstruction(programBlue);
            // プログラムレッドを実行
            executeInstruction(programRed);

            // メモリ表示を更新
            updateMemoryDisplay();
        }, 1000);
    }

    function stopBattle() {
        clearInterval(battleInterval);
    }

    updateMemoryDisplay();
</script>

</body>
</html>

25
19
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?