Created
July 22, 2014 06:36
-
-
Save lambda-fairy/d6b033a6afd94dc0a6e3 to your computer and use it in GitHub Desktop.
Minimal Tetris implementation
This file contains hidden or 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> | |
| <title>Blahtris</title> | |
| <style type="text/css"> | |
| div#sandbox { | |
| float: left; | |
| position: relative; | |
| } | |
| div#msgbox { | |
| position: absolute; | |
| top: 45%; | |
| left: 0; | |
| right: 0; | |
| text-align: center; | |
| } | |
| div#grid-holder { | |
| border: 1px solid #aaa; | |
| float: left; | |
| position: relative; | |
| margin: 1em 1em 0.5em; | |
| } | |
| div.hide { | |
| visibility: hidden; | |
| } | |
| div.asplode { | |
| background: #afa; | |
| color: #0a0; | |
| font-size: 1.5em; | |
| } | |
| div.pause { | |
| background: #aaf; | |
| color: #00f; | |
| font-size: 1.5em; | |
| } | |
| div.fail { | |
| background: #faa; | |
| color: #f00; | |
| font-size: 1.5em; | |
| } | |
| table#grid { | |
| border-spacing: 0; | |
| } | |
| table#grid td { | |
| width: 1em; | |
| height: 1em; | |
| } | |
| td.full { | |
| background: #333; | |
| } | |
| td.empty { | |
| background: #ccc; | |
| } | |
| p#instructions { | |
| clear: both; | |
| font-size: 75%; | |
| line-height: 1em; | |
| background: #ccc; | |
| color: #999; | |
| margin: 0.5em; | |
| } | |
| p#instructions span { | |
| float: left; | |
| position: relative; | |
| margin: 0 0.75em; | |
| } | |
| </style> | |
| <script type="text/javascript"> | |
| var w = 10, h = 20; | |
| var cells; | |
| var msgbox; | |
| var matrix; | |
| var blockNum, rotation; | |
| var going = true; | |
| var blocks = [ | |
| [ | |
| [ | |
| [0,0,0,0], | |
| [0,1,1,0], | |
| [0,1,1,0], | |
| [0,0,0,0], | |
| ], | |
| ], | |
| [ | |
| [ | |
| [0,0,0,0], | |
| [0,1,1,0], | |
| [0,0,1,0], | |
| [0,0,1,0], | |
| ], | |
| [ | |
| [0,0,0,0], | |
| [0,0,0,1], | |
| [0,1,1,1], | |
| [0,0,0,0], | |
| ], | |
| [ | |
| [0,0,0,0], | |
| [0,1,0,0], | |
| [0,1,0,0], | |
| [0,1,1,0], | |
| ], | |
| [ | |
| [0,0,0,0], | |
| [0,1,1,1], | |
| [0,1,0,0], | |
| [0,0,0,0], | |
| ], | |
| ], | |
| [ | |
| [ | |
| [0,0,0,0], | |
| [0,1,1,0], | |
| [0,1,0,0], | |
| [0,1,0,0], | |
| ], | |
| [ | |
| [0,0,0,0], | |
| [0,1,1,1], | |
| [0,0,0,1], | |
| [0,0,0,0], | |
| ], | |
| [ | |
| [0,0,0,0], | |
| [0,0,1,0], | |
| [0,0,1,0], | |
| [0,1,1,0], | |
| ], | |
| [ | |
| [0,0,0,0], | |
| [0,1,0,0], | |
| [0,1,1,1], | |
| [0,0,0,0], | |
| ], | |
| ], | |
| [ | |
| [ | |
| [0,1,0,0], | |
| [0,1,0,0], | |
| [0,1,0,0], | |
| [0,1,0,0], | |
| ], | |
| [ | |
| [0,0,0,0], | |
| [1,1,1,1], | |
| [0,0,0,0], | |
| [0,0,0,0], | |
| ], | |
| ], | |
| [ | |
| [ | |
| [0,0,0,0], | |
| [0,0,1,0], | |
| [0,1,1,1], | |
| [0,0,0,0], | |
| ], | |
| [ | |
| [0,0,0,0], | |
| [0,0,1,0], | |
| [0,0,1,1], | |
| [0,0,1,0], | |
| ], | |
| [ | |
| [0,0,0,0], | |
| [0,0,0,0], | |
| [0,1,1,1], | |
| [0,0,1,0], | |
| ], | |
| [ | |
| [0,0,0,0], | |
| [0,0,1,0], | |
| [0,1,1,0], | |
| [0,0,1,0], | |
| ], | |
| ], | |
| ]; | |
| var current = null; | |
| var offsetx = 0, offsety = 0; | |
| function createMatrix(rows, cols, value) { | |
| var res = new Array(rows); | |
| for(var j = 0; j < rows; j++) { | |
| res[j] = new Array(cols); | |
| for(var i = 0; i < cols; i++) { | |
| res[j][i] = value; | |
| } | |
| } | |
| return res; | |
| } | |
| function paint() { | |
| for(var j = 0; j < h; j++) { | |
| for(var i = 0; i < w; i++) { | |
| if(matrix[j][i] || (current && j >= offsety && j < offsety+4 && i >= offsetx && i < offsetx+4 && current[j-offsety][i-offsetx])) { | |
| cells[j][i].className = "full"; | |
| } else { | |
| cells[j][i].className = "empty"; | |
| } | |
| } | |
| } | |
| } | |
| function cement() { | |
| if(!current) return; | |
| for(var j = 0; j < 4; j++) { | |
| if(j+offsety < h) { | |
| for(var i = 0; i < 4; i++) { | |
| if(i+offsetx < w) { | |
| matrix[j+offsety][i+offsetx] |= current[j][i]; | |
| } | |
| } | |
| } | |
| } | |
| current = null; | |
| } | |
| function overlapsWithMatrix() { | |
| if(!current) { | |
| return true; | |
| } | |
| for(var j = 0; j < 4; j++) { | |
| for(var i = 0; i < 4; i++) { | |
| if(current[j][i] && (j+offsety >= h || i+offsetx >= w || i+offsetx < 0 || matrix[j+offsety][i+offsetx])) { | |
| return true; | |
| } | |
| } | |
| } | |
| return false; | |
| } | |
| function aSplodeRow(row) { | |
| for(var j = row-1; j >= 0; j--) { | |
| for(var i = 0; i < w; i++) { | |
| matrix[j+1][i] = matrix[j][i]; | |
| if(j == 0) { | |
| matrix[j][i] = 0; | |
| } | |
| } | |
| } | |
| msgbox.className = "asplode"; | |
| msgbox.innerHTML = "Blam!"; | |
| setTimeout(function() { msgbox.className = "hide"; }, 500); | |
| } | |
| function checkFullRow() { | |
| for(var j = h-1; j >= 0; j--) { | |
| var isFull = true; | |
| for(var i = 0; i < w; i++) { | |
| if(!matrix[j][i]) { | |
| isFull = false; | |
| break; | |
| } | |
| } | |
| if(isFull) { | |
| aSplodeRow(j); | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| function moveDown() { | |
| ++offsety; | |
| if(!overlapsWithMatrix()) { | |
| return true; | |
| } else { | |
| --offsety; | |
| return false; | |
| } | |
| } | |
| function moveLeft() { | |
| --offsetx; | |
| if(!overlapsWithMatrix()) { | |
| return true; | |
| } else { | |
| ++offsetx; | |
| return false; | |
| } | |
| } | |
| function moveRight() { | |
| ++offsetx; | |
| if(!overlapsWithMatrix()) { | |
| return true; | |
| } else { | |
| --offsetx; | |
| return false; | |
| } | |
| } | |
| function rotateCW() { | |
| var newRotation = (rotation + 1) % blocks[blockNum].length; | |
| current = blocks[blockNum][newRotation]; | |
| if(overlapsWithMatrix()) { | |
| current = blocks[blockNum][rotation]; | |
| } else { | |
| rotation = newRotation; | |
| paint(); | |
| } | |
| } | |
| function drop() { | |
| while(moveDown()) ; // keep moving down 'til I reach the bottom | |
| paint(); | |
| } | |
| function togglePause() { | |
| if(going) { | |
| going = false; | |
| msgbox.className = "pause"; | |
| msgbox.innerHTML = "Paused"; | |
| } else { | |
| going = true; | |
| msgbox.className = "hide"; | |
| loop(); | |
| } | |
| } | |
| function handleKeyboard(e) { | |
| e = e || window.event; // hack for IE | |
| var bindings = { | |
| 32: drop, | |
| 37: moveLeft, | |
| 38: rotateCW, | |
| 39: moveRight, | |
| 80: togglePause, | |
| }; | |
| if(bindings[e.keyCode]) { | |
| var f = bindings[e.keyCode]; | |
| if(f()) { | |
| paint(); | |
| } | |
| return false; | |
| } | |
| return true; | |
| } | |
| function youLose() { | |
| msgbox.className = "fail"; | |
| msgbox.innerHTML = "You Lose!" | |
| } | |
| function loop() { | |
| if(!going) | |
| return; | |
| if(!moveDown()) { | |
| cement(); | |
| // only place a new block when there's no more lines to asplode | |
| if(!checkFullRow()) { | |
| offsetx = parseInt(w / 2) - 2; | |
| offsety = 0; | |
| blockNum = parseInt(Math.random()*(blocks.length)); | |
| rotation = parseInt(Math.random()*(blocks[blockNum].length)); | |
| current = blocks[blockNum][rotation]; | |
| if(overlapsWithMatrix()) { | |
| youLose(); | |
| return; | |
| } | |
| } | |
| } | |
| paint(); | |
| setTimeout(loop, 1000); | |
| } | |
| window.onload = function() { | |
| var gridHolder = document.createElement("div"); | |
| gridHolder.id = "grid-holder"; | |
| var grid = document.createElement("table"); | |
| grid.id = "grid"; | |
| cells = new Array(h); | |
| for(var j = 0; j < h; j++) { | |
| var row = document.createElement("tr"); | |
| cells[j] = new Array(w); | |
| for(var i = 0; i < w; i++) { | |
| var cell = document.createElement("td"); | |
| cells[j][i] = cell; | |
| row.appendChild(cell); | |
| } | |
| grid.appendChild(row); | |
| } | |
| msgbox = document.createElement("div"); | |
| msgbox.id = "msgbox"; | |
| msgbox.className = "hide"; | |
| var sandbox = document.getElementById("sandbox"); | |
| document.onkeydown = handleKeyboard; | |
| gridHolder.appendChild(grid); | |
| gridHolder.appendChild(msgbox); | |
| sandbox.appendChild(gridHolder); | |
| var inst = document.createElement("p"); | |
| inst.id = "instructions"; | |
| inst.innerHTML = "<span>◀ ▶ Move</span> <span>▲ Rotate</span> <span><b>[Space]</b> Drop</span>"; | |
| sandbox.appendChild(inst); | |
| matrix = createMatrix(h, w, 0); | |
| loop(); | |
| }; | |
| </script> | |
| </head> | |
| <body> | |
| <div id="sandbox"></div> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment