Skip to content

Instantly share code, notes, and snippets.

@NeoCat
Last active August 29, 2015 13:58
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NeoCat/9947862 to your computer and use it in GitHub Desktop.
Save NeoCat/9947862 to your computer and use it in GitHub Desktop.
2048 -- Join the numbers and get to the 2048 tile using SystemTap!
#!/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 or GPLv2
// 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()
delete changed
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 `./2048.stp rand=1', or
`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()
}
@NeoCat
Copy link
Author

NeoCat commented Apr 3, 2014

How to play

example in Fedora 20.

install some packages

% sudo yum update
% sudo yum install systemtap
% sudo debuginfo-install kernel
% sudo reboot # only if kernel is updated ...

Let's play!

% ./2048.stp
OR
% sudo stap 2048.stp

@fche
Copy link

fche commented Apr 3, 2014

Haha. Would you like us to ship it with upstream systemtap?

@NeoCat
Copy link
Author

NeoCat commented Apr 3, 2014

Hi! Yes, I appreciate if you would put this in systemtap. Thanks!

@fche
Copy link

fche commented Apr 4, 2014

(Would you like us to credit it with --author="NeoCat", or a real name?)

@NeoCat
Copy link
Author

NeoCat commented Apr 4, 2014

--author=NeoCat is OK for me.

@NeoCat
Copy link
Author

NeoCat commented Apr 4, 2014

Found a bug in gameover checking. Now it's fixed :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment