cursesでメダカっぽい動きを表現する

# これは何？
![fish.gif](https://qiita-image-store.s3.amazonaws.com/0/175214/b67ff591-df3d-31f7-29e2-065fecf8edda.gif)

こんなやつです。それとなくメダカっぽい動きをしています。
[Tkinterでメダカっぽい動きを表現する](https://qiita.com/can110/items/91987555ce55d7e747e0)の続き。
`curses`で動かしてみました。

# ソースコード
```Python
import math
import random
import time
import numpy as np

# ベクトル正規化
def norm( a):
    x = np.linalg.norm(a)
    if x == 0.0:
        x = 1
    return  a / x

#
# 魚
#
class Fish(object):

    VISCOSITY = 2.2 # 粘性係数[1/sec]
    RUSH_ACL = 15.0 # 突進加速度[m/sec^2]
    RUSH_TIME= 2    # 突進加速する時間間隔[sec]
    MAX_POS = 1     # 空間の広さ[m]

    fishes = []     # 魚群

    def __init__(self,id=-1,pos_x=0,pos_y=0):
        self.id = id
        self.pt_vel = np.array([0.0,0.0])
        self.pt_pos = np.array([pos_x,pos_y])
        self.rush_time = 0 # 次回突進までの残り時間

    # 更新
    def update(self, delta_t,mode='MODE_RAND'):

        # 一定時間がたったら突進加速
        self.rush_time -= delta_t
        if self.rush_time < 0:
            acl,tim = 1,1 # 先頭魚用の係数

            # 各自ランダムに泳ぐ
            if mode == 'MODE_RAND':
                pt_dir = norm( np.array([random.uniform(-1,1),random.uniform(-1,1)]))
            # 先頭魚を追う
            elif mode == 'MODE_HEAD':
                if self.id == 0: # 先頭魚
                    pt_dir = norm( np.array([random.uniform(-1,1),random.uniform(-1,1)]))
                    acl,tim = 2,0.1 # 10倍の頻度で２倍の加速
                else:            # その他の魚
                    head = Fish.fishes[0]
                    pt_dir = norm( head.pt_pos - self.pt_pos)

            pt_acl = pt_dir * acl * Fish.RUSH_ACL * random.uniform(0.8,1.2)
            self.rush_time = tim * Fish.RUSH_TIME * random.uniform(0.5,1.2)
        else:
            pt_acl = self.pt_vel * -Fish.VISCOSITY

        # 速度、位置の計算
        self.pt_vel += pt_acl * delta_t
        self.pt_pos += self.pt_vel * delta_t

        self.limitWall()

        return (self.pt_pos,self.pt_vel)

    # 壁（境界）処理
    def limitWall(self):
        bLim = False
        if   self.pt_pos[0] >= Fish.MAX_POS:self.pt_pos[0] = Fish.MAX_POS; bLim = True
        elif self.pt_pos[0] < 0:            self.pt_pos[0] = 0;            bLim = True
        elif self.pt_pos[1] >= Fish.MAX_POS:self.pt_pos[1] = Fish.MAX_POS; bLim = True
        elif self.pt_pos[1] < 0:            self.pt_pos[1] = 0;            bLim = True
        if bLim: self.pt_vel *= -1 # 反転


import curses

#
def main(stdscr):

    N_FISH = 15
    DELTA_T = 0.033
    SX,SY = 60,30

    curses.curs_set(0) # カーソルを消す
    stdscr.nodelay(True) # 非同期でキー入力

    # 魚群の生成
    Fish.fishes = []
    for idx in range(N_FISH):
        fish = Fish(idx,random.uniform(0,1),random.uniform(0,1))
        Fish.fishes.append( fish)

    # イベントループ
    mode_time = 0
    while True:

        # スペースキー入力で終了
        try:
            key = stdscr.getkey()
            if key == ' ':
                break
        except curses.error:
            pass

        stdscr.clear()

        # 魚が泳ぐ
        for idx,fish in enumerate(Fish.fishes):
            pt_pos,pt_vel = fish.update(DELTA_T)
            pt_vel = norm(pt_vel)

            try:
                pos_body = [ int(pt_pos[0]*SX), int(pt_pos[1]*SY)]
                pos_tail = [ pos_body[0]-int(round(pt_vel[0])), pos_body[1]-int(round(pt_vel[1]))]

                stdscr.addstr(pos_tail[1], pos_tail[0], 'o') # しっぽ
                stdscr.addstr(pos_body[1], pos_body[0], 'O') # 本体

            except curses.error:
                pass

        stdscr.refresh()
        time.sleep(DELTA_T)

if __name__ == '__main__':
    curses.wrapper(main)
```

# 感想
全然メダカに見えなくて残念。