Mon 21 Jul 22:43:21 CEST 2025

This commit is contained in:
sbosse 2025-07-21 23:06:45 +02:00
parent 4a71e9ec3f
commit 8f0c925753

309
js/x11/examples/tetris.js Normal file
View File

@ -0,0 +1,309 @@
var figs = [
//[ 0, 0, 4, 0],
// 0 0
// 0 0
[ 1, 1, 0, 1, 1, 0, 0, 0],
// 0000
[ -2, 0, -1, 0, 0, 0, 1, 0],
// 00
// 00
[ -1, 0, 0, 0, 0, 1, 1, 1],
// 00
// 00
[ 0, 0, 0, 1, -1, 1, 1, 0],
// 0
// 000
[ 0, 0, 1, 0, 0, 1, -1, 0 ],
// 0
// 000
[ 0, 0, -1, 0, -2, 0, 0, 1 ],
[ 0, 0, -1, 0, -2, 0, 0, -1 ]
];
var Buffer = require('buffer').Buffer;
var startpos = [4, 15];
var cupsize = [10, 20];
var cup = new Buffer(cupsize[0]*cupsize[1]);
var moveInterval;
function clearCup()
{
for (var i=0; i <cup.length; ++i)
cup[i] = 0;
}
var anglecoeff = [1, 0, 0, 1,
0, -1, 1, 0,
-1, 0, 0, -1,
0, 1, -1, 0];
// 0: x = 1x + 0y, y = 0x + 1y
// 1: x = 0x - 1y, y = 1x + 0y
// 2: x =-1x + 0y, y = 0x - 1y
// 2: x = 0x + 1y, y = -1x + 0y;
function intersects(num, pos, angle)
{
angle %= 4;
var fig = getTransformedFigure(num, angle, pos);
for (var i=0; i < fig.length; i+= 2)
{
var x = fig[i];
var y = fig[i+1]
if (y < 0)
return true;
if (x < 0)
return true;
if (x >= cupsize[0])
return true;
if (y >= cupsize[1])
return true;
if (cup[x + y*cupsize[0]])
return true;
}
return false;
}
function putfig(num, pos, angle)
{
angle %= 4;
var fig = getTransformedFigure(num, angle, pos);
for (var i=0; i < fig.length; i+= 2)
{
var x = fig[i];
var y = fig[i+1]
var ind = x + y*cupsize[0];
cup[ind] = 1;
}
}
function deleteLines()
{
for (var y=0; y < cupsize[1]; ++y)
{
var count = 0;
for (var x=0; x < cupsize[0]; ++x)
{
var i = x + y*cupsize[0];
if (cup[i] == 1)
count++;
}
if (count == cupsize[0]) // full line;
{
var count = 0;
for (var yy=y; yy < cupsize[1] - 1; ++yy)
{
for (var xx=0; xx < cupsize[0]; ++xx)
{
var ii = xx + yy*cupsize[0];
cup[ii] = cup[ii+cupsize[0]];
}
}
y--;
}
}
}
var x11 = require('../lib');
var Exposure = x11.eventMask.Exposure;
var KeyPress = x11.eventMask.KeyPress;
var sqsize = 15;
var wid, cidBlack, cidWhite;
var angle = 0;
var gamestate = 'stopped';
var timer;
var X;
var pos = [4, 13];
var fignum = 0;
function timerMove()
{
var newpos = [pos[0], pos[1]];
newpos[1]--;
if (intersects(fignum, newpos, angle))
{
putfig(fignum, pos, angle);
deleteLines();
fignum = parseInt((Math.random()*100)%figs.length);
pos[0] = startpos[0];
pos[1] = startpos[1];
angle = 0;
if (intersects(fignum, pos, angle)) {
process.exit(0);
}
draw();
} else {
pos = newpos;
draw();
}
}
function startGame()
{
// start timers set up cirrent + next figure, clear cup
clearCup();
moveInterval = setInterval(timerMove, 200);
}
function getTransformedFigure(num, angle, pos)
{
var tfig = [];
var fig = figs[num];
for (var i=0; i < fig.length; i+=2)
{
var figx = fig[i];
var figy = fig[i+1]
var x = pos[0] + anglecoeff[angle*4]*figx + anglecoeff[angle*4+1]*figy;
var y = pos[1] + anglecoeff[angle*4+2]*figx + anglecoeff[angle*4+3]*figy;
tfig.push(x);
tfig.push(y);
}
return tfig;
}
function draw()
{
var whiterects = [];
var blackrects = [];
for (var x=0; x < cupsize[0]; ++x)
{
for (var y=0; y < cupsize[1]; ++y)
{
var index = x + y*cupsize[0];
var rect = [x*sqsize, (cupsize[1]-1)*sqsize - y*sqsize, sqsize, sqsize];
if (cup[index] != 0)
blackrects = blackrects.concat(rect);
else
whiterects = whiterects.concat(rect);
}
}
var fig = getTransformedFigure(fignum, angle, pos);
for (var i=0; i < fig.length; i+=2)
{
var x = fig[i];
var y = fig[i+1]
blackrects = blackrects.concat([x*sqsize, (cupsize[1]-1)*sqsize - y*sqsize, sqsize, sqsize]);
}
X.PolyFillRectangle(wid, cidWhite, whiterects);
X.PolyFillRectangle(wid, cidBlack, blackrects);
}
function rotate(v)
{
var newangle = angle + v;
if (newangle < 0)
newangle = 3;
if (newangle >= 4)
newangle = 0;
if (intersects(fignum, pos, newangle))
return;
angle = newangle;
draw();
}
function rotateUp()
{
rotate(1);
}
function rotateDown()
{
rotate(-1);
}
function moveX(v)
{
var newpos = [pos[0] + v, pos[1]];
if (intersects(fignum, newpos, angle))
return;
pos = [newpos[0], newpos[1]];
draw();
}
function moveLeft()
{
moveX(-1);
}
function moveRight()
{
moveX(1);
}
function drop()
{
var newpos = [pos[0], pos[1]];
while (!intersects(fignum, newpos, angle))
newpos[1]--;
newpos[1]++;
pos = [newpos[0], newpos[1]];
draw();
}
x11.createClient(function(err, display) {
var ks = x11.keySyms;
var ks2Name = {};
for (var key in ks)
ks2Name[ ks[key].code ] = key;
var kk2Name = {};
var min = display.min_keycode;
var max = display.max_keycode;
X = display.client;
X.GetKeyboardMapping(min, max-min, function(err, list) {
for (var i=0; i < list.length; ++i)
{
var name = kk2Name[i+min] = [];
var sublist = list[i];
for (var j =0; j < sublist.length; ++j)
name.push(ks2Name[sublist[j]]);
}
var root = display.screen[0].root;
var white = display.screen[0].white_pixel;
var black = display.screen[0].black_pixel;
wid = X.AllocID();
X.CreateWindow(wid, root, 0, 0, cupsize[0]*sqsize, cupsize[1]*sqsize, 0, 0, 0, 0, { backgroundPixel: white, eventMask: KeyPress|Exposure });
cidBlack = X.AllocID();
cidWhite = X.AllocID();
X.CreateGC(cidBlack, wid, { foreground: black, background: white } );
X.CreateGC(cidWhite, wid, { foreground: white, background: black } );
X.MapWindow(wid);
clearCup();
startGame();
X.on('event', function(ev) {
switch(ev.type) {
case 6:
break;
case 12: // expose
draw(); break;
case 2:
var key = kk2Name[ev.keycode][0];
console.log(key);
switch(key) {
case 'XK_Up': rotateUp(); break;
case 'XK_Down': rotateDown(); break;
case 'XK_Left': moveLeft(); break;
case 'XK_Right': moveRight(); break;
case 'XK_space': drop(); break;
}
break;
default:
console.log('default event', ev);
}
});
X.on('end', function() {
clearInterval(moveInterval);
});
});
});