--- /dev/null
+#!/bin/bash
+//usr/bin/env stty -echo; sudo staprun -T 30 `stap -p4 "$0"`; stty echo; exit
+
+// 2048.stp - written by NeoCat
+// Inspired by https://github.com/gabrielecirulli/2048/
+// Licensed under MIT license
+
+// Join the numbers and get to the 2048 tile!
+// HOW TO PLAY: Use your arrow keys to move the tiles. When two tiles with the same number touch, they merge into one!
+
+global k, F, F_copy, clear, changed, score
+global animate, moving, moved, spawning
+
+function color(i) {
+ if (i < 0)
+ printf("\033[0m");
+ else
+ printf("\033[48;5;%dm\033[38;5;%dm",
+ i == 0 ? 96 :
+ i == 1 ? 95 :
+ i == 2 ? 252 :
+ i == 4 ? 225 :
+ i == 8 ? 218 :
+ i == 16 ? 136 :
+ i == 32 ? 202 :
+ i == 64 ? 196 :
+ i == 128 ? 214 :
+ i == 256 ? 178 :
+ i == 512 ? 178 : 136,
+ i < 8 ? 0 : 255)
+}
+function cmove(x,y) {
+ printf("\033[%d;%dH", y, x)
+}
+function disp_number(n, j) {
+ if (!n || j != 1)
+ printf(" ")
+ else if (n < 100)
+ printf(" %3d ", n)
+ else
+ printf(" %4d ", n)
+}
+function display() {
+ cmove(0,0)
+ frame = "\033[48;5;95m \033[0m"
+ printf("%s\n", frame)
+ for (y = 0; y < 4; y++) {
+ for (j = 0; j < 3; j++) {
+ for (x = 0; x < 4; x++) {
+ i = x + y*4
+ color(1)
+ printf(" ")
+ color(F[i])
+ disp_number(F[i], j)
+ }
+ color(1)
+ printf(" ")
+ color(-1)
+ printf("\n")
+ }
+ printf("%s\n", frame)
+ }
+}
+
+function spawn() {
+ cnt = 0
+ for (i = 0; i < 16; i++)
+ if (!F[i])
+ cnt++;
+ if (cnt == 0) return -1
+ r = get_cycles() % cnt
+ cnt = 0
+ for (i = 0; i < 16; i++) {
+ if (!F[i])
+ if (cnt++ == r) {
+ F[i] = get_cycles()%20 ? 2 : 4
+ return i
+ }
+ }
+ return -1
+}
+
+function move(from, to) {
+ if (!F[from])
+ return 0
+ if (!F[to]) {
+ moving[from] = F[from]
+ moved = 1
+ F[to] = F[from]
+ F[from] = 0
+ return 1
+ }
+ if (F[from] == F[to] && !changed[from] && !changed[to]) {
+ moving[from] = F[from]
+ moved = 1
+ F[to] += F[from]
+ F[from] = 0
+ changed[to] = 1
+ score += F[to]
+ if (F[to] == 2048) clear = 1
+ return 1
+ }
+ return 0
+}
+function up() {
+ updated = 0
+ for (i = 4; i < 16; i++)
+ updated = move(i, i-4) || updated
+ return updated
+}
+function down() {
+ updated = 0
+ for (i = 11; i >= 0; i--)
+ updated = move(i, i+4) || updated
+ return updated
+}
+function left() {
+ updated = 0
+ for (i = 0; i < 16; i++)
+ if (i % 4)
+ updated = move(i, i-1) || updated
+ return updated
+}
+function right() {
+ updated = 0
+ for (i = 15; i >= 0; i--)
+ if (i % 4 != 3)
+ updated = move(i, i+1) || updated
+ return updated
+}
+
+probe begin {
+ for (i = 0; i < 16; i++)
+ F[i] = 0
+ spawn()
+
+ printf("\033[2J") // clear
+ display()
+}
+
+probe timer.ms(30) {
+ if (!animate) next
+ if (animate > 3) {
+ display()
+ animate = 0
+ next_move()
+ next
+ }
+ if (k == 103) {
+ dx = 0
+ dy = -animate
+ }
+ if (k == 105) {
+ dx = -animate*2-2
+ dy = 0
+ }
+ if (k == 106) {
+ dx = animate*2-2
+ dy = 0
+ }
+ if (k == 108) {
+ dx = 0
+ dy = animate
+ }
+ for (y = 0; y < 4; y++) {
+ for (x = 0; x < 4; x++) {
+ i = x + y*4;
+ if (!moving[i]) continue
+ for (j = 0; j < 3; j++) {
+ cmove(x*8+3+dx, y*4+2+j+dy)
+ if (k == 105 || k == 106) {
+ color(0)
+ printf(" ")
+ }
+ color(moving[i])
+ disp_number(moving[i], j)
+ if (k == 105 || k == 106) {
+ color(0)
+ printf(" ")
+ }
+ color(-1)
+ }
+ if (dy) {
+ cmove(x*8+3+dx, y*4+dy+(dy<0?5:1))
+ color(0)
+ printf(" ")
+ color(-1)
+ }
+ }
+ }
+ animate++
+}
+
+function next_move() {
+ delete moving
+ if (spawning) {
+ spawning = 0
+ display()
+ for (i = 0; i < 16; i++)
+ F_copy[i] = F[i];
+ if (!up() && !down() && !left() && !right())
+ gameover = 1
+ for (i = 0; i < 16; i++)
+ F[i] = F_copy[i];
+ cmove(0,18)
+ printf(" Score: %d\n", score)
+ if (clear) {
+ printf(" !! Y O U W I N !! \n\n")
+ printf(" Score: %d\n", score)
+ }
+ if (gameover) {
+ printf(" !! G A M E O V E R !! \n\n")
+ printf(" Score: %d\n", score)
+ exit()
+ }
+ return 0
+ }
+ if (k == 103)
+ animate = up()
+ else if (k == 105)
+ animate = left()
+ else if (k == 106)
+ animate = right()
+ else if (k == 108)
+ animate = down()
+ if (!animate && moved && !spawning) {
+ animate = 9
+ spawning = spawn()
+ cmove(spawning%4*8+4, spawning/4*4+3)
+ color(F[spawning])
+ printf(" %d ", F[spawning])
+ }
+ return animate
+}
+
+probe kernel.function("kbd_event") {
+ if ($value != 1) next
+ key = $event_code
+ if (!key || key == 4) next
+ //cmove(0,19) printf("key = %d ", key)
+ onkeydown(key)
+}
+
+/* RANDOM MOVE: run with option `stap -G rand=1 2048.stp' or
+ `staprun -T 30 /path/to/*.ko rand=1' */
+global c, rand=0
+probe timer.ms(500) {
+ if (!rand) next
+ dir = get_cycles()/256%4
+ c[0] = 103 c[1] = 105 c[2] = 106 c[3] = 108
+ key = c[dir]
+ cmove(0,19) printf("key = %d ", key)
+ onkeydown(key)
+}
+
+function onkeydown(key) {
+ if (animate) {
+ while (next_move());
+ animate = 0
+ display()
+ }
+ k = key
+ delete changed
+ moved = 0
+ next_move()
+}