MATLABいたずらテクニック

# はじめに
うちの研究室では，研究にMATLABが必須となっています。
そして，一時期他の人のMATLABにいたずらプログラムを仕掛けることが流行っていました。
同じ悲劇を繰り返さないため[^mean]に，その時に得た知識をメモしておきます。
[^mean]: 仕掛け方を知っていれば対処も可能ですが，知らないと解除になかなか苦労します・・・。

# 注意
もし試してみようと思った人は以下に気を付けてください。

- 使い方を誤るとシミュレーションデータが消えるなど，**シャレにならない結果**になります。
- かならず自分の環境でデバッグしてから仕掛けましょう。
- コードを仕掛けるときは，時と場合と相手を選んで利用してください。

そして，コードを利用したことによる損害に，**私は一切責任を取らない**ことを付け加えておきます。

# MATLAB起動時にスクリプトを自動実行する
MATLABでは起動時に検索パス内にある `start.m` という名前のファイルが自動的に実行されます。([公式ドキュメント](https://jp.mathworks.com/help/matlab/ref/startup.html))
そこで，この`startup.m`にいたずらコードを仕込むことで，相手がMATLABを起動した瞬間にいたずらプログラムを実行できます。

この方法なら起動直後なのでシミュレーション結果を壊してしまう恐れもありません。
また，コードを仕込むタイミングと実際に実行されるタイミングがずれるため，仕掛人がばれにくいという利点があります。

# 無限ループを作る
MATLABでも`while true ~~ end`とかで無限ループが作れます。
これと[msgbox関数](https://jp.mathworks.com/help/matlab/ref/msgbox.html)や[uiwait関数](https://jp.mathworks.com/help/matlab/ref/uiwait.html)を組み合わせれば，無限アラートなどは簡単に作れます。

```matlab:infinite_loop.m
% 実行した場合は，Ctrl-Cで終了可能
str = {'  ∧_∧  ババババ', '（ ・ω・)=つ≡つ', '（っ ≡つ=つ', '`/　　)',...
       '(ノΠＵ', '何回閉じても無駄ですよ～ww', 'm9（＾Д＾）プギャー！！'};
while true
h = msgbox(str, 'アラート', 'warn');
uiwait(h);
end
```

# 抜けられない無限ループを作る
先ほど無限ループの作り方を紹介しました。
しかし，単純な無限ループでは["Ctrl-C"](https://jp.mathworks.com/help/matlab/matlab_env/stop-execution.html)で終了可能です。
これを回避し勝手に終了できなくするために，[onCleanup関数](https://jp.mathworks.com/help/matlab/ref/oncleanup.html)を利用します。

onCleanup関数はある変数が消えるとき（スコープを抜けるとき）に，任意の関数を実行させる関数です。
そして，Ctrl-Cで関数を終了させた場合には，その関数のスコープを抜けるためローカル変数は消えてしまいます。
そこで，ローカル変数をトリガーに再帰的に関数呼び出しをさせることで抜けられないループを作れます。

例えば，「（クイズに正解するまでは）何回閉じても無駄なアラート[^safety]」は以下のコードで実現可能です。
(もちろん，Ctrl-Cでも止めることはできません)

```matlab:infinite_loop_advanced.m

looping();          % ループする関数呼び出し

function looping()
persistent c;       % ループ回数
persistent flagFin; % 終了するべきか
MAX_ITERATION = 10; % 最大ループ回数(500以下)
if isempty(c)
    % 永続変数の初期化
    c = 0;
    flagFin = false;
end
% ループを終了すべきかを判断
if c < MAX_ITERATION && ~flagFin
    tempObj = onCleanup(@() looping());     % 消えるとき再帰呼び出し
    joke();                                 % ジョークプログラム呼び出し
    flagFin = isFinished();                 % 終了条件を判定
    c = c + 1;
else
    clear flagFin c     % 永続変数の消去
end
end

function flag = isFinished()
% 終了条件を判定する（今回はクイズ）
in = input('Q. 1年は何か月ですか?: ');
if in == 12
    flag = true;
else
    flag = false;
end
end

function joke()
% ジョークプログラム本体

str = {'  ∧_∧  ババババ', '（ ・ω・)=つ≡つ', '（っ ≡つ=つ', '`/　　)',...
    '(ノΠＵ', '何回閉じても無駄ですよ～ww', 'm9（＾Д＾）プギャー！！'};
h = msgbox(str, 'アラート', 'warn');
uiwait(h);
disp('aa');
end
```
[^safety]: 一応安全のため，`MAX_ITERATION`で回数制限はかけています。また，MATLAB本体が再帰呼び出しの回数に制限をかけているため，厳密には無限にはループしません。

# コードを読めないようにpファイル化する
いろいろスクリプトで工夫したとしても，ソースコードを読むことができれば対処は可能です。
ですが，MATLABにはソースコードを保護する（隠す）方法があります。
それが，[pcode関数](https://jp.mathworks.com/help/matlab/ref/pcode.html)とpファイルです。

例えば，先ほどのlooping関数を別個の関数ファイルに保存し`start.m`から呼び出す形とすると，ソースコードを難読化することができます。

# おわりに
以上が，これまでに当研究室で確認されたいたずらテクニックです。
~~仕掛ける相手に気を付けつつ，楽しんでもらえたらなーと思います。~~

MATLABは研究に使うため真面目なイメージがあるかもしれませんが，いたずらも含めてゲーム作成などいろいろ遊ぶこともできます。
「好きこそものの上手なれ」ですし，楽しいと学ぶ意欲も高まるものだと思います。
ですので個人的には，遊びながらMATLABに慣れていくのもありなのかなーと思います。
「こんなこともできるんだ！」「面白そう！」と思ってもらって，MATLABに興味を持つきっかけになればうれしいです。

なお，もし本記事に問題などありましたらコメントなどですぐにお知らせください。

# 参考文献
1. [闇の魔術に対する防衛術 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/yaminomajutu) (Qiita)
2. [闇の魔術に対する防衛術 Advent Calendar 2018](https://qiita.com/advent-calendar/2018/yami) (Qiita)
2. [アラートループ事件](https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%A9%E3%83%BC%E3%83%88%E3%83%AB%E3%83%BC%E3%83%97%E4%BA%8B%E4%BB%B6) (Wikipedia)
3. [MATLAB でゲームを作る](https://qiita.com/macht/items/05e848f2fa9fab0a538e) (Qiita)
4. [MATLABでマインスイーパ](https://qiita.com/uqiitam/items/c1622d84264032c1d17e) (Qiita)
5. [Simlinkでテトリス](https://jp.mathworks.com/help/stateflow/examples/tetris.html) (MATLAB **公式**ドキュメント)