# MATRIX.	- 鏡に映してご覧ください. (Please look in the mirror) -
#
var background = 0	# 0:Black 1:Red 2:Green 3:Yellow 4:Blue 5:Magenta 6:Cyan 7:White
val part = 1        # MATRIX I, II 
var palette = 0	    # 0:All 1...:Palette No.
var width = 80	    # Screen width
var tail = 30	    # The unit is the display cycle
var wait = 0.05	    # sec.
var alarm = 0	    # min.
var loop = 0
BEGIN {
	var alarmTime = systime() + alarm * 60	# sec.
	initialize()
	while (loop == 0 || --loop > 0) {
	  #        カーソル移動 前スクロール 太字 背景色
	  var s = "\033[1;1H\033[1T\033[1m\033[4" background "m"
	  for (var i = 0; i < width; i++) {
	    var r = rand()
	    var cha = (MATRIX[i] > 0) ? CHAR[int(r * charLen) + 1] : " "
	    var color = "\033[38;5;" colorCode(i) "m"
	    s = s " " color cha " " 

	    if (MATRIX[i] == 0) PALETTE[i] = int(r * paletteNumber)	# Palette number selection
	    if (MATRIX[i] <= 0) {
	      if (++MATRIX[i] >= 0) MATRIX[i] = int(r * colorLen)	# Body length
	    } else {
	      if (--MATRIX[i] <= 0) MATRIX[i] = - int(r * tail)	# Tail length
	    }
	  }
	  print s
	  isAlarm = alarm != 0 && alarmTime < systime()
	  sleep(wait)
	}
	print "\033[0m"	    # reset
}
function initialize() {
	charLen1 = split("0123456789" " [](){}" \
	  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", CHAR1, "")
	charLen2 = split("0123456789" " " \
	  "ｦｧｨｩｪｫｬｭｮｯｰｱｲｳｴｵｶｷｸｹｺｻｼｽｾｿﾀﾁﾂﾃﾄﾅﾆﾇﾈﾉﾊﾋﾌﾍﾎﾏﾐﾑﾒﾓﾔﾕﾖﾗﾘﾙﾚﾛﾜﾝﾞﾟ", CHAR2, "")
	colorLen = split("46 47 48 49 50 51 87 86 85 84 83 82 " \
	  "118 119 120 121 122 123 159 158 157 156 155 154 " \
	  "190 191 192 193 194 195 231 230 229 228 227 226", COLOR01)
	colorLen = split("40 41 42 43 44 45 76 77 78 79 80 81 " \
	  "112 113 114 115 116 117 148 149 150 151 152 153 " \
	  "184 185 186 187 188 189 220 221 222 223 224 225", COLOR02)
	colorLen = split("34 35 36 37 38 39 70 71 72 73 74 75 " \
	  "106 107 108 109 110 111 142 143 144 145 146 147 " \
	  "178 179 180 181 182 183 214 215 216 217 218 219", COLOR03)
	colorLen = split("28 29 30 31 32 33 64 65 66 67 68 69 " \
	  "100 101 102 103 104 105 136 137 138 139 140 141 " \
	  "172 173 174 175 176 177 208 209 210 211 212 213", COLOR04)
	colorLen = split("22 23 24 25 26 27 58 59 60 61 62 63 " \
	  "94 95 96 97 98 99 130 131 132 133 134 135 " \
	  "166 167 168 169 170 171 202 203 204 205 206 207", COLOR05)
	colorLen = split("16 17 18 19 20 21 52 53 54 55 56 57 " \
	  "88 89 90 91 92 93 124 125 126 127 128 129 " \
	  "160 161 162 163 164 165 196 197 198 199 200 201", COLOR06)
	alarmLen = split("124 125 126 127 128 129 " \
	  "160 161 162 163 164 165 196 197 198 199 200 201", ALARM)
	paletteNumber = 6
	if (loop != 0) loop += 1	# 'loop=0' measures
	for (var i = 0; i < width; i++) {
	  MATRIX[i] = - int(rand() * tail)	# Tail length
	}
	charLen = part == 1 ? charLen1 : charLen2
	CHAR = part == 1 ? CHAR1 : CHAR2
	srand()
}
function colorCode(i) {	# get palette color
	var p = palette == 0 ? PALETTE[i] : (palette - 1) % paletteNumber
	var x = MATRIX[i] + 1
	if (isAlarm) return ALARM[x % alarmLen + 1]
	if (p == 0) return COLOR01[x]
	if (p == 1) return COLOR02[x]
	if (p == 2) return COLOR03[x]
	if (p == 3) return COLOR04[x]
	if (p == 4) return COLOR05[x]
	return COLOR06[x]
}
# ESC[0m	指定をリセットし未指定状態に戻す
# ESC[nJ	画面消去、nを省略、もしくは0を指定した場合、カーソルより後ろを消去、1を指定するとカーソルより前を消去、2を指定すると全体を消去
# ESC[n;mH	カーソルを現在の位置に関係なく上端からn、左端からmの場所に移動
# ESC[nS	n行分、コンソールを次にスクロールする。(nには整数が入る、省略すると1)
# ESC[nT 	n行分コンソールを前にスクロール
# ESC[nA	カーソルを上にn移動
# ESC[nJ	画面消去、nを省略、もしくは0を指定した場合、カーソルより後ろを消去、1を指定するとカーソルより前を消去、2を指定すると全体を消去
#
# ESC[38m	文字色指定拡張用、引き続き引数をとる。5;xで、0～255のカラーインデックス指定
#	    	2;r;g;bでRGB指定。ただし、24bitカラーが表示できる端末は少ない
# ESC[30m～ESC[37m	文字色指定
# ESC[40m～ESC[47m	背景色指定
# ESC[90m～ESC[97m	前景色指定、30番代の指定より強い色。標準ではないらしい
# ESC[1m	太字
# ESC[2m	薄く表示する、あまり対応されていないらしいが、gnome-terminalでは文字色が変化している
# ESC[39m	文字色をデフォルトに戻す
# ESC[38;5;nm	    ESC[48;5;nm	    	nを0～255のカラーコードを指定(文字,背景)
# ESC[38;2;r;g;bm	ESC[48;2;r;g;bm	    RGBでのカラーコードを指定

# https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit