動機のお話
簡単にいうと、進捗バーを作成したくなりました。
tqdmというパッケージを使えば簡単にできるっぽいのですが、それでは面白みがありません。
せっかくアスキーアートというものがあるのだから、暇な時間はそれを映したいなと思い、いろいろ試すことにしました。
必要な知識
まず、進捗バーを表示する際に知っておくべきことがあります。
それは、表示カーソルの動かし方です。
以下のコードを見てください。
import time
for i in range(10):
time.sleep(1)
print("\r{}".format(i),end="")
これを実行すると、表示される数字が上書きされます。
注目すべきは二つ。
- 1. end=""
- これはprint関数のオプションにある、終端文字の指定で、デフォルトは"\n"(改行文字)です。 そのため、これを""(文字なし)に変更すると、行を下に動かさずに出力できるようになります。
- 2. "\r"
- こちらはエスケープシーケンスというもので特殊なコマンドを意味し、入力カーソルを行の先頭に移すことができます。
これを応用すれば、次のようにかけます。
もし使用したいのであれば、stepの数を変更するだけで、大体なんとかなる。はず。
import time
progress_bar = "\r[{0}{1}] {2}%"
step = 100
for i in range(step):
time.sleep(1)
bar = "#" * (i//10+1)
nobar = " " * ((step-i)//10)
print(progress_bar.format(bar, nobar, round((i+1) / step * 100., 2)), end="")
ここまでが基本のお話。
次に、エスケープシーケンスについて、もう少し詳しく触れます。
エスケープシーケンスで入力箇所を動かす。
エスケープシーケンスとは、ターミナルの制御を可能とする文字で、\033から始まる文字列で表します。
これを利用すれば色の変更などもできるようだが、今回はカーソルを動かすことに焦点を当てます。
使用するシーケンスは以下の通りです。これさえ使いこなせれば、いかようにもターミナル内の文字を操作できるでしょう。
\033[nA ...カーソルをn行だけ上に移動
\033[nB ...カーソルをn行だけ下に移動
\033[nC ...カーソルをn行だけ右に移動
\033[nD ...カーソルをn行だけ左に移動
ただし、Windowsではエスケープシーケンスはデフォルトでは使用できないので、設定を変える必要があります。下に参考になりそうなリンクを掲載しておきました。
また、Jupyterなどの環境はターミナルとは異なるので、上にあげたようなエスケープシーケンスは使用できないようです。
ということで、これらを用いて、動くAAを作ってみましょう。
完成品はこちら
ダンスを披露するAAを進捗バーの下に表示
コードは以下の通り
import time
progress_bar = "\r[{0}{1}] {2}%"
size = 1000
#顔文字がずれているのは自分で修正してください。
dance1 = """\
♪ ∧,_∧ ♪
( ´・ω・) ))
(( ( つ ヽ、 ♪
〉 とノ )))
(__ノ^(_)
"""
dance2 = """\
∧_,∧ ♪
(( (・ω・` )
♪ / ⊂ ) )) ♪
(((ヽつ〈
(_)^ヽ__)
"""
dance3 = """\
∧,_∧ ♪
(( ( )
♪ / ) )) ♪
(( ( ( 〈
(_)^ヽ__)
"""
dance4 = """\
♪ ∧,_∧
( ) ))
(( ( ヽ、 ♪
〉 ノ ) ))
(__ノ^(_)
"""
dance5 = """\
∧_∧ ♪
(´・ω・`) ♪
( つ つ
(( (⌒ __) ))
し' っ
"""
dance6 = """\
♪ ∧_∧
∩´・ω・`)
ヽ ⊂ノ
(( ( ⌒) ))
c し'
"""
dance7 = """\
♪
∧_∧ ♪
. ((o(・ω・` )(o))
/ /
し―-J
"""
dance8 = """\
♪
∧_∧
((o(´・ω・)o))
ヽ ヽ ♪
し―-J
"""
dance_list = [dance1,dance2,dance3,dance4,dance5,dance6,dance7,dance8]
for i in range(size):
time.sleep(0.05)
progress = int ((i+1)/100)
maxprog = int(size/100)
bar = "=" * progress
nobar = " " * (maxprog - progress)
dancenum = (i//25)%8
if i%25==0:
print(progress_bar.format(bar, nobar, round((i+1) / size * 100., 2)))
print(dance_list[dancenum])
print("\r\33[7A", end = "")
else:
print(progress_bar.format(bar, nobar, round((i+1) / size * 100., 2)), end="")
if i == size-1:
for j in range(6):
print(" "*40)
print("\r\33[5A",end="")
見て察したとは思いますが、上の8個のAAをひたすら繰り返す進捗バーです。
証拠隠滅のため、進捗100%になった時にAAは消えるように調整しています。
証拠隠滅なんてする必要がない!と思った方は、下の4行を削除すればそのままになるはずです。
せっかくなので、もう一つ用意しておきました。
待機中にお茶を勧めてくるAA
ocha = []
ocha.append("""\
_______
∧__∧ /__ o、 |、
(´・ω・) | ・ \ノ
旦 o) | ・ |
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
""")
ocha.append("""\
ジャー ______
∧__∧ /__ o、 |、
(´・ω・) ノ .ii | ・ \ノ
( o 旦 | ・ |
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
""")
ocha.append("""\
あ、きみもお茶のむ?
______
∧__∧ /__ o、 |、
(´・ω・ ) | ・ \ノ
( o旦o | ・ |
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
""")
for i in range(3):
bar = "#" * (i+1)
nobar = " " * (2-i)
print("\r[{0}{1}] {2}/3".format(bar, nobar, i+1))
print(ocha[i])
time.sleep(5)
if i != 2:
print("\r\33[8A",end="")
if i == 2:
time.sleep(2)
print("\r\33[7A",end="")
for i in range(6):
print(" "*40)
print("\r\33[6A",end="")
まとめ
今回、AA進捗バーを作ってみて、エスケープシーケンスの良い勉強になりました。これを応用すれば文字の色なども変えられることも分かったし、以外と学びは多かったです。
これはPython以外でも活用できるようなので、今後仕事でCなどを使う際にも活用していきたいです。
参考サイト
Qiita:Pythonで進捗表示したい!
2chのかわいいAA/顔文字まとめ
Windowsでエスケープシーケンスを有効化する方法