# 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
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.1	    # 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() {
	charLen = split("0123456789" " " \
	  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", CHAR, "")
	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
	}
	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