Last active
August 29, 2015 13:58
-
-
Save NeoCat/9947862 to your computer and use it in GitHub Desktop.
2048 -- Join the numbers and get to the 2048 tile using SystemTap!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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() | |
} |
Haha. Would you like us to ship it with upstream systemtap?
Hi! Yes, I appreciate if you would put this in systemtap. Thanks!
(Would you like us to credit it with --author="NeoCat", or a real name?)
--author=NeoCat is OK for me.
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
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