iTermで動く年賀状（寅）を作ってみた

こんにちは、@nininiです。
本記事は[ハンズラボAdvent Calendar 2021](https://qiita.com/advent-calendar/2021/handslab) の21日目の記事です。

# はじめに

クリスマスもまだですが、そろそろ年賀状を作るリミットですね。
自分はまだハガキも買っていませんが...

bashのワンライナーで干支の絵でも書いてほしいと社内でリクエストがありました。
macのターミナルで年賀状っぽいものを作ってみました。
とりあえず動くものだけでも見ていっていただけると幸いです。
↓来年の干支、トラです
![tora.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2334762/09441da7-31f6-9db4-b8c9-23ffb5b23389.gif)

# 本記事の目的
トラをフニフニ動かして、新年をお祝いする準備をしたかっただけです。
仕事と関係ないことをしております。

# 動かしていった手順
以下、動かしていった手順を書きます。
泥臭かったり、ひどいプログラムが出てくきます。


## 環境
mac:Big Sur version:11.6
ターミナル：iTerm2 Build 3.4.14


## 手順
1. 絵をエクセルで描く
1. 絵の素材をファイルに貼り付ける
1. 変なbashを動かす

### 1. 絵をエクセルで描く
これが一番大変かもしれません。
絵を描いてデジタル化出来るアプリとかもあるみたいですがエクセルで描きました。
２種類書きました（動かしたかったので）
色をつけたいところはセルに文字を書いています。（C10セルは黄色にしたいから`y`と書く、など）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2334762/a73c2d2c-5fef-d153-377e-e1a8cea33e82.png)

### 2. 絵の素材をファイルに貼り付ける
B2セル〜AJ20セルをテキストファイルにコピペ→`tora-1`というファイル名で保存



```text:tora-1

																														r	r
																													r	r	r	r
																											w	w	w	r	r
																											b	b	b
								y	y																	b	b	b	b	b
			y	y	y	y	y			y															b	b	b	b	b	b	b
		y							y		y
	y							y	y			y		y	y	y	y	y	y	y											y
		y	y	y	y	y	y						w			w				w	y	y							y	y		y
		y		y		y	y						w			w				w			y				y	y				y
			y		y		y						w			w				w			y	y	y	y					y
		y	y	y	y	y																						y	y	y
		y						y	y	y																	y	y
			y	y	y	y	y				y			y				y	y	y			y	y			y
											y		y		y		y				y		y		y		y
											y		y		y		y				y		y		y		y
												y	y		y	y	y				y	y			y	y
```

AO2セル〜BW20セルをテキストファイルにコピペ→`tora-2`というファイル名で保存

```text:tora-2

																														r	r
																													r	r	r	r
																											w	w	w	r	r
								y	y																		b	b	b
			y	y	y	y	y			y																b	b	b	b	b
		y									y														b	b	b	b	b	b	b
	y							y	y		y
		y	y	y	y	y	y					y		y	y	y	y	y	y	y
		y		y		y	y						w			w				w	y	y
							y						w			w				w			y				y	y	y
			y		y		y						w			w				w			y	y	y	y				y
		y	y	y	y	y																						y			y	y	y
		y						y	y	y																	y	y	y				y
			y	y	y	y	y				y			y				y	y	y			y	y			y			y	y	y
											y		y		y		y				y		y		y		y
											y		y		y		y				y		y		y		y
												y	y		y	y	y				y	y			y	y
```

### 3. 変なbashを動かす
さっき作った`tora-1``tora-2`と同じ階層に置いて実行します。
可読性の「か」の字も無いプログラムです。

```bash:nengajou.bash
#!/bin/bash

for ((;;)) ;do
  for torafile in $(ls tora-*);do
    eval echo $(cat ${torafile} | sed 's/    /\t/g;s/   /\t/g;s/\t\t/\t_\t/g;s/\t\t/\t_\t/g;s/r/1/g;s/y/3/g;s/b/4/g;s/w/7/g' | expand | awk 'BEGIN{print "$(tput clear)"}{for(i=1;i<=NF;i++){if($i!="_"){print "$(tput cup "NR,(i*2)-1")$(tput setaf "$i")■"}}}')
  done
  sleep 0.1
done

exit 0
```


### 変なbashについて
説明しよう！

#### ３行目
`for ((;;)) ;do`
ずっとフニフニ動かしたかったので無限ループにしています。

#### ４行目
`  for torafile in $(ls tora-*);do`
作ったtoraファイルを順番に読み込みます。

#### 5行目
ここがひどいプログラムです。分解します。

```
    eval echo $(cat ${torafile} | sed 's/    /\t/g;s/   /\t/g;s/\t\t/\t_\t/g;s/\t\t/\t_\t/g;s/r/1/g;s/y/3/g;s/b/4/g;s/w/7/g' | expand | awk 'BEGIN{print "$(tput clear)"}{for(i=1;i<=NF;i++){if($i!="_"){print "$(tput cup "NR,(i*2)-1")$(tput setaf "$i")■"}}}')
```

`tput`というコマンドがあります。これがターミナルを制御するのに便利です。
よしなにエスケープシーケンスを発行してくれます。
エスケープシーケンスで書いた方がかっこいいかもしれませんが、途中でわけがわからなくなったので`tput`に頼りました。

`tput clear`：画面をクリアします。 `clear`コマンドと同じ動きをします。
`tput cup <行> <列>`：カーソルを左上から指定した場所に移動します。
`tput setaf <色番号>`：カーソルの色を変えます。

1. Qiitaのtora-1,tora-2をコピるとタブがスペースになってしまうので、一旦タブ区切りに変換
   * このプログラムを試していただけるありがたい方用処理(エクセルコピペ時は不要)
   * `sed`コマンドで実施している`s/    /\t/g;s/   /\t/g;`
2. タブ区切りなっているので、スペース区切りに変換する
   * `sed`コマンドで実施している`s/\t\t/\t_\t/g;s/\t\t/\t_\t/g`
   * `expand`コマンド
3. 色を指定するコードを文字から数字に変更
   * `sed`コマンドで実施している`s/r/1/g;s/y/3/g;s/b/4/g;s/w/7/g`
4. 文字を出す場所、出す色、出す文字を指定
   * awkコマンドで色々やっています
    * 色が指定されている座標を出力しています。(`$(tput cup 15 9)`など）
        * `NR`で行番号、`(i*2)-1`で列番号。出力する文字が`■`でマルチバイトなので、それに合わせています
    * 指定された色を出力するための文字列を出しています。(`$(tput setaf 3)`など)
    *  evalを実行する前はこんな文字列が続いていきます。１つのプロットごとに`位置指定`→`色指定`→`■を出力`をする形になります。
    *  最初の`$(tput clear)`ですでに描画されている絵を一度消しています。


```
$(tput clear) $(tput cup 2 59)$(tput setaf 1)■ $(tput cup 2 61)$(tput setaf 1)■ $(tput cup 3 57)$(tput setaf 1)■ $(tput cup 3 59)$(tput setaf 1)■(続く...）
```


そして、`eval echo`でこれらの文字列を実行して絵を描いています。


#### 7行目
無限ループさせているのでsleepも入れています。
暴走は怖いですからね。


## まとめ
* ここまで読んでいただいた方、ありがとうございます。
* トラの動きは、個人的には気に入ってます。
* 久しぶりに無意味なプログラムが書けて楽しかったです。息抜き大事。
* 実際に業務で書くプログラムは、可読性重視で行きたいと思います。