Last active
December 20, 2015 08:09
-
-
Save grindars/6098560 to your computer and use it in GitHub Desktop.
This file contains 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
<!DOCTYPE html> | |
<html> | |
<head> | |
<script> | |
!function(){this.Shape=function(){function Shape(){}Shape.prototype.rotated=null;Shape.$shapeTemplates=[{rotated:7,blocks:["TL","TC","MR"],color:"red"},{rotated:8,blocks:["TC","TR","ML"],color:"lime"},{rotated:9,blocks:["ML","MR","BC"],color:"#aa00ff"},{rotated:3,blocks:["TL","TC","ML"],color:"yellow"},{rotated:12,blocks:["ML","BL","MR"],color:"orange"},{rotated:15,blocks:["ML","BR","MR"],color:"blue"},{rotated:18,blocks:["ML","MR","MSR"],color:"cyan"},{rotated:0,blocks:["TC","ML","BL"],color:"red"},{rotated:1,blocks:["TC","MR","BR"],color:"lime"},{rotated:10,blocks:["TC","MR","BC"],color:"#aa00ff"},{rotated:11,blocks:["TC","ML","MR"],color:"#aa00ff"},{rotated:2,blocks:["TC","ML","BC"],color:"#aa00ff"},{rotated:13,blocks:["TC","BC","BR"],color:"orange"},{rotated:14,blocks:["TR","ML","MR"],color:"orange"},{rotated:4,blocks:["TL","TC","BC"],color:"orange"},{rotated:16,blocks:["TR","TC","BC"],color:"blue"},{rotated:17,blocks:["TL","ML","MR"],color:"blue"},{rotated:5,blocks:["TC","BC","BL"],color:"blue"},{rotated:6,blocks:["TC","BC","BSC"],color:"cyan"}];Shape.prototype.initializeBlocksFromTemplate=function(template,cols,rows){var offset;this.blocks=function(){var _i,_len,_results;_results=[];for(_i=0,_len=template.length;_i<_len;_i++){offset=template[_i];switch(offset){case"TL":_results.push(-cols-1);break;case"TC":_results.push(-cols);break;case"TR":_results.push(-cols+1);break;case"ML":_results.push(-1);break;case"MR":_results.push(1);break;case"MSR":_results.push(2);break;case"BL":_results.push(cols-1);break;case"BC":_results.push(cols);break;case"BR":_results.push(cols+1);break;case"BSC":_results.push(2*cols);break;default:_results.push(void 0)}}return _results}();return this.blocks.unshift(0)};Shape.forBoard=function(cols,rows){var index,shape,shapes,template,_i,_j,_len,_ref;shapes=new Array(this.$shapeTemplates.length);for(shape=_i=0,_ref=shapes.length;0<=_ref?_i<_ref:_i>_ref;shape=0<=_ref?++_i:--_i){shapes[shape]=new Shape}for(index=_j=0,_len=shapes.length;_j<_len;index=++_j){shape=shapes[index];template=this.$shapeTemplates[index];shape.rotated=shapes[template.rotated];shape.color=template.color;shape.initializeBlocksFromTemplate(template.blocks,cols,rows)}return shapes};return Shape}()}.call(this);!function(){this.Board=function(){Board.prototype.cols=12;Board.prototype.rows=23;function Board(){var col,row,_i,_j,_ref,_ref1;this.$board=new Array(this.cols*this.rows);for(col=_i=0,_ref=this.cols;0<=_ref?_i<_ref:_i>_ref;col=0<=_ref?++_i:--_i){for(row=_j=0,_ref1=this.rows;0<=_ref1?_j<_ref1:_j>_ref1;row=0<=_ref1?++_j:--_j){if(col===0||col===this.cols-1||row>=this.rows-2){this.$board[col+row*this.cols]="gray"}else{this.$board[col+row*this.cols]=null}}}this.shapes=Shape.forBoard(this.cols,this.rows)}Board.prototype.fits=function(pos,shape){var block,_i,_len,_ref;_ref=shape.blocks;for(_i=0,_len=_ref.length;_i<_len;_i++){block=_ref[_i];if(this.$board[pos+block]!==null){return false}}return true};Board.prototype.place=function(pos,shape,state){var block,_i,_len,_ref;_ref=shape.blocks;for(_i=0,_len=_ref.length;_i<_len;_i++){block=_ref[_i];if(state){this.$board[pos+block]=shape.color}else{this.$board[pos+block]=null}}return true};Board.prototype.color=function(pos){return this.$board[pos]};Board.prototype.elide=function(){var col,row,_i,_j,_ref,_ref1;for(row=_i=1,_ref=this.rows-2;1<=_ref?_i<_ref:_i>_ref;row=1<=_ref?++_i:--_i){if(this.$rowIsFilled(row)){for(col=_j=1,_ref1=this.cols-1;1<=_ref1?_j<_ref1:_j>_ref1;col=1<=_ref1?++_j:--_j){this.$board[row*this.cols+col]=null}return function(){var copyaddr,_k,_ref2,_results;_results=[];for(copyaddr=_k=_ref2=row*this.cols;_ref2<=0?_k<=0:_k>=0;copyaddr=_ref2<=0?++_k:--_k){_results.push(this.$board[copyaddr+this.cols]=this.$board[copyaddr])}return _results}}}return null};Board.prototype.$rowIsFilled=function(row){var col,_i,_ref;for(col=_i=1,_ref=this.cols-1;1<=_ref?_i<_ref:_i>_ref;col=1<=_ref?++_i:--_i){if(this.$board[row*this.cols+col]===null){return false}}return true};return Board}()}.call(this);!function(){this.UserInterface=function(){UserInterface.prototype.blockSize=24;UserInterface.prototype.previewMargin=8;UserInterface.prototype.fontSize=16;UserInterface.prototype.largeFontSize=24;function UserInterface(container,inputReceiver){this.$canvas=document.createElement("canvas");this.$canvas.width=480;this.$canvas.height=640;this.$canvas.tabIndex=1;container.appendChild(this.$canvas);this.$canvas.focus();this.$canvas.addEventListener("keydown",this.$keydown.bind(this),false);this.$context=this.$canvas.getContext("2d");this.$inputReceiver=inputReceiver}UserInterface.prototype.$keydown=function(ev){switch(ev.keyCode){case 37:return this.$inputReceiver.pushKey("left");case 39:return this.$inputReceiver.pushKey("right");case 38:return this.$inputReceiver.pushKey("rotate");case 40:return this.$inputReceiver.pushKey("drop")}};UserInterface.prototype.updateScreen=function(){var block,board,col,color,pos,row,uiOffset,_i,_j,_k,_len,_ref,_ref1,_ref2;board=this.$inputReceiver.board;this.$context.fillStyle="#fff";this.$context.strokeStyle="rgba(0,0,0,0.5)";this.$context.fillRect(0,0,this.$canvas.width,this.$canvas.height);for(col=_i=0,_ref=board.cols;0<=_ref?_i<_ref:_i>_ref;col=0<=_ref?++_i:--_i){for(row=_j=0,_ref1=board.rows;0<=_ref1?_j<_ref1:_j>_ref1;row=0<=_ref1?++_j:--_j){pos=row*board.cols+col;color=board.color(pos);if(color!==null){this.$context.fillStyle=color;this.$context.fillRect(col*this.blockSize,row*this.blockSize,this.blockSize,this.blockSize);this.$context.strokeRect(col*this.blockSize,row*this.blockSize,this.blockSize,this.blockSize)}}}uiOffset=this.blockSize*(board.cols+1);this.$context.fillStyle="gray";this.$context.font=this.fontSize+"px monospace";this.$context.fillRect(uiOffset,this.blockSize,this.blockSize*6,this.blockSize*6);this.$context.fillStyle="white";this.$context.fillRect(uiOffset+this.blockSize-this.previewMargin,2*this.blockSize-this.previewMargin,this.blockSize*4+this.previewMargin*2,this.blockSize*4+this.previewMargin*2);this.$context.fillStyle=this.$inputReceiver.nextShape.color;_ref2=this.$inputReceiver.nextShape.blocks;for(_k=0,_len=_ref2.length;_k<_len;_k++){block=_ref2[_k];block+=board.cols+1;col=block%board.cols;row=block/board.cols<<0;this.$context.fillRect(uiOffset+this.blockSize+col*this.blockSize,2*this.blockSize+row*this.blockSize,this.blockSize,this.blockSize);this.$context.strokeRect(uiOffset+this.blockSize+col*this.blockSize,2*this.blockSize+row*this.blockSize,this.blockSize,this.blockSize)}this.$context.fillStyle="black";this.$context.fillText("Score: "+this.$inputReceiver.score,uiOffset,this.blockSize*8+this.fontSize);return this.$context.fillText("Level: "+this.$inputReceiver.level,uiOffset,this.blockSize*8+2*this.fontSize)};UserInterface.prototype.gameOver=function(){var line,lines,metrics,totalHeight,y_offset,_i,_j,_len,_len1,_results;this.$context.fillStyle="#fff";this.$context.fillRect(0,0,this.$canvas.width,this.$canvas.height);this.$context.fillStyle="#000";lines=[{height:this.largeFontSize,text:"Game over"},{height:this.largeFontSize,text:""},{height:this.fontSize,text:"Score: "+this.$inputReceiver.score},{height:this.fontSize,text:"Level: "+this.$inputReceiver.level}];totalHeight=0;for(_i=0,_len=lines.length;_i<_len;_i++){line=lines[_i];totalHeight+=line.height}y_offset=(this.$canvas.height-totalHeight)/2;_results=[];for(_j=0,_len1=lines.length;_j<_len1;_j++){line=lines[_j];this.$context.font=line.height+"px monospace";metrics=this.$context.measureText(line.text);this.$context.fillText(line.text,(this.$canvas.width-metrics.width)/2,y_offset);_results.push(y_offset+=line.height)}return _results};return UserInterface}()}.call(this);!function(){this.Tetris=function(){function Tetris(container,level){this.board=new Board;this.$ui=new UserInterface(container,this);this.$pendingInputQueue=[];this.score=0;this.level=level;this.$fallRate=1e3/level;this.nextShape=this.$randomShape();this.currentShape=this.$randomShape();this.$pos=1*this.board.cols+this.board.cols/2-1;this.$gameTick()}Tetris.prototype.$randomShape=function(){var index;index=Math.floor(Math.random()*this.board.shapes.length);return this.board.shapes[index]};Tetris.prototype.$gameTick=function(){this.board.place(this.$pos,this.currentShape,true);this.$ui.updateScreen();this.board.place(this.$pos,this.currentShape,false);return this.$receiveInput(function(ch){switch(ch){case null:if(this.board.fits(this.$pos+this.board.cols,this.currentShape)){this.$pos+=this.board.cols;return this.$gameTick()}else{this.board.place(this.$pos,this.currentShape,true);this.score++;return this.$elide(function(){this.currentShape=this.nextShape;this.nextShape=this.$randomShape();this.$pos=1*this.board.cols+this.board.cols/2-1;if(this.board.fits(this.$pos,this.currentShape)){return this.$gameTick()}else{return this.$ui.gameOver()}})}break;case"left":if(this.board.fits(this.$pos-1,this.currentShape)){this.$pos--}return this.$gameTick();case"right":if(this.board.fits(this.$pos+1,this.currentShape)){this.$pos++}return this.$gameTick();case"rotate":if(this.board.fits(this.$pos,this.currentShape.rotated)){this.currentShape=this.currentShape.rotated}return this.$gameTick();case"drop":while(this.board.fits(this.$pos+this.board.cols,this.currentShape)){this.$pos+=this.board.cols;this.score++}return this.$gameTick()}})};Tetris.prototype.$elide=function(callback){var boardCallback,forwardCallback,shiftCallback,_this=this;boardCallback=this.board.elide();if(boardCallback!=null){forwardCallback=function(){return _this.$elide(callback)};shiftCallback=function(){boardCallback.call(_this.board);_this.$ui.updateScreen();return setTimeout(forwardCallback,100)};this.$ui.updateScreen();return setTimeout(shiftCallback,100)}else{return callback.call(this)}};Tetris.prototype.$receiveInput=function(callback){var timeout,timeoutHandler,_this=this;if(this.$pendingInputQueue.length>0){callback.call(this,this.$pendingInputQueue.shift());return}if(this.$tickRemaining!=null){timeout=this.$tickRemaining;delete this.$tickRemaining}else{timeout=this.$fallRate}this.$inputReceiver=callback;this.$inputStarted=(new Date).valueOf();timeoutHandler=function(){delete _this.$inputTimeout;delete _this.$inputReceiver;delete _this.$inputStarted;return callback.call(_this,null)};return this.$inputTimeout=setTimeout(timeoutHandler,timeout)};Tetris.prototype.pushKey=function(code){var receiver;if(this.$inputTimeout!=null){receiver=this.$inputReceiver;this.$tickRemaining=this.$fallRate-((new Date).valueOf()-this.$inputStarted);clearTimeout(this.$inputTimeout);delete this.$inputTimeout;delete this.$inputStarted;delete this.$inputReceiver;return receiver.call(this,code)}else{return this.$pendingInputQueue.push(code)}};return Tetris}()}.call(this); </script> | |
<script> | |
window.addEventListener('load', function() { | |
var tetris = new Tetris(document.getElementById('container'), 2); | |
}); | |
</script> | |
<style> | |
#container > canvas { | |
border: solid 1px #000; | |
} | |
</style> | |
</head> | |
<body> | |
<div id='container'></div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment