2歳むすめちゃんお気に入りのslコマンド！これのアンパンマンバージョン、その名も"anp"コマンドを作ればむすめちゃん大喜びなのでは...？！！

はい、タイトルの通りですね！
というわけでslコマンドのアンパンマンバージョン、その名もanpコマンドを作っていきます~~！

## SLコマンドって？

言わずと知れたlinuxジョークコマンド。

slと入力すると汽車ぽっぽ（国鉄D51形蒸気機関車）が走ります。エンジニアの子供が叩かされがちなコマンドです。
https://ja.wikipedia.org/wiki/Sl_(UNIX)

![sl.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241199/d3b73597-047a-f193-5a21-42a308ddcec7.gif)

Macでしたらbrewで入りますので、ぜひ`brew install sl`して試してみてください！

ちなみにこんなオプションが指定できたりします。
|オプション | 内容 |
| ---- | ---- | 
|a |  乗客？がHELP| 
| l |  汽車が細くなる| 
| F |  汽車が飛んでいく| 
| c |  C51系機関車になる| 

### どんな感じの実装か

コードを読んでみる。

https://github.com/mtoyoda/sl

こんな感じっぽいです。
1. 画面をクリアする
2. 出力する空白を増やして移動してるように見せる
3. アニメーションは行ごとに文字列化
4. アニメーションつけるなら複数のアスキーアートを組み合わせて交互に表示
5. 表示切り替え時にsleepさせてアニメーション感を出す
6. キーボード入力無視の設定

とりあえずやってみましょう。

## 手始めに文字をちょっと移動させる

C言語はもう忘れてしまったので、うろ覚えのC++で書いてみましょう。

```c++
#include <iostream>
#include <thread>
#include <chrono>
#include <sys/ioctl.h>
#include <unistd.h>
using namespace std;

int getScreenWidth() {
    struct winsize w;
    ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);

    return w.ws_col;
}

int main() {
    const int width = getScreenWidth();
    const string anpan = "anpanman"; 

    for (int i = width; i >= 0; i--) {
        system("clear");
        for (int j = 0; j < i; j++) {
            cout << " ";
        }
        if (i < anpan.length()) {
            cout << anpan.substr(anpan.length() - i, i) << endl;
        } else if (i > width - anpan.length()) {
            cout << anpan.substr(0, width - i) << endl;
        } else {
            cout << anpan << endl;
        }
        this_thread::sleep_for(chrono::milliseconds(100));
    }
    return 0;
}
```

これでこんな感じになる。

![firstanp.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241199/4b35298c-9b83-3ad3-a90a-82448aac3e84.gif)


ふむふむ、なんかいけそうな気がしてきた！

## アンパンマンのアスキーアートを動かそう！

空を飛んでるアンパンマンが右から左に飛んでいくような感じにしたいな〜と思っていい感じの画像やAAがないか探してたら、[AAHUB](https://aahub.org/mlt/05750d3a4b4d8dfe2b574173bb7fb4cb)でドンピシャなやつを見つけました！

早速このAAを文字列化しようとしたのですが...
![](https://storage.googleapis.com/zenn-user-upload/bcc99602ec58-20231221.png)

あわわ...なんか大変なことに...これめんどくさいやつ...。
![](https://storage.googleapis.com/zenn-user-upload/f0a3c6d2a98e-20231221.png)

ということで難易度を急激に下げてこちらのAAを右から左に移動させてみましょう。
![](https://storage.googleapis.com/zenn-user-upload/5baa91d86b84-20231221.png)

こんな感じになりました。
多少のアニメーションとしてちょっと上下させたり表示を変えたりしてみました...

![anp.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241199/911c05ab-d07c-2e25-763f-594820ce4497.gif)

https://github.com/pistachiyoda/anp

## ビルドプロセスの整理

むすめちゃんが叩きやすいように、バイナリを./anpと実行するのではなく、バイナリをパスの通ったディレクトリに置いてanpコマンドとして実行する感じにしようと思います。

Linucサイトによると自作プログラムは/usr/local/binに置くのがいいらしいので、バイナリを/usr/local/binにコピーするMakefileを書いておきましょう。

> 「/usr/local/bin」には、「シングルユーザモードで利用しない」かつ「RPMやdebなどのパッケージ管理システムによってシステムに管理されないコマンドやプログラム」が置かれることになります。自作のスクリプトなどはこのディレクトリに置くことが一般的です。

https://linuc.org/study/knowledge/544/

### Makefile

```makefile
# Makefile
CC=g++
CFLAGS=-Wall
TARGET=amp
DESTDIR=/usr/local/bin

all: $(TARGET)

$(TARGET): $(TARGET).cpp
	$(CC) $(CFLAGS) -o $(TARGET) $(TARGET).cpp

install:
	cp $(TARGET) $(DESTDIR)/$(TARGET)

clean:
	rm -f $(TARGET)
```

## むすめちゃん、大喜びなるか...？！！

![original_477267ed-c731-4e7b-9f64-3c87dec6f896_PXL_20231223_071123810.MP~2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241199/48cfcf67-108e-07ce-179e-229e80fa21fe.jpeg)

アンパンマンとか何も言わずにコマンドを初披露したところ、「アンパンマンだー！」と認識してくれました...！！

やったね！

## 感想など

時間不足（言い訳）でアンパンマンのクオリティがイマイチになってしまいましたが、むすめちゃんがそこそこ喜んでくれてよかったです。
アスキーアート難しい、アニメーションも難しい...

ゆるい内容でしたが最後まで読んでくださりありがとうございました！