Skip to content

Instantly share code, notes, and snippets.

@murooka
Created September 14, 2014 20:58
Show Gist options
  • Select an option

  • Save murooka/45eec53ef2315d594c7d to your computer and use it in GitHub Desktop.

Select an option

Save murooka/45eec53ef2315d594c7d to your computer and use it in GitHub Desktop.
(function () {
var initBoard = function (w, h) {
var board = [];
for (var y=0; y<h; y++) {
var line = [];
for (var x=0; x<w; x++) {
line.push(0);
}
board.push(line);
}
for (var y=0; y<h; y++) {
for (var x=0; x<w; x++) {
if (y == h - 1 || x == 0 || x == w - 1) {
board[y][x] = 1;
}
}
}
return board;
}
var canvas = document.getElementById('tetris');
var width = canvas.width;
var height = canvas.height;
var ctx = canvas.getContext('2d');
var W = 12;
var H = 24;
var S = 30;
var colors = [
{ r: 191, g: 191, b: 191 },
{ r: 255, g: 0, b: 0 },
{ r: 255, g: 255, b: 0 },
{ r: 0, g: 255, b: 0 },
{ r: 0, g: 255, b: 255 },
{ r: 0, g: 0, b: 255 },
{ r: 255, g: 0, b: 255 },
{ r: 255, g: 127, b: 63 },
];
var strFromColor = function(r, g, b) {
return 'rgb('+(r|0)+','+(g|0)+','+(b|0)+')';
};
var BLOCKS = [
{ p: [{ x: 0, y: 0}, { x: 0, y: 0}, { x: 0, y: 0}] }, // null
{ p: [{ x:-1, y: 0}, { x: 1, y: 0}, { x: 2, y: 0}] }, // I
{ p: [{ x: 0, y:-1}, { x: 0, y: 1}, { x: 1, y: 1}] }, // J
{ p: [{ x: 0, y:-1}, { x: 0, y: 1}, { x:-1, y: 1}] }, // L
{ p: [{ x: 0, y:-1}, { x:-1, y: 0}, { x:-1, y: 1}] }, // N
{ p: [{ x: 0, y:-1}, { x: 1, y: 0}, { x: 1, y: 1}] }, // Z
{ p: [{ x: 1, y: 0}, { x: 0, y: 1}, { x: 1, y: 1}] }, // O
{ p: [{ x: 0, y:-1}, { x:-1, y: 0}, { x: 1, y: 0}] }, // T
];
var Hand = function (x, y, t) {
this.x = x;
this.y = y;
this.r = 0;
this.t = t;
};
Hand.copy = function (h) {
var ret = new Hand(h.x, h.y, h.t);
ret.r = h.r;
return ret;
};
var putBlock = function (b, act) {
if (board[b.y][b.x] != 0) return false;
if (act) board[b.y][b.x] = b.t;
var B = BLOCKS[b.t];
for (var i=0,len=B.p.length; i<len; i++) {
var x = B.p[i].x;
var y = B.p[i].y;
for (var j=0; j<(b.r%4+4)%4; j++) {
var nx = -y;
var ny = x;
x = nx;
y = ny;
}
x += b.x;
y += b.y;
if (board[y][x] != 0) return;
if (act) board[y][x] = b.t;
}
if (!act) {
putBlock(b, true);
}
return true;
};
var deleteBlock = function (b) {
board[b.y][b.x] = 0;
var B = BLOCKS[b.t];
for (var i=0,len=B.p.length; i<len; i++) {
var x = B.p[i].x;
var y = B.p[i].y;
for (var j=0; j<(b.r%4+4)%4; j++) {
var nx = -y;
var ny = x;
x = nx;
y = ny;
}
x += b.x;
y += b.y;
board[y][x] = 0;
}
}
var fallBlock = function (b) {
var tmp = Hand.copy(current);
tmp.y++;
deleteBlock(current);
if (!putBlock(tmp) ) {
putBlock(current);
return false;
}
current = tmp;
return true;
};
var gameOver = function () {
for (var y=1; y<H-1; y++) {
for (var x=1; x<W; x++) {
if (board[y][x] != 0) {
board[y][x] = 1;
}
}
}
};
var generateNext = function () {
return new Hand(((W-2) / 2) | 0, 1, ((Math.random() * 7) | 0) + 1);
};
var eraseLine = function () {
for (var y=0; y<H-1; y++) {
var shouldErase = true;
for (var x=1; x<W; x++) {
if (board[y][x] === 0) shouldErase = false;
}
if (shouldErase) {
for (i=y; i>0; i--) {
for (var x=1; x<W; x++) {
board[i][x] = board[i-1][x];
}
}
y--;
}
}
};
var renderBlock = function (x, y, c) {
var m = 1.6;
ctx.fillStyle = strFromColor(c.r/m, c.g/m, c.b/m);
ctx.fillRect(x, y, S, S);
ctx.fillStyle = strFromColor(c.r, c.g, c.b);
ctx.fillRect(x, y, S, 2);
ctx.fillRect(x, y, 2, S);
var d = 1.8;
ctx.fillStyle = strFromColor(c.r/d, c.g/d, c.b/d);
ctx.fillRect(x+S-2, y, 2, S);
ctx.fillRect(x, y+S-2, S, 2);
};
var render = function () {
ctx.clearRect(0, 0, width, height);
for (var y=1; y<H-1; y++) {
for (var x=1; x<W; x++) {
var c = colors[board[y][x]];
renderBlock((x-1)*S, (y-3)*S, c);
}
}
};
var board = initBoard(12, 24);
var current = generateNext();
var counter = 0;
var keyQueue = [];
var update = function () {
var shouldFall = false;
while (1) {
var key = keyQueue.shift()
if (!key) break;
var tmp = Hand.copy(current);
if (key === 'Left') {
tmp.x--;
} else if (key === 'Right') {
tmp.x++;
} else if (key === 'Down') {
shouldFall = true;
} else if (key === 'U+005A') {
tmp.r--;
} else if (key === 'U+0058') {
tmp.r++;
}
if (current.x != tmp.x || current.y != tmp.y || current.r != tmp.r) {
deleteBlock(current);
if ( putBlock(tmp) ) {
current = tmp;
} else {
putBlock(current);
}
}
}
if (shouldFall || counter % 10 == 0) {
var success = fallBlock();
if (!success) {
eraseLine();
current = generateNext();
if (!putBlock(current)) {
gameOver();
}
}
counter = 0;
}
counter++;
};
window.addEventListener('keydown', function (e) {
keyQueue.push(e.keyIdentifier);
});
putBlock(current);
setInterval(function () {
update();
render();
}, 1000 / 30);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment