tetris.golf.html
2025-02-27 23:25
A Tetris game for t0.vc
Hover mouse over canvas to allow keyboard input.
Use arrow keys to play.
Someone else can add touch controls (see window.Tetris).
<canvas id="tetris" style="border: solid 1px #000; background: #eee" width="200" height="400"></canvas>
<script>
(($Window, $Document, _m_addEventListener, _m_preventDefault, _m_forEach, _prop_$canvas, _prop_score, _prop_board, _prop_piece, _const_COLS, _const_ROWS, _const_SHAPES, _const_COLORS, _const_ROW_SCORE) => {
class Tetris {
static I = {};
constructor(selector) {
if (Tetris.I[selector])
return Tetris.I[selector];
Tetris.I[selector] = this;
this[_prop_$canvas] = $Document.querySelector(selector);
this.ctx = this[_prop_$canvas].getContext("2d");
this.ms = 350;
this.reset();
this._L();
}
_L() {
this.drop(0);
this.draw();
setTimeout(() => this._L(), this.ms);
}
reset() {
this[_prop_score] = 0
this[_prop_board] = Array.from({ length: _const_ROWS }, () => Array(_const_COLS).fill(0));
this._N();
};
_N(index) {
index = Math.floor(Math.random() * _const_SHAPES.length);
this[_prop_piece] = { m: _const_SHAPES[index], c: index + 1, x: 4, y: 0 };
};
draw() {
this.ctx.clearRect(0, 0, this[_prop_$canvas].width, this[_prop_$canvas].height);
this[_prop_board][_m_forEach]((row, y) => row[_m_forEach]((color, x) => {
if (color) this._B(x, y, color);
}));
const { x, y, m, c } = this[_prop_piece];
m[_m_forEach]((row, j) => row[_m_forEach]((value, i) => {
if (value) this._B(x + i, y + j, c);
}));
this.ctx.fillStyle = _const_COLORS[0];
this.ctx.fillText(`${_prop_score}: ${this[_prop_score]}`, 1, 10);
}
_B(x, y, color, size) {
size = _const_ROWS;
this.ctx.fillStyle = _const_COLORS[color];
this.ctx.strokeStyle = _const_COLORS[0];
this.ctx.fillRect(x * size, y * size, size, size);
this.ctx.strokeRect(x * size, y * size, size, size);
}
_C() {
const { x, y, m } = this[_prop_piece];
return m.some((row, dy) => row.some((value, dx) =>
value && (this[_prop_board][y + dy]?.[x + dx] || y + dy >= _const_ROWS)
));
}
drop(mult, count) {
this[_prop_piece].y++;
this[_prop_score] += 1 + 2 * (mult || 0);
if (this._C()) {
this[_prop_piece].y--;
const { x, y, c, m } = this[_prop_piece];
m[_m_forEach]((row, j) => row[_m_forEach]((value, i) => {
if (value) this[_prop_board][y + j][x + i] = c;
}));
count = 0;
this[_prop_board] = this[_prop_board].filter((row, _, __, full) => (full = row.every(cell => cell), count += full, !full));
this[_prop_score] += _const_ROW_SCORE[count];
while (this[_prop_board].length < _const_ROWS) this[_prop_board].unshift(Array(_const_COLS).fill(0));
this._N();
if (this._C()) this.reset();
}
}
move(dir) {
this[_prop_piece].x += dir;
if (this[_prop_piece].x < 0 || this[_prop_piece].x + this[_prop_piece].m[0].length > _const_COLS || this._C()) {
this[_prop_piece].x -= dir;
}
}
rot8(temp, old) {
temp = this[_prop_piece].m[0].map((_, i) => this[_prop_piece].m.map(row => row[i]).reverse());
old = this[_prop_piece].m;
this[_prop_piece].m = temp;
if (this._C()) this[_prop_piece].m = old;
}
play(k, e) {
if (k === "ArrowLeft") { e[_m_preventDefault](); this.move(-1); }
if (k === "ArrowRight") { e[_m_preventDefault](); this.move(1); }
if (k === "ArrowDown") { e[_m_preventDefault](); this.drop(1); }
if (k === "ArrowUp") { e[_m_preventDefault](); this.rot8(); }
}
}
$Window.Tetris = Tetris;
$Document[_m_addEventListener]("DOMContentLoaded", (game, keydown, on, toggle) => {
on = false;
game = new Tetris('#tetris');
keydown = (e) => game.play(e.key, e);
toggle = (o) => $Document[o ? (game.reset(), _m_addEventListener) : 'removeEventListener']("keydown", keydown);
game.$canvas[_m_addEventListener]('mouseenter', () => toggle((on = true, on)));
game.$canvas[_m_addEventListener]('mouseout', () => toggle((on = false, on)));
});
})(
window,
document,
'addEventListener',
'preventDefault',
'forEach',
'$canvas',
'score',
'board',
'piece',
10,
20,
[
[[1, 1, 1, 1]],
[[1, 1], [1, 1]],
[[0, 1, 0], [1, 1, 1]],
[[1, 1, 0], [0, 1, 1]],
[[0, 1, 1], [1, 1, 0]],
[[1, 0, 0], [1, 1, 1]],
[[0, 0, 1], [1, 1, 1]]
],
['#000', "#0FF", "#FF0", "#80F", "#0F0", "#F00", "#F80", "#00F"],
[0, 100, 300, 500, 800]
);
</script>