From 779e6ca22a55716dc88b562539c952b295d37b42 Mon Sep 17 00:00:00 2001 From: sbosse Date: Mon, 21 Jul 2025 23:02:58 +0200 Subject: [PATCH] Mon 21 Jul 22:43:21 CEST 2025 --- js/x11/core/examples/tetris.js | 309 +++++++++++++++++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 js/x11/core/examples/tetris.js diff --git a/js/x11/core/examples/tetris.js b/js/x11/core/examples/tetris.js new file mode 100644 index 0000000..67a3565 --- /dev/null +++ b/js/x11/core/examples/tetris.js @@ -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 = 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); + }); + + }); + +});