├── .gitignore ├── share-image.png ├── ambient ├── css │ └── styles.css ├── index.html ├── custom │ ├── color_manager.js │ ├── random_piece_generator.js │ └── piece.js └── js │ └── index.js ├── classic ├── css │ └── styles.css ├── index.html ├── custom │ ├── random_piece_generator.js │ ├── piece.js │ ├── game_manager.js │ └── draw_functions.js └── js │ └── index.js ├── colored_classic ├── css │ └── styles.css ├── index.html ├── custom │ ├── random_piece_generator.js │ ├── piece.js │ ├── game_manager.js │ └── draw_functions.js └── js │ └── index.js ├── readme.md ├── package.json ├── core └── js │ ├── random_piece_generator.js │ ├── updater.js │ ├── ai.js │ ├── utils.js │ ├── piece.js │ ├── game_manager.js │ └── grid.js ├── gulpfile.js ├── styles.css └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules -------------------------------------------------------------------------------- /share-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/tetris-pieces/HEAD/share-image.png -------------------------------------------------------------------------------- /ambient/css/styles.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Styles! 3 | */ 4 | 5 | * { 6 | box-sizing: border-box; 7 | } 8 | 9 | html, body { 10 | min-height: 100%; 11 | min-width: 100%; 12 | margin: 0px; 13 | width: 0px; 14 | height: 100%; 15 | overflow: hidden; 16 | } 17 | 18 | canvas { 19 | background: #fff; 20 | position: absolute; 21 | bottom: 0px; 22 | } 23 | -------------------------------------------------------------------------------- /classic/css/styles.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Styles! 3 | */ 4 | 5 | * { 6 | box-sizing: border-box; 7 | } 8 | 9 | html, body { 10 | min-height: 100%; 11 | min-width: 100%; 12 | margin: 0px; 13 | width: 0px; 14 | height: 100%; 15 | overflow: hidden; 16 | } 17 | 18 | canvas { 19 | background: #C6CFA4; 20 | position: absolute; 21 | bottom: 0px; 22 | } 23 | -------------------------------------------------------------------------------- /colored_classic/css/styles.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Styles! 3 | */ 4 | 5 | * { 6 | box-sizing: border-box; 7 | } 8 | 9 | html, body { 10 | min-height: 100%; 11 | min-width: 100%; 12 | margin: 0px; 13 | width: 0px; 14 | height: 100%; 15 | overflow: hidden; 16 | } 17 | 18 | canvas { 19 | background: #fff; 20 | position: absolute; 21 | bottom: 0px; 22 | } 23 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Tetris Pieces, for the electric object 2 | 3 | A visual artificially intelligent tetris, built to be displayed on your wall. You can see them in action [here](http://tholman.com/tetris-pieces). 4 | 5 | This is the source for the styalized version for the electric object. 6 | 7 | The source of the AI running behind the scenes is built by the incredible Yiyuan 8 | 9 | ![tetris at play](https://i.imgur.com/7Aby4cV.png) 10 | -------------------------------------------------------------------------------- /ambient/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Tetris AI 7 | 8 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /ambient/custom/color_manager.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Color Manager 3 | * - Handles the slow hue rotations of colors 4 | */ 5 | 6 | function ColorManager( baseColor ){ 7 | this.hueRotation = 0; 8 | this.rotationSpeed = 4; 9 | this.baseColor = '#F0C9DD'; // Light pink 10 | }; 11 | 12 | ColorManager.prototype.getColor = function(){ 13 | 14 | // Rotate hue's for every new piece. 15 | this.hueRotation += this.rotationSpeed; 16 | if( this.hueRotation > 360 ) { 17 | this.hueRotation = 0; 18 | } 19 | 20 | return changeHue(this.baseColor, this.hueRotation); 21 | }; -------------------------------------------------------------------------------- /classic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Tetris AI 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /colored_classic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Tetris AI 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tetris", 3 | "version": "1.0.0", 4 | "description": "Tetris Sims for the Electric Object", 5 | "main": "gulpfile.js", 6 | "dependencies": {}, 7 | "devDependencies": { 8 | "gulp": "^3.9.1" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/tholman/electric-object-tetris.git" 16 | }, 17 | "author": "", 18 | "license": "ISC", 19 | "bugs": { 20 | "url": "https://github.com/tholman/electric-object-tetris/issues" 21 | }, 22 | "homepage": "https://github.com/tholman/electric-object-tetris#readme" 23 | } 24 | -------------------------------------------------------------------------------- /core/js/random_piece_generator.js: -------------------------------------------------------------------------------- 1 | function RandomPieceGenerator(){ 2 | Math.seed 3 | this.bag = [0, 1, 2, 3, 4, 5, 6]; 4 | this.shuffleBag(); 5 | this.index = -1; 6 | 7 | this.colorManager = new ColorManager(); 8 | }; 9 | 10 | RandomPieceGenerator.prototype.nextPiece = function(){ 11 | 12 | this.index++; 13 | if (this.index >= this.bag.length){ 14 | this.shuffleBag(); 15 | this.index = 0; 16 | } 17 | 18 | var color = this.colorManager.getColor(); 19 | 20 | return Piece.fromIndex(this.bag[this.index], color); 21 | 22 | }; 23 | 24 | RandomPieceGenerator.prototype.shuffleBag = function() { 25 | var currentIndex = this.bag.length 26 | , temporaryValue 27 | , randomIndex 28 | ; 29 | 30 | // While there remain elements to shuffle... 31 | while (0 !== currentIndex) { 32 | 33 | // Pick a remaining element... 34 | randomIndex = Math.floor(Math.random() * currentIndex); 35 | currentIndex -= 1; 36 | 37 | // And swap it with the current element. 38 | temporaryValue = this.bag[currentIndex]; 39 | this.bag[currentIndex] = this.bag[randomIndex]; 40 | this.bag[randomIndex] = temporaryValue; 41 | } 42 | }; -------------------------------------------------------------------------------- /classic/custom/random_piece_generator.js: -------------------------------------------------------------------------------- 1 | function RandomPieceGenerator(){ 2 | Math.seed 3 | this.bag = [0, 1, 2, 3, 4, 5, 6]; 4 | this.shuffleBag(); 5 | this.index = -1; 6 | 7 | this.drawFunctions = new DrawFunctions(); 8 | }; 9 | 10 | RandomPieceGenerator.prototype.nextPiece = function(){ 11 | 12 | this.index++; 13 | if (this.index >= this.bag.length){ 14 | this.shuffleBag(); 15 | this.index = 0; 16 | } 17 | 18 | return Piece.fromIndex(this.bag[this.index], this.drawFunctions.getDrawFunction(this.bag[this.index])); 19 | 20 | }; 21 | 22 | RandomPieceGenerator.prototype.shuffleBag = function() { 23 | var currentIndex = this.bag.length 24 | , temporaryValue 25 | , randomIndex 26 | ; 27 | 28 | // While there remain elements to shuffle... 29 | while (0 !== currentIndex) { 30 | 31 | // Pick a remaining element... 32 | randomIndex = Math.floor(Math.random() * currentIndex); 33 | currentIndex -= 1; 34 | 35 | // And swap it with the current element. 36 | temporaryValue = this.bag[currentIndex]; 37 | this.bag[currentIndex] = this.bag[randomIndex]; 38 | this.bag[randomIndex] = temporaryValue; 39 | } 40 | }; -------------------------------------------------------------------------------- /ambient/custom/random_piece_generator.js: -------------------------------------------------------------------------------- 1 | function RandomPieceGenerator(){ 2 | Math.seed 3 | this.bag = [0, 1, 2, 3, 4, 5, 6]; 4 | this.shuffleBag(); 5 | this.index = -1; 6 | 7 | this.colorManager = new ColorManager(); 8 | }; 9 | 10 | RandomPieceGenerator.prototype.nextPiece = function(){ 11 | 12 | this.index++; 13 | if (this.index >= this.bag.length){ 14 | this.shuffleBag(); 15 | this.index = 0; 16 | } 17 | 18 | var color = this.colorManager.getColor(); 19 | 20 | return Piece.fromIndex(this.bag[this.index], color); 21 | 22 | }; 23 | 24 | RandomPieceGenerator.prototype.shuffleBag = function() { 25 | var currentIndex = this.bag.length 26 | , temporaryValue 27 | , randomIndex 28 | ; 29 | 30 | // While there remain elements to shuffle... 31 | while (0 !== currentIndex) { 32 | 33 | // Pick a remaining element... 34 | randomIndex = Math.floor(Math.random() * currentIndex); 35 | currentIndex -= 1; 36 | 37 | // And swap it with the current element. 38 | temporaryValue = this.bag[currentIndex]; 39 | this.bag[currentIndex] = this.bag[randomIndex]; 40 | this.bag[randomIndex] = temporaryValue; 41 | } 42 | }; -------------------------------------------------------------------------------- /colored_classic/custom/random_piece_generator.js: -------------------------------------------------------------------------------- 1 | function RandomPieceGenerator(){ 2 | Math.seed 3 | this.bag = [0, 1, 2, 3, 4, 5, 6]; 4 | this.shuffleBag(); 5 | this.index = -1; 6 | 7 | this.drawFunctions = new DrawFunctions(); 8 | }; 9 | 10 | RandomPieceGenerator.prototype.nextPiece = function(){ 11 | 12 | this.index++; 13 | if (this.index >= this.bag.length){ 14 | this.shuffleBag(); 15 | this.index = 0; 16 | } 17 | 18 | return Piece.fromIndex(this.bag[this.index], this.drawFunctions.getDrawFunction(this.bag[this.index])); 19 | 20 | }; 21 | 22 | RandomPieceGenerator.prototype.shuffleBag = function() { 23 | var currentIndex = this.bag.length 24 | , temporaryValue 25 | , randomIndex 26 | ; 27 | 28 | // While there remain elements to shuffle... 29 | while (0 !== currentIndex) { 30 | 31 | // Pick a remaining element... 32 | randomIndex = Math.floor(Math.random() * currentIndex); 33 | currentIndex -= 1; 34 | 35 | // And swap it with the current element. 36 | temporaryValue = this.bag[currentIndex]; 37 | this.bag[currentIndex] = this.bag[randomIndex]; 38 | this.bag[randomIndex] = temporaryValue; 39 | } 40 | }; -------------------------------------------------------------------------------- /core/js/updater.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Updater, controls time and speed. 3 | */ 4 | 5 | function Updater() { 6 | this.lastUpdateTime = Date.now(); 7 | this.deltaThreshold = 250; // MS before each update 8 | this.updateCallback = null; 9 | 10 | window.requestAnimFrame = (function() { 11 | // Polyfill 12 | return ( 13 | window.requestAnimationFrame || 14 | window.webkitRequestAnimationFrame || 15 | window.mozRequestAnimationFrame || 16 | window.oRequestAnimationFrame || 17 | window.msRequestAnimationFrame || 18 | function(callback) { 19 | window.setTimeout(callback, 1000 / 60); 20 | } 21 | ); 22 | })(); 23 | } 24 | 25 | Updater.prototype.onUpdate = function(callback) { 26 | this.updateCallback = callback; 27 | }; 28 | 29 | Updater.prototype.doUpdate = function(timestamp) { 30 | if (this.updateCallback != null) { 31 | this.updateCallback(); 32 | } 33 | 34 | this.lastUpdateTime = timestamp; 35 | }; 36 | 37 | Updater.prototype.checkUpdate = function(timestamp) { 38 | var self = this; 39 | var delta = timestamp - this.lastUpdateTime; 40 | 41 | if (delta > this.deltaThreshold) { 42 | this.doUpdate(timestamp); 43 | } 44 | 45 | window.requestAnimFrame(function() { 46 | self.checkUpdate(Date.now()); 47 | }); 48 | }; 49 | -------------------------------------------------------------------------------- /core/js/ai.js: -------------------------------------------------------------------------------- 1 | function AI(heightWeight, linesWeight, holesWeight, bumpinessWeight){ 2 | 3 | this.heightWeight = heightWeight; 4 | this.linesWeight = linesWeight; 5 | this.holesWeight = holesWeight; 6 | this.bumpinessWeight = bumpinessWeight; 7 | 8 | }; 9 | 10 | AI.prototype.best = function(grid, workingPieces, workingPieceIndex){ 11 | 12 | var best = null; 13 | var bestScore = null; 14 | var workingPiece = workingPieces[workingPieceIndex]; 15 | 16 | for(var rotation = 0; rotation < 4; rotation++){ 17 | var _piece = workingPiece.clone(); 18 | _piece.rotate(rotation); 19 | 20 | while(grid.canMoveLeft(_piece)){ 21 | _piece.column --; 22 | } 23 | 24 | while(grid.valid(_piece)){ 25 | var _pieceSet = _piece.clone(); 26 | while(grid.canMoveDown(_pieceSet)){ 27 | _pieceSet.row++; 28 | } 29 | 30 | var _grid = grid.clone(); 31 | _grid.addPiece(_pieceSet); 32 | 33 | var score = null; 34 | if (workingPieceIndex == (workingPieces.length - 1)) { 35 | score = -this.heightWeight * _grid.aggregateHeight() + this.linesWeight * _grid.lines() - this.holesWeight * _grid.holes() - this.bumpinessWeight * _grid.bumpiness(); 36 | }else{ 37 | score = this.best(_grid, workingPieces, workingPieceIndex + 1).score; 38 | } 39 | 40 | if (score > bestScore || bestScore == null){ 41 | bestScore = score; 42 | best = _piece.clone(); 43 | } 44 | 45 | _piece.column++; 46 | } 47 | } 48 | 49 | return {piece:best, score:bestScore}; 50 | }; -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Tetris Concats 3 | * 4 | */ 5 | 6 | var gulp = require('gulp'); 7 | var concat = require('gulp-concat'); 8 | 9 | gulp.task('ambient-tetris', function() { 10 | gulp 11 | .src([ 12 | './core/js/utils.js', 13 | './ambient/custom/color_manager.js', 14 | './core/js/grid.js', 15 | './ambient/custom/piece.js', 16 | './core/js/game_manager.js', 17 | './ambient/custom/random_piece_generator.js', 18 | './core/js/ai.js', 19 | './core/js/updater.js' 20 | ]) 21 | .pipe(concat('index.js')) 22 | .pipe(gulp.dest('./ambient/js/')); 23 | }); 24 | 25 | gulp.task('classic-tetris', function() { 26 | gulp 27 | .src([ 28 | './classic/custom/draw_functions.js', 29 | './core/js/grid.js', 30 | './classic/custom/piece.js', 31 | './classic/custom/game_manager.js', 32 | './classic/custom/random_piece_generator.js', 33 | './core/js/ai.js', 34 | './core/js/updater.js' 35 | ]) 36 | .pipe(concat('index.js')) 37 | .pipe(gulp.dest('./classic/js/')); 38 | }); 39 | 40 | gulp.task('colored-classic-tetris', function() { 41 | gulp 42 | .src([ 43 | './colored_classic/custom/draw_functions.js', 44 | './core/js/grid.js', 45 | './colored_classic/custom/piece.js', 46 | './colored_classic/custom/game_manager.js', 47 | './colored_classic/custom/random_piece_generator.js', 48 | './core/js/ai.js', 49 | './core/js/updater.js' 50 | ]) 51 | .pipe(concat('index.js')) 52 | .pipe(gulp.dest('./colored_classic/js/')); 53 | }); 54 | 55 | gulp.task('watch', function() { 56 | gulp.watch(['./ambient/custom/*', './core/js/*'], ['ambient-tetris']); 57 | gulp.watch(['./classic/custom/*', './core/js/*'], ['classic-tetris']); 58 | gulp.watch( 59 | ['./colored_classic/custom/*', './core/js/*'], 60 | ['colored-classic-tetris'] 61 | ); 62 | }); 63 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | html, 6 | body { 7 | margin: 0px; 8 | padding: 0px; 9 | } 10 | 11 | body { 12 | font-family: 'Open Sans', sans-serif; 13 | border: 20px solid #fff; 14 | background: #eee; 15 | padding-top: 80px; 16 | } 17 | 18 | section { 19 | width: 100%; 20 | } 21 | 22 | iframe { 23 | box-sizing: content-box; 24 | border: 20px solid #fff; 25 | height: 390px; 26 | width: 240px; 27 | } 28 | 29 | h1, 30 | h2 { 31 | font-weight: normal; 32 | margin-top: 0px; 33 | } 34 | 35 | h1 { 36 | margin-bottom: 50px; 37 | margin-top: 20px; 38 | font-size: 60px; 39 | } 40 | 41 | h2 { 42 | margin-bottom: 0px; 43 | } 44 | 45 | a { 46 | color: #335fff; 47 | text-decoration: none; 48 | } 49 | 50 | header { 51 | line-height: 28px; 52 | text-align: center; 53 | max-width: 620px; 54 | font-size: 18px; 55 | margin: auto; 56 | margin-bottom: 100px; 57 | padding-left: 20px; 58 | padding-right: 20px; 59 | } 60 | 61 | section { 62 | display: flex; 63 | max-width: 940px; 64 | margin: auto; 65 | margin-bottom: 100px; 66 | padding-left: 20px; 67 | padding-right: 20px; 68 | } 69 | 70 | .showcase { 71 | display: flex; 72 | flex-direction: row; 73 | justify-content: space-between; 74 | } 75 | 76 | .explaination { 77 | padding-left: 100px; 78 | display: flex; 79 | flex-direction: column; 80 | justify-content: center; 81 | } 82 | 83 | footer { 84 | padding-left: 50px; 85 | margin: auto; 86 | text-align: center; 87 | padding-right: 50px; 88 | padding-bottom: 50px; 89 | } 90 | 91 | /** 92 | * Responsive 93 | */ 94 | 95 | @media (max-width: 800px) { 96 | .explaination { 97 | padding-left: 50px; 98 | } 99 | } 100 | 101 | @media (max-width: 650px) { 102 | h1 { 103 | line-height: 66px; 104 | } 105 | 106 | header { 107 | margin-bottom: 50px; 108 | } 109 | 110 | header p { 111 | font-size: 16px; 112 | } 113 | 114 | .showcase { 115 | flex-direction: column; 116 | } 117 | 118 | .frame { 119 | margin: auto; 120 | margin-bottom: 50px; 121 | } 122 | 123 | .explaination { 124 | padding-left: 0px; 125 | } 126 | 127 | section:nth-child(odd) { 128 | background: rgba(255, 255, 255, 0.5); 129 | padding-bottom: 50px; 130 | margin-bottom: 50px; 131 | padding-top: 50px; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /core/js/utils.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | // http://stackoverflow.com/questions/17433015/change-the-hue-of-a-rgb-color-in-javascript 4 | // TODO: Clean up 5 | 6 | function changeHue(rgb, degree) { 7 | var hsl = rgbToHSL(rgb); 8 | hsl.h += degree; 9 | if (hsl.h > 360) { 10 | hsl.h -= 360; 11 | } 12 | else if (hsl.h < 0) { 13 | hsl.h += 360; 14 | } 15 | return hslToRGB(hsl); 16 | } 17 | 18 | // exepcts a string and returns an object 19 | function rgbToHSL(rgb) { 20 | // strip the leading # if it's there 21 | rgb = rgb.replace(/^\s*#|\s*$/g, ''); 22 | 23 | // convert 3 char codes --> 6, e.g. `E0F` --> `EE00FF` 24 | if(rgb.length == 3){ 25 | rgb = rgb.replace(/(.)/g, '$1$1'); 26 | } 27 | 28 | var r = parseInt(rgb.substr(0, 2), 16) / 255, 29 | g = parseInt(rgb.substr(2, 2), 16) / 255, 30 | b = parseInt(rgb.substr(4, 2), 16) / 255, 31 | cMax = Math.max(r, g, b), 32 | cMin = Math.min(r, g, b), 33 | delta = cMax - cMin, 34 | l = (cMax + cMin) / 2, 35 | h = 0, 36 | s = 0; 37 | 38 | if (delta == 0) { 39 | h = 0; 40 | } 41 | else if (cMax == r) { 42 | h = 60 * (((g - b) / delta) % 6); 43 | } 44 | else if (cMax == g) { 45 | h = 60 * (((b - r) / delta) + 2); 46 | } 47 | else { 48 | h = 60 * (((r - g) / delta) + 4); 49 | } 50 | 51 | if (delta == 0) { 52 | s = 0; 53 | } 54 | else { 55 | s = (delta/(1-Math.abs(2*l - 1))) 56 | } 57 | 58 | return { 59 | h: h, 60 | s: s, 61 | l: l 62 | } 63 | } 64 | 65 | // expects an object and returns a string 66 | function hslToRGB(hsl) { 67 | var h = hsl.h, 68 | s = hsl.s, 69 | l = hsl.l, 70 | c = (1 - Math.abs(2*l - 1)) * s, 71 | x = c * ( 1 - Math.abs((h / 60 ) % 2 - 1 )), 72 | m = l - c/ 2, 73 | r, g, b; 74 | 75 | if (h < 60) { 76 | r = c; 77 | g = x; 78 | b = 0; 79 | } 80 | else if (h < 120) { 81 | r = x; 82 | g = c; 83 | b = 0; 84 | } 85 | else if (h < 180) { 86 | r = 0; 87 | g = c; 88 | b = x; 89 | } 90 | else if (h < 240) { 91 | r = 0; 92 | g = x; 93 | b = c; 94 | } 95 | else if (h < 300) { 96 | r = x; 97 | g = 0; 98 | b = c; 99 | } 100 | else { 101 | r = c; 102 | g = 0; 103 | b = x; 104 | } 105 | 106 | r = normalize_rgb_value(r, m); 107 | g = normalize_rgb_value(g, m); 108 | b = normalize_rgb_value(b, m); 109 | 110 | return rgbToHex(r,g,b); 111 | } 112 | 113 | function normalize_rgb_value(color, m) { 114 | color = Math.floor((color + m) * 255); 115 | if (color < 0) { 116 | color = 0; 117 | } 118 | return color; 119 | } 120 | 121 | function rgbToHex(r, g, b) { 122 | return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); 123 | } -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Tetris Pieces 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |

Tetris Pieces

32 |

33 | A visual artificially intelligent tetris, built to be displayed on your wall. 34 |

35 | You can fork this, or check out the code on GitHub ... or look at the original (and smart!) source of the AI running behind the scenes, built by the incredible Yiyuan 36 |

37 | These pieces can be displayed via Electric Object (here). 38 |

39 |
40 | 41 |
42 |
43 | 44 |
45 | 46 |
47 | 48 |
49 | 50 |
51 | 52 |
53 |
54 | 55 | 58 | 59 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /core/js/piece.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Piece 3 | * - Represents a single piece on the board. 4 | */ 5 | 6 | // Object that represents a single piece & its properties. 7 | function Piece(cells, color){ 8 | this.cells = cells; 9 | this.dimension = this.cells.length; 10 | this.row = 0; 11 | this.column = 0; 12 | this.color = color; 13 | }; 14 | 15 | Piece.fromIndex = function(index, color){ 16 | 17 | var cells 18 | 19 | switch (index){ 20 | case 0:// O 21 | cells = [ 22 | [1, 1], 23 | [1, 1] 24 | ]; 25 | break; 26 | case 1: // J 27 | cells = [ 28 | [1, 0, 0], 29 | [1, 1, 1], 30 | [0, 0, 0] 31 | ]; 32 | break; 33 | case 2: // L 34 | cells = [ 35 | [0, 0, 1], 36 | [1, 1, 1], 37 | [0, 0, 0] 38 | ]; 39 | break; 40 | case 3: // Z 41 | cells = [ 42 | [1, 1, 0], 43 | [0, 1, 1], 44 | [0, 0, 0] 45 | ]; 46 | break; 47 | case 4: // S 48 | cells = [ 49 | [0, 1, 1], 50 | [1, 1, 0], 51 | [0, 0, 0] 52 | ]; 53 | break; 54 | case 5: // T 55 | cells = [ 56 | [0, 1, 0], 57 | [1, 1, 1], 58 | [0, 0, 0] 59 | ]; 60 | break; 61 | case 6: // I 62 | cells = [ 63 | [0, 0, 0, 0], 64 | [1, 1, 1, 1], 65 | [0, 0, 0, 0], 66 | [0, 0, 0, 0] 67 | ]; 68 | break; 69 | 70 | } 71 | 72 | var piece = new Piece(cells, color); 73 | 74 | piece.row = 0; 75 | piece.column = Math.floor((10 - piece.dimension) / 2); // Centralize 76 | return piece; 77 | }; 78 | 79 | Piece.prototype.clone = function(){ 80 | 81 | var _cells = new Array(this.dimension); 82 | for (var r = 0; r < this.dimension; r++) { 83 | _cells[r] = new Array(this.dimension); 84 | for(var c = 0; c < this.dimension; c++){ 85 | _cells[r][c] = this.cells[r][c]; 86 | } 87 | } 88 | 89 | var piece = new Piece(_cells, this.color); 90 | piece.row = this.row; 91 | piece.column = this.column; 92 | return piece; 93 | }; 94 | 95 | Piece.prototype.rotate = function(rotations){ 96 | for(var i = 0; i < rotations; i++) { 97 | var _cells = new Array(this.dimension); 98 | for (var r = 0; r < this.dimension; r++) { 99 | _cells[r] = new Array(this.dimension); 100 | } 101 | 102 | switch (this.dimension) { // Assumed square matrix 103 | case 2: 104 | _cells[0][0] = this.cells[1][0]; 105 | _cells[0][1] = this.cells[0][0]; 106 | _cells[1][0] = this.cells[1][1]; 107 | _cells[1][1] = this.cells[0][1]; 108 | break; 109 | case 3: 110 | _cells[0][0] = this.cells[2][0]; 111 | _cells[0][1] = this.cells[1][0]; 112 | _cells[0][2] = this.cells[0][0]; 113 | _cells[1][0] = this.cells[2][1]; 114 | _cells[1][1] = this.cells[1][1]; 115 | _cells[1][2] = this.cells[0][1]; 116 | _cells[2][0] = this.cells[2][2]; 117 | _cells[2][1] = this.cells[1][2]; 118 | _cells[2][2] = this.cells[0][2]; 119 | break; 120 | case 4: 121 | _cells[0][0] = this.cells[3][0]; 122 | _cells[0][1] = this.cells[2][0]; 123 | _cells[0][2] = this.cells[1][0]; 124 | _cells[0][3] = this.cells[0][0]; 125 | _cells[1][3] = this.cells[0][1]; 126 | _cells[2][3] = this.cells[0][2]; 127 | _cells[3][3] = this.cells[0][3]; 128 | _cells[3][2] = this.cells[1][3]; 129 | _cells[3][1] = this.cells[2][3]; 130 | _cells[3][0] = this.cells[3][3]; 131 | _cells[2][0] = this.cells[3][2]; 132 | _cells[1][0] = this.cells[3][1]; 133 | 134 | _cells[1][1] = this.cells[2][1]; 135 | _cells[1][2] = this.cells[1][1]; 136 | _cells[2][2] = this.cells[1][2]; 137 | _cells[2][1] = this.cells[2][2]; 138 | break; 139 | } 140 | 141 | this.cells = _cells; 142 | } 143 | }; 144 | -------------------------------------------------------------------------------- /ambient/custom/piece.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Piece 3 | * - Represents a single piece on the board. 4 | */ 5 | 6 | // Object that represents a single piece & its properties. 7 | function Piece(cells, color){ 8 | this.cells = cells; 9 | this.dimension = this.cells.length; 10 | this.row = 0; 11 | this.column = 0; 12 | this.color = color; 13 | }; 14 | 15 | Piece.fromIndex = function(index, color){ 16 | 17 | var cells 18 | 19 | switch (index){ 20 | case 0:// O 21 | cells = [ 22 | [1, 1], 23 | [1, 1] 24 | ]; 25 | break; 26 | case 1: // J 27 | cells = [ 28 | [1, 0, 0], 29 | [1, 1, 1], 30 | [0, 0, 0] 31 | ]; 32 | break; 33 | case 2: // L 34 | cells = [ 35 | [0, 0, 1], 36 | [1, 1, 1], 37 | [0, 0, 0] 38 | ]; 39 | break; 40 | case 3: // Z 41 | cells = [ 42 | [1, 1, 0], 43 | [0, 1, 1], 44 | [0, 0, 0] 45 | ]; 46 | break; 47 | case 4: // S 48 | cells = [ 49 | [0, 1, 1], 50 | [1, 1, 0], 51 | [0, 0, 0] 52 | ]; 53 | break; 54 | case 5: // T 55 | cells = [ 56 | [0, 1, 0], 57 | [1, 1, 1], 58 | [0, 0, 0] 59 | ]; 60 | break; 61 | case 6: // I 62 | cells = [ 63 | [0, 0, 0, 0], 64 | [1, 1, 1, 1], 65 | [0, 0, 0, 0], 66 | [0, 0, 0, 0] 67 | ]; 68 | break; 69 | 70 | } 71 | 72 | var piece = new Piece(cells, color); 73 | 74 | piece.row = 0; 75 | piece.column = Math.floor((10 - piece.dimension) / 2); // Centralize 76 | return piece; 77 | }; 78 | 79 | Piece.prototype.clone = function(){ 80 | 81 | var _cells = new Array(this.dimension); 82 | for (var r = 0; r < this.dimension; r++) { 83 | _cells[r] = new Array(this.dimension); 84 | for(var c = 0; c < this.dimension; c++){ 85 | _cells[r][c] = this.cells[r][c]; 86 | } 87 | } 88 | 89 | var piece = new Piece(_cells, this.color); 90 | piece.row = this.row; 91 | piece.column = this.column; 92 | return piece; 93 | }; 94 | 95 | Piece.prototype.rotate = function(rotations){ 96 | for(var i = 0; i < rotations; i++) { 97 | var _cells = new Array(this.dimension); 98 | for (var r = 0; r < this.dimension; r++) { 99 | _cells[r] = new Array(this.dimension); 100 | } 101 | 102 | switch (this.dimension) { // Assumed square matrix 103 | case 2: 104 | _cells[0][0] = this.cells[1][0]; 105 | _cells[0][1] = this.cells[0][0]; 106 | _cells[1][0] = this.cells[1][1]; 107 | _cells[1][1] = this.cells[0][1]; 108 | break; 109 | case 3: 110 | _cells[0][0] = this.cells[2][0]; 111 | _cells[0][1] = this.cells[1][0]; 112 | _cells[0][2] = this.cells[0][0]; 113 | _cells[1][0] = this.cells[2][1]; 114 | _cells[1][1] = this.cells[1][1]; 115 | _cells[1][2] = this.cells[0][1]; 116 | _cells[2][0] = this.cells[2][2]; 117 | _cells[2][1] = this.cells[1][2]; 118 | _cells[2][2] = this.cells[0][2]; 119 | break; 120 | case 4: 121 | _cells[0][0] = this.cells[3][0]; 122 | _cells[0][1] = this.cells[2][0]; 123 | _cells[0][2] = this.cells[1][0]; 124 | _cells[0][3] = this.cells[0][0]; 125 | _cells[1][3] = this.cells[0][1]; 126 | _cells[2][3] = this.cells[0][2]; 127 | _cells[3][3] = this.cells[0][3]; 128 | _cells[3][2] = this.cells[1][3]; 129 | _cells[3][1] = this.cells[2][3]; 130 | _cells[3][0] = this.cells[3][3]; 131 | _cells[2][0] = this.cells[3][2]; 132 | _cells[1][0] = this.cells[3][1]; 133 | 134 | _cells[1][1] = this.cells[2][1]; 135 | _cells[1][2] = this.cells[1][1]; 136 | _cells[2][2] = this.cells[1][2]; 137 | _cells[2][1] = this.cells[2][2]; 138 | break; 139 | } 140 | 141 | this.cells = _cells; 142 | } 143 | }; 144 | -------------------------------------------------------------------------------- /classic/custom/piece.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Piece 3 | * - Represents a single piece on the board. 4 | */ 5 | 6 | // Object that represents a single piece & its properties. 7 | function Piece(cells, color){ 8 | this.cells = cells; 9 | this.dimension = this.cells.length; 10 | this.row = 0; 11 | this.column = 0; 12 | this.color = color; 13 | }; 14 | 15 | Piece.fromIndex = function(index, color){ 16 | 17 | var cells 18 | 19 | switch (index){ 20 | case 0:// O 21 | cells = [ 22 | [1, 1], 23 | [1, 1] 24 | ]; 25 | break; 26 | case 1: // J 27 | cells = [ 28 | [1, 0, 0], 29 | [1, 1, 1], 30 | [0, 0, 0] 31 | ]; 32 | break; 33 | case 2: // L 34 | cells = [ 35 | [0, 0, 1], 36 | [1, 1, 1], 37 | [0, 0, 0] 38 | ]; 39 | break; 40 | case 3: // Z 41 | cells = [ 42 | [1, 1, 0], 43 | [0, 1, 1], 44 | [0, 0, 0] 45 | ]; 46 | break; 47 | case 4: // S 48 | cells = [ 49 | [0, 1, 1], 50 | [1, 1, 0], 51 | [0, 0, 0] 52 | ]; 53 | break; 54 | case 5: // T 55 | cells = [ 56 | [0, 1, 0], 57 | [1, 1, 1], 58 | [0, 0, 0] 59 | ]; 60 | break; 61 | case 6: // I 62 | cells = [ 63 | [0, 0, 0, 0], 64 | [2, 3, 4, 5], 65 | [0, 0, 0, 0], 66 | [0, 0, 0, 0] 67 | ]; 68 | break; 69 | 70 | } 71 | 72 | var piece = new Piece(cells, color); 73 | 74 | piece.row = 0; 75 | piece.column = Math.floor((10 - piece.dimension) / 2); // Centralize 76 | return piece; 77 | }; 78 | 79 | Piece.prototype.clone = function(){ 80 | 81 | var _cells = new Array(this.dimension); 82 | for (var r = 0; r < this.dimension; r++) { 83 | _cells[r] = new Array(this.dimension); 84 | for(var c = 0; c < this.dimension; c++){ 85 | _cells[r][c] = this.cells[r][c]; 86 | } 87 | } 88 | 89 | var piece = new Piece(_cells, this.color); 90 | piece.row = this.row; 91 | piece.column = this.column; 92 | return piece; 93 | }; 94 | 95 | Piece.prototype.rotate = function(rotations){ 96 | for(var i = 0; i < rotations; i++) { 97 | var _cells = new Array(this.dimension); 98 | for (var r = 0; r < this.dimension; r++) { 99 | _cells[r] = new Array(this.dimension); 100 | } 101 | 102 | switch (this.dimension) { // Assumed square matrix 103 | case 2: 104 | _cells[0][0] = this.cells[1][0]; 105 | _cells[0][1] = this.cells[0][0]; 106 | _cells[1][0] = this.cells[1][1]; 107 | _cells[1][1] = this.cells[0][1]; 108 | break; 109 | case 3: 110 | _cells[0][0] = this.cells[2][0]; 111 | _cells[0][1] = this.cells[1][0]; 112 | _cells[0][2] = this.cells[0][0]; 113 | _cells[1][0] = this.cells[2][1]; 114 | _cells[1][1] = this.cells[1][1]; 115 | _cells[1][2] = this.cells[0][1]; 116 | _cells[2][0] = this.cells[2][2]; 117 | _cells[2][1] = this.cells[1][2]; 118 | _cells[2][2] = this.cells[0][2]; 119 | break; 120 | case 4: 121 | _cells[0][0] = this.cells[3][0]; 122 | _cells[0][1] = this.cells[2][0]; 123 | _cells[0][2] = this.cells[1][0]; 124 | _cells[0][3] = this.cells[0][0]; 125 | _cells[1][3] = this.cells[0][1]; 126 | _cells[2][3] = this.cells[0][2]; 127 | _cells[3][3] = this.cells[0][3]; 128 | _cells[3][2] = this.cells[1][3]; 129 | _cells[3][1] = this.cells[2][3]; 130 | _cells[3][0] = this.cells[3][3]; 131 | _cells[2][0] = this.cells[3][2]; 132 | _cells[1][0] = this.cells[3][1]; 133 | 134 | _cells[1][1] = this.cells[2][1]; 135 | _cells[1][2] = this.cells[1][1]; 136 | _cells[2][2] = this.cells[1][2]; 137 | _cells[2][1] = this.cells[2][2]; 138 | break; 139 | } 140 | 141 | this.cells = _cells; 142 | } 143 | }; 144 | -------------------------------------------------------------------------------- /colored_classic/custom/piece.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Piece 3 | * - Represents a single piece on the board. 4 | */ 5 | 6 | // Object that represents a single piece & its properties. 7 | function Piece(cells, color){ 8 | this.cells = cells; 9 | this.dimension = this.cells.length; 10 | this.row = 0; 11 | this.column = 0; 12 | this.color = color; 13 | }; 14 | 15 | Piece.fromIndex = function(index, color){ 16 | 17 | var cells 18 | 19 | switch (index){ 20 | case 0:// O 21 | cells = [ 22 | [1, 1], 23 | [1, 1] 24 | ]; 25 | break; 26 | case 1: // J 27 | cells = [ 28 | [1, 0, 0], 29 | [1, 1, 1], 30 | [0, 0, 0] 31 | ]; 32 | break; 33 | case 2: // L 34 | cells = [ 35 | [0, 0, 1], 36 | [1, 1, 1], 37 | [0, 0, 0] 38 | ]; 39 | break; 40 | case 3: // Z 41 | cells = [ 42 | [1, 1, 0], 43 | [0, 1, 1], 44 | [0, 0, 0] 45 | ]; 46 | break; 47 | case 4: // S 48 | cells = [ 49 | [0, 1, 1], 50 | [1, 1, 0], 51 | [0, 0, 0] 52 | ]; 53 | break; 54 | case 5: // T 55 | cells = [ 56 | [0, 1, 0], 57 | [1, 1, 1], 58 | [0, 0, 0] 59 | ]; 60 | break; 61 | case 6: // I 62 | cells = [ 63 | [0, 0, 0, 0], 64 | [2, 3, 4, 5], 65 | [0, 0, 0, 0], 66 | [0, 0, 0, 0] 67 | ]; 68 | break; 69 | 70 | } 71 | 72 | var piece = new Piece(cells, color); 73 | 74 | piece.row = 0; 75 | piece.column = Math.floor((10 - piece.dimension) / 2); // Centralize 76 | return piece; 77 | }; 78 | 79 | Piece.prototype.clone = function(){ 80 | 81 | var _cells = new Array(this.dimension); 82 | for (var r = 0; r < this.dimension; r++) { 83 | _cells[r] = new Array(this.dimension); 84 | for(var c = 0; c < this.dimension; c++){ 85 | _cells[r][c] = this.cells[r][c]; 86 | } 87 | } 88 | 89 | var piece = new Piece(_cells, this.color); 90 | piece.row = this.row; 91 | piece.column = this.column; 92 | return piece; 93 | }; 94 | 95 | Piece.prototype.rotate = function(rotations){ 96 | for(var i = 0; i < rotations; i++) { 97 | var _cells = new Array(this.dimension); 98 | for (var r = 0; r < this.dimension; r++) { 99 | _cells[r] = new Array(this.dimension); 100 | } 101 | 102 | switch (this.dimension) { // Assumed square matrix 103 | case 2: 104 | _cells[0][0] = this.cells[1][0]; 105 | _cells[0][1] = this.cells[0][0]; 106 | _cells[1][0] = this.cells[1][1]; 107 | _cells[1][1] = this.cells[0][1]; 108 | break; 109 | case 3: 110 | _cells[0][0] = this.cells[2][0]; 111 | _cells[0][1] = this.cells[1][0]; 112 | _cells[0][2] = this.cells[0][0]; 113 | _cells[1][0] = this.cells[2][1]; 114 | _cells[1][1] = this.cells[1][1]; 115 | _cells[1][2] = this.cells[0][1]; 116 | _cells[2][0] = this.cells[2][2]; 117 | _cells[2][1] = this.cells[1][2]; 118 | _cells[2][2] = this.cells[0][2]; 119 | break; 120 | case 4: 121 | _cells[0][0] = this.cells[3][0]; 122 | _cells[0][1] = this.cells[2][0]; 123 | _cells[0][2] = this.cells[1][0]; 124 | _cells[0][3] = this.cells[0][0]; 125 | _cells[1][3] = this.cells[0][1]; 126 | _cells[2][3] = this.cells[0][2]; 127 | _cells[3][3] = this.cells[0][3]; 128 | _cells[3][2] = this.cells[1][3]; 129 | _cells[3][1] = this.cells[2][3]; 130 | _cells[3][0] = this.cells[3][3]; 131 | _cells[2][0] = this.cells[3][2]; 132 | _cells[1][0] = this.cells[3][1]; 133 | 134 | _cells[1][1] = this.cells[2][1]; 135 | _cells[1][2] = this.cells[1][1]; 136 | _cells[2][2] = this.cells[1][2]; 137 | _cells[2][1] = this.cells[2][2]; 138 | break; 139 | } 140 | 141 | this.cells = _cells; 142 | } 143 | }; 144 | -------------------------------------------------------------------------------- /classic/custom/game_manager.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Game manager, manages flow and updating of game. 3 | */ 4 | 5 | function GameManager(){ 6 | 7 | this.gridCanvas = document.getElementById('grid-canvas'); 8 | 9 | this.gravityUpdater = new Updater(); 10 | 11 | this.gravityUpdater.onUpdate(function(){ 12 | self.applyGravity(); 13 | self.actuate(); 14 | }); 15 | 16 | var self = this; 17 | this.setup(); 18 | this.startAI(); 19 | this.gravityUpdater.checkUpdate(Date.now()); 20 | }; 21 | 22 | GameManager.prototype.setup = function(){ 23 | 24 | this.baseColumns = 8; 25 | 26 | this.pieceWidth = window.innerWidth / this.baseColumns; 27 | this.pieceHeight = this.pieceWidth; 28 | 29 | this.displacementWidth = Math.floor(this.pieceWidth / 4); 30 | 31 | var canvasHeightPieces = Math.ceil(window.innerHeight / this.pieceHeight) + 2; 32 | 33 | this.gridCanvas.width = window.innerWidth; 34 | this.gridCanvas.height = canvasHeightPieces * this.pieceHeight; 35 | 36 | this.grid = new Grid(canvasHeightPieces, this.baseColumns); 37 | this.rpg = new RandomPieceGenerator(); 38 | this.ai = new AI(0.510066, 0.760666, 0.35663, 0.184483); 39 | 40 | this.workingPieces = [this.rpg.nextPiece(), this.rpg.nextPiece()]; 41 | this.workingPiece = this.workingPieces[0]; 42 | 43 | this.isOver = true; 44 | 45 | this.stopAI(); 46 | this.actuate(); 47 | }; 48 | 49 | GameManager.prototype.actuate = function(){ 50 | 51 | var _grid = this.grid.clone(); 52 | 53 | if (this.workingPiece != null) { 54 | _grid.addPiece(this.workingPiece); 55 | } 56 | 57 | var context = this.gridCanvas.getContext('2d'); 58 | context.save(); 59 | 60 | context.clearRect(0, 0, this.gridCanvas.width, this.gridCanvas.height); 61 | 62 | for(var r = 2; r < _grid.rows; r++){ 63 | 64 | for(var c = 0; c < _grid.columns; c++){ 65 | 66 | if (_grid.cells[r][c] != 0){ 67 | 68 | 69 | // console.log(_grid.cells[r], _grid.cells[r][c]); 70 | _grid.cells[r][c](context, c, r, this.pieceWidth, this.pieceHeight); 71 | 72 | } 73 | } 74 | } 75 | 76 | context.restore(); 77 | }; 78 | 79 | GameManager.prototype.startAI = function(){ 80 | this.aiActive = true; 81 | }; 82 | 83 | GameManager.prototype.stopAI = function(){ 84 | this.aiActive = false; 85 | }; 86 | 87 | GameManager.prototype.setWorkingPiece = function(){ 88 | 89 | this.grid.addPiece(this.workingPiece); 90 | this.grid.clearLines(); 91 | 92 | if (!this.grid.exceeded()){ 93 | 94 | for(var i = 0; i < this.workingPieces.length - 1; i++){ 95 | this.workingPieces[i] = this.workingPieces[i + 1]; 96 | } 97 | 98 | this.workingPieces[this.workingPieces.length - 1] = this.rpg.nextPiece(); 99 | this.workingPiece = this.workingPieces[0]; 100 | 101 | if (this.aiActive) { 102 | this.aiMove(); 103 | } 104 | 105 | // I piece 106 | if( this.workingPiece.cells.length > 3) { 107 | 108 | if( this.workingPiece.cells[0][2] !== 0 ) { 109 | this.workingPiece.cells[0][2] = 6; 110 | this.workingPiece.cells[1][2] = 7; 111 | this.workingPiece.cells[2][2] = 8; 112 | this.workingPiece.cells[3][2] = 9; 113 | } 114 | } 115 | } 116 | 117 | // TODO: NO WAYYYY 118 | else{ 119 | 120 | } 121 | }; 122 | 123 | GameManager.prototype.applyGravity = function(){ 124 | 125 | if (this.grid.canMoveDown(this.workingPiece)) { 126 | this.workingPiece.row++; 127 | }else{ 128 | this.setWorkingPiece(); 129 | } 130 | 131 | }; 132 | 133 | GameManager.prototype.drop = function(){ 134 | while(this.grid.canMoveDown(this.workingPiece)){ 135 | this.workingPiece.row++; 136 | } 137 | }; 138 | 139 | GameManager.prototype.moveLeft = function(){ 140 | if (this.grid.canMoveLeft(this.workingPiece)){ 141 | this.workingPiece.column--; 142 | } 143 | }; 144 | 145 | GameManager.prototype.moveRight = function(){ 146 | if (this.grid.canMoveRight(this.workingPiece)){ 147 | this.workingPiece.column++; 148 | } 149 | }; 150 | 151 | GameManager.prototype.rotate = function(){ 152 | var offset = this.grid.rotateOffset(this.workingPiece); 153 | if (offset != null){ 154 | this.workingPiece.rotate(1); 155 | this.workingPiece.row += offset.rowOffset; 156 | this.workingPiece.column += offset.columnOffset; 157 | } 158 | }; 159 | 160 | GameManager.prototype.aiMove = function(){ 161 | this.workingPiece = this.ai.best(this.grid, this.workingPieces, 0).piece; 162 | }; 163 | -------------------------------------------------------------------------------- /colored_classic/custom/game_manager.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Game manager, manages flow and updating of game. 3 | */ 4 | 5 | function GameManager(){ 6 | 7 | this.gridCanvas = document.getElementById('grid-canvas'); 8 | 9 | this.gravityUpdater = new Updater(); 10 | 11 | this.gravityUpdater.onUpdate(function(){ 12 | self.applyGravity(); 13 | self.actuate(); 14 | }); 15 | 16 | var self = this; 17 | this.setup(); 18 | this.startAI(); 19 | this.gravityUpdater.checkUpdate(Date.now()); 20 | }; 21 | 22 | GameManager.prototype.setup = function(){ 23 | 24 | this.baseColumns = 8; 25 | 26 | this.pieceWidth = window.innerWidth / this.baseColumns; 27 | this.pieceHeight = this.pieceWidth; 28 | 29 | this.displacementWidth = Math.floor(this.pieceWidth / 4); 30 | 31 | var canvasHeightPieces = Math.ceil(window.innerHeight / this.pieceHeight) + 2; 32 | 33 | this.gridCanvas.width = window.innerWidth; 34 | this.gridCanvas.height = canvasHeightPieces * this.pieceHeight; 35 | 36 | this.grid = new Grid(canvasHeightPieces, this.baseColumns); 37 | this.rpg = new RandomPieceGenerator(); 38 | this.ai = new AI(0.510066, 0.760666, 0.35663, 0.184483); 39 | 40 | this.workingPieces = [this.rpg.nextPiece(), this.rpg.nextPiece()]; 41 | this.workingPiece = this.workingPieces[0]; 42 | 43 | this.isOver = true; 44 | 45 | this.stopAI(); 46 | this.actuate(); 47 | }; 48 | 49 | GameManager.prototype.actuate = function(){ 50 | 51 | var _grid = this.grid.clone(); 52 | 53 | if (this.workingPiece != null) { 54 | _grid.addPiece(this.workingPiece); 55 | } 56 | 57 | var context = this.gridCanvas.getContext('2d'); 58 | context.save(); 59 | 60 | context.clearRect(0, 0, this.gridCanvas.width, this.gridCanvas.height); 61 | 62 | for(var r = 2; r < _grid.rows; r++){ 63 | 64 | for(var c = 0; c < _grid.columns; c++){ 65 | 66 | if (_grid.cells[r][c] != 0){ 67 | 68 | 69 | // console.log(_grid.cells[r], _grid.cells[r][c]); 70 | _grid.cells[r][c](context, c, r, this.pieceWidth, this.pieceHeight); 71 | 72 | } 73 | } 74 | } 75 | 76 | context.restore(); 77 | }; 78 | 79 | GameManager.prototype.startAI = function(){ 80 | this.aiActive = true; 81 | }; 82 | 83 | GameManager.prototype.stopAI = function(){ 84 | this.aiActive = false; 85 | }; 86 | 87 | GameManager.prototype.setWorkingPiece = function(){ 88 | 89 | this.grid.addPiece(this.workingPiece); 90 | this.grid.clearLines(); 91 | 92 | if (!this.grid.exceeded()){ 93 | 94 | for(var i = 0; i < this.workingPieces.length - 1; i++){ 95 | this.workingPieces[i] = this.workingPieces[i + 1]; 96 | } 97 | 98 | this.workingPieces[this.workingPieces.length - 1] = this.rpg.nextPiece(); 99 | this.workingPiece = this.workingPieces[0]; 100 | 101 | if (this.aiActive) { 102 | this.aiMove(); 103 | } 104 | 105 | // I piece 106 | if( this.workingPiece.cells.length > 3) { 107 | 108 | if( this.workingPiece.cells[0][2] !== 0 ) { 109 | this.workingPiece.cells[0][2] = 6; 110 | this.workingPiece.cells[1][2] = 7; 111 | this.workingPiece.cells[2][2] = 8; 112 | this.workingPiece.cells[3][2] = 9; 113 | } 114 | } 115 | } 116 | 117 | // TODO: NO WAYYYY 118 | else{ 119 | 120 | } 121 | }; 122 | 123 | GameManager.prototype.applyGravity = function(){ 124 | 125 | if (this.grid.canMoveDown(this.workingPiece)) { 126 | this.workingPiece.row++; 127 | }else{ 128 | this.setWorkingPiece(); 129 | } 130 | 131 | }; 132 | 133 | GameManager.prototype.drop = function(){ 134 | while(this.grid.canMoveDown(this.workingPiece)){ 135 | this.workingPiece.row++; 136 | } 137 | }; 138 | 139 | GameManager.prototype.moveLeft = function(){ 140 | if (this.grid.canMoveLeft(this.workingPiece)){ 141 | this.workingPiece.column--; 142 | } 143 | }; 144 | 145 | GameManager.prototype.moveRight = function(){ 146 | if (this.grid.canMoveRight(this.workingPiece)){ 147 | this.workingPiece.column++; 148 | } 149 | }; 150 | 151 | GameManager.prototype.rotate = function(){ 152 | var offset = this.grid.rotateOffset(this.workingPiece); 153 | if (offset != null){ 154 | this.workingPiece.rotate(1); 155 | this.workingPiece.row += offset.rowOffset; 156 | this.workingPiece.column += offset.columnOffset; 157 | } 158 | }; 159 | 160 | GameManager.prototype.aiMove = function(){ 161 | this.workingPiece = this.ai.best(this.grid, this.workingPieces, 0).piece; 162 | }; 163 | -------------------------------------------------------------------------------- /core/js/game_manager.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Game manager, manages flow and updating of game. 3 | */ 4 | 5 | function GameManager(){ 6 | 7 | this.gridCanvas = document.getElementById('grid-canvas'); 8 | 9 | this.gravityUpdater = new Updater(); 10 | 11 | this.gravityUpdater.onUpdate(function(){ 12 | self.applyGravity(); 13 | self.actuate(); 14 | }); 15 | 16 | var self = this; 17 | this.setup(); 18 | this.startAI(); 19 | this.gravityUpdater.checkUpdate(Date.now()); 20 | }; 21 | 22 | GameManager.prototype.setup = function(){ 23 | 24 | this.baseColumns = 8; 25 | 26 | this.pieceWidth = window.innerWidth / this.baseColumns; 27 | this.pieceHeight = this.pieceWidth; 28 | 29 | this.displacementWidth = Math.floor(this.pieceWidth / 4); 30 | this.strokeThickness = 20; 31 | 32 | var canvasHeightPieces = Math.ceil(window.innerHeight / this.pieceHeight) + 2; 33 | 34 | this.gridCanvas.width = window.innerWidth; 35 | this.gridCanvas.height = canvasHeightPieces * this.pieceHeight; 36 | 37 | this.grid = new Grid(canvasHeightPieces, this.baseColumns); 38 | this.rpg = new RandomPieceGenerator(); 39 | this.ai = new AI(0.510066, 0.760666, 0.35663, 0.184483); 40 | 41 | this.workingPieces = [this.rpg.nextPiece(), this.rpg.nextPiece()]; 42 | this.workingPiece = this.workingPieces[0]; 43 | 44 | this.isOver = true; 45 | 46 | this.stopAI(); 47 | this.actuate(); 48 | }; 49 | 50 | GameManager.prototype.actuate = function(){ 51 | 52 | var _grid = this.grid.clone(); 53 | 54 | if (this.workingPiece != null) { 55 | _grid.addPiece(this.workingPiece); 56 | } 57 | 58 | var context = this.gridCanvas.getContext('2d'); 59 | context.save(); 60 | 61 | context.clearRect(0, 0, this.gridCanvas.width, this.gridCanvas.height); 62 | 63 | for(var r = 2; r < _grid.rows; r++){ 64 | 65 | for(var c = 0; c < _grid.columns; c++){ 66 | 67 | if (_grid.cells[r][c] != 0){ 68 | 69 | context.fillStyle = _grid.cells[r][c]; 70 | context.strokeStyle = _grid.cells[r][c]; 71 | context.fillRect(this.pieceWidth * c, this.pieceHeight * r, this.pieceWidth, this.pieceHeight); 72 | 73 | // Border? 74 | context.fillStyle = "rgba(255, 255, 255, 0.3)"; 75 | context.fillRect(this.pieceWidth * c + this.displacementWidth, this.pieceHeight * r + this.displacementWidth, this.pieceWidth / 2, this.strokeThickness); 76 | context.fillRect(this.pieceWidth * c + this.displacementWidth, this.pieceHeight * r + this.displacementWidth + this.strokeThickness, this.strokeThickness, this.pieceWidth / 2 - this.strokeThickness ); 77 | } 78 | } 79 | } 80 | 81 | context.restore(); 82 | }; 83 | 84 | GameManager.prototype.startAI = function(){ 85 | this.aiActive = true; 86 | }; 87 | 88 | GameManager.prototype.stopAI = function(){ 89 | this.aiActive = false; 90 | }; 91 | 92 | GameManager.prototype.setWorkingPiece = function(){ 93 | 94 | this.grid.addPiece(this.workingPiece); 95 | this.grid.clearLines(); 96 | 97 | if (!this.grid.exceeded()){ 98 | 99 | for(var i = 0; i < this.workingPieces.length - 1; i++){ 100 | this.workingPieces[i] = this.workingPieces[i + 1]; 101 | } 102 | 103 | this.workingPieces[this.workingPieces.length - 1] = this.rpg.nextPiece(); 104 | this.workingPiece = this.workingPieces[0]; 105 | 106 | if (this.aiActive) { 107 | this.aiMove(); 108 | } 109 | } 110 | 111 | // TODO: NO WAYYYY 112 | else{ 113 | 114 | } 115 | }; 116 | 117 | GameManager.prototype.applyGravity = function(){ 118 | 119 | if (this.grid.canMoveDown(this.workingPiece)) { 120 | this.workingPiece.row++; 121 | }else{ 122 | this.setWorkingPiece(); 123 | } 124 | 125 | }; 126 | 127 | GameManager.prototype.drop = function(){ 128 | while(this.grid.canMoveDown(this.workingPiece)){ 129 | this.workingPiece.row++; 130 | } 131 | }; 132 | 133 | GameManager.prototype.moveLeft = function(){ 134 | if (this.grid.canMoveLeft(this.workingPiece)){ 135 | this.workingPiece.column--; 136 | } 137 | }; 138 | 139 | GameManager.prototype.moveRight = function(){ 140 | if (this.grid.canMoveRight(this.workingPiece)){ 141 | this.workingPiece.column++; 142 | } 143 | }; 144 | 145 | GameManager.prototype.rotate = function(){ 146 | var offset = this.grid.rotateOffset(this.workingPiece); 147 | if (offset != null){ 148 | this.workingPiece.rotate(1); 149 | this.workingPiece.row += offset.rowOffset; 150 | this.workingPiece.column += offset.columnOffset; 151 | } 152 | }; 153 | 154 | GameManager.prototype.aiMove = function(){ 155 | this.workingPiece = this.ai.best(this.grid, this.workingPieces, 0).piece; 156 | }; 157 | -------------------------------------------------------------------------------- /core/js/grid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Grid 3 | * - Manages the state of the grid 4 | */ 5 | 6 | // Init 7 | function Grid(rows, columns){ 8 | 9 | this.rows = rows; 10 | this.columns = columns; 11 | this.cells = new Array(rows); 12 | 13 | // For each row! 14 | // Has a column 15 | // Which has X cells in it. 16 | for (var r = 0; r < this.rows; r++) { 17 | 18 | this.cells[r] = new Array(this.columns); 19 | for(var c = 0; c < this.columns; c++){ 20 | this.cells[r][c] = 0; 21 | } 22 | } 23 | 24 | }; 25 | 26 | // Methods 27 | Grid.prototype.clone = function(){ 28 | var _grid = new Grid(this.rows, this.columns); 29 | for (var r = 0; r < this.rows; r++) { 30 | for(var c = 0; c < this.columns; c++){ 31 | _grid.cells[r][c] = this.cells[r][c]; 32 | } 33 | } 34 | return _grid; 35 | }; 36 | 37 | // Clear spaces in the grid, including when the blocks "fall" 38 | Grid.prototype.clearLines = function(){ 39 | 40 | var distance = 0; 41 | var row = new Array(this.columns); 42 | 43 | for(var r = this.rows - 1; r >= 0; r--){ 44 | 45 | // Clear full line 46 | if (this.isLine(r)){ 47 | 48 | distance++; 49 | for(var c = 0; c < this.columns; c++){ 50 | this.cells[r][c] = 0; 51 | } 52 | 53 | // Clear moved spaces 54 | } else if (distance > 0) { 55 | 56 | for(var c = 0; c < this.columns; c++){ 57 | this.cells[r + distance][c] = this.cells[r][c]; 58 | this.cells[r][c] = 0; 59 | } 60 | } 61 | } 62 | }; 63 | 64 | // If every item in the row has an item! 65 | Grid.prototype.isLine = function(row){ 66 | for(var c = 0; c < this.columns; c++){ 67 | if (this.cells[row][c] == 0){ 68 | return false; 69 | } 70 | } 71 | return true; 72 | }; 73 | 74 | Grid.prototype.isEmptyRow = function(row){ 75 | for(var c = 0; c < this.columns; c++){ 76 | 77 | // TH: != 0 rather than == 1 78 | if (this.cells[row][c] != 0){ 79 | return false; 80 | } 81 | } 82 | return true; 83 | }; 84 | 85 | Grid.prototype.exceeded = function(){ 86 | return !this.isEmptyRow(0) || !this.isEmptyRow(1); 87 | }; 88 | 89 | Grid.prototype.height = function(){ 90 | var r = 0; 91 | for(; r < this.rows && this.isEmptyRow(r); r++); 92 | return this.rows - r; 93 | }; 94 | 95 | Grid.prototype.lines = function(){ 96 | var count = 0; 97 | for(var r = 0; r < this.rows; r++){ 98 | if (this.isLine(r)){ 99 | count++; 100 | } 101 | } 102 | return count; 103 | }; 104 | 105 | Grid.prototype.holes = function(){ 106 | var count = 0; 107 | 108 | for(var c = 0; c < this.columns; c++){ 109 | var block = false; 110 | for(var r = 0; r < this.rows; r++){ 111 | 112 | // TH: != 0 rather than == 1 113 | if (this.cells[r][c] != 0) { 114 | block = true; 115 | }else if (this.cells[r][c] == 0 && block){ 116 | count++; 117 | } 118 | } 119 | } 120 | return count; 121 | }; 122 | 123 | Grid.prototype.blockades = function(){ 124 | var count = 0; 125 | 126 | for(var c = 0; c < this.columns; c++){ 127 | var hole = false; 128 | for(var r = this.rows - 1; r >= 0; r--){ 129 | if (this.cells[r][c] == 0){ 130 | hole = true; 131 | 132 | // TH: != 0 rather than == 1 133 | }else if (this.cells[r][c] != 0 && hole){ 134 | count++; 135 | } 136 | } 137 | } 138 | return count; 139 | } 140 | 141 | Grid.prototype.aggregateHeight = function(){ 142 | var total = 0; 143 | 144 | for(var c = 0; c < this.columns; c++){ 145 | total += this.columnHeight(c); 146 | } 147 | return total; 148 | }; 149 | 150 | Grid.prototype.bumpiness = function(){ 151 | var total = 0; 152 | for(var c = 0; c < this.columns - 1; c++){ 153 | total += Math.abs(this.columnHeight(c) - this.columnHeight(c+ 1)); 154 | } 155 | return total; 156 | } 157 | 158 | Grid.prototype.columnHeight = function(column){ 159 | var r = 0; 160 | 161 | for(; r < this.rows && this.cells[r][column] == 0; r++); 162 | return this.rows - r; 163 | }; 164 | 165 | // Piece 166 | Grid.prototype.addPiece = function(piece) { 167 | 168 | for(var r = 0; r < piece.cells.length; r++) { 169 | for (var c = 0; c < piece.cells[r].length; c++) { 170 | 171 | var _r = piece.row + r; 172 | var _c = piece.column + c; 173 | 174 | // TH: != 0 rather than == 1 175 | if (piece.cells[r][c] != 0 && _r >= 0){ 176 | 177 | // TH: Updates color, rather than 1 178 | if (piece.cells[r][c] > 1) { 179 | var num = piece.cells[r][c] - 2; 180 | this.cells[_r][_c] = piece.color[num]; 181 | } else { 182 | this.cells[_r][_c] = piece.color; 183 | } 184 | } 185 | 186 | } 187 | } 188 | }; 189 | 190 | Grid.prototype.valid = function(piece){ 191 | 192 | for(var r = 0; r < piece.cells.length; r++){ 193 | for(var c = 0; c < piece.cells[r].length; c++){ 194 | var _r = piece.row + r; 195 | var _c = piece.column + c; 196 | 197 | // TH: != 0 rather than == 1 198 | if (piece.cells[r][c] != 0){ 199 | if (!(_c < this.columns && _r < this.rows && this.cells[_r][_c] == 0)){ 200 | return false; 201 | } 202 | } 203 | } 204 | } 205 | return true; 206 | }; 207 | 208 | Grid.prototype.canMoveDown = function(piece){ 209 | for(var r = 0; r < piece.cells.length; r++){ 210 | for(var c = 0; c < piece.cells[r].length; c++){ 211 | var _r = piece.row + r + 1; 212 | var _c = piece.column + c; 213 | 214 | // TH: != 0 rather than == 1 215 | if (piece.cells[r][c] != 0 && _r >= 0){ 216 | 217 | if (!(_r < this.rows && this.cells[_r][_c] == 0)){ 218 | return false; 219 | } 220 | } 221 | } 222 | } 223 | return true; 224 | }; 225 | 226 | Grid.prototype.canMoveLeft = function(piece){ 227 | for(var r = 0; r < piece.cells.length; r++){ 228 | for(var c = 0; c < piece.cells[r].length; c++){ 229 | var _r = piece.row + r; 230 | var _c = piece.column + c - 1; 231 | 232 | // TH: != 0 rather than == 1 233 | if (piece.cells[r][c] != 0){ 234 | if (!(_c >= 0 && this.cells[_r][_c] == 0)){ 235 | return false; 236 | } 237 | } 238 | } 239 | } 240 | return true; 241 | }; 242 | 243 | Grid.prototype.canMoveRight = function(piece){ 244 | for(var r = 0; r < piece.cells.length; r++){ 245 | for(var c = 0; c < piece.cells[r].length; c++){ 246 | var _r = piece.row + r; 247 | var _c = piece.column + c + 1; 248 | 249 | // TH: != 0 rather than == 1 250 | if (piece.cells[r][c] != 0){ 251 | if (!(_c >= 0 && this.cells[_r][_c] == 0)){ 252 | return false; 253 | } 254 | } 255 | } 256 | } 257 | return true; 258 | }; 259 | 260 | Grid.prototype.rotateOffset = function(piece){ 261 | 262 | console.log("rotate?"); 263 | 264 | var _piece = piece.clone(); 265 | _piece.rotate(1); 266 | if (this.valid(_piece)) { 267 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 268 | } 269 | 270 | // Kicking 271 | var initialRow = _piece.row; 272 | var initialCol = _piece.column; 273 | 274 | for (var i = 0; i < _piece.dimension - 1; i++) { 275 | _piece.column = initialCol + i; 276 | if (this.valid(_piece)) { 277 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 278 | } 279 | 280 | for (var j = 0; j < _piece.dimension - 1; j++) { 281 | _piece.row = initialRow - j; 282 | if (this.valid(_piece)) { 283 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 284 | } 285 | } 286 | _piece.row = initialRow; 287 | } 288 | _piece.column = initialCol; 289 | 290 | for (var i = 0; i < _piece.dimension - 1; i++) { 291 | _piece.column = initialCol - i; 292 | if (this.valid(_piece)) { 293 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 294 | } 295 | 296 | for (var j = 0; j < _piece.dimension - 1; j++) { 297 | _piece.row = initialRow - j; 298 | if (this.valid(_piece)) { 299 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 300 | } 301 | } 302 | _piece.row = initialRow; 303 | } 304 | _piece.column = initialCol; 305 | 306 | return null; 307 | }; 308 | -------------------------------------------------------------------------------- /classic/custom/draw_functions.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | function square(context, x, y, width, height) { 4 | 5 | var unitWidth = 0.125 * width; 6 | 7 | // Border 8 | context.fillStyle = "#000"; 9 | context.fillRect(width * x, height * y, width, height); 10 | 11 | context.fillStyle = "#C6CFA4"; 12 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 13 | 14 | context.fillStyle = "#000"; 15 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, width - unitWidth * 4, height - unitWidth * 4); 16 | 17 | } 18 | 19 | function jay(context, x, y, width, height) { 20 | 21 | var unitWidth = 0.125 * width; 22 | 23 | // Border 24 | context.fillStyle = "#000"; 25 | context.fillRect(width * x, height * y, width, height); 26 | 27 | context.fillStyle = "#92BE7C"; 28 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 29 | 30 | context.fillStyle = "#000"; 31 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, width - unitWidth * 4, height - unitWidth * 4); 32 | 33 | context.fillStyle = "#C6CFA4"; 34 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 3, width - unitWidth * 6, height - unitWidth * 6); 35 | } 36 | 37 | function ell(context, x, y, width, height) { 38 | 39 | var unitWidth = 0.125 * width; 40 | 41 | context.fillStyle = "#000"; 42 | context.fillRect(width * x, height * y, width, height); 43 | 44 | context.fillStyle = "#3C6A4E"; 45 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 46 | 47 | } 48 | 49 | function zee(context, x, y, width, height) { 50 | 51 | var unitWidth = 0.125 * width; 52 | 53 | context.fillStyle = "#000"; 54 | context.fillRect(width * x, height * y, width, height); 55 | 56 | context.fillStyle = "#92BE7C"; 57 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 58 | 59 | context.fillStyle = "#000"; 60 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 3, width - unitWidth * 6, height - unitWidth * 6); 61 | 62 | } 63 | 64 | function ess(context, x, y, width, height) { 65 | 66 | var unitWidth = 0.125 * width; 67 | 68 | context.fillStyle = "#000"; 69 | context.fillRect(width * x, height * y, width, height); 70 | 71 | context.fillStyle = "#3C6A4E"; 72 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 73 | 74 | context.fillStyle = "#000"; 75 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, width - unitWidth * 4, height - unitWidth * 4); 76 | 77 | context.fillStyle = "#C6CFA4"; 78 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 3, width - unitWidth * 6, height - unitWidth * 6); 79 | } 80 | 81 | function tee(context, x, y, width, height) { 82 | 83 | var unitWidth = 0.125 * width; 84 | 85 | context.fillStyle = "#000"; 86 | context.fillRect(width * x, height * y, width, height); 87 | 88 | context.fillStyle = "#92BE7C"; 89 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 90 | 91 | context.fillStyle = "#C6CFA4"; 92 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, unitWidth, height - unitWidth * 4); 93 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, unitWidth * 4, unitWidth); 94 | 95 | context.fillStyle = "#000"; 96 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 5, unitWidth * 4, unitWidth); 97 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 3, unitWidth, unitWidth * 3); 98 | 99 | } 100 | 101 | var eyes = [ 102 | //h1 103 | function(context, x, y, width, height) { 104 | 105 | var unitWidth = 0.125 * width; 106 | context.fillStyle = "#000"; 107 | context.fillRect(width * x, height * y, width, height); 108 | 109 | context.fillStyle = "#92BE7C"; 110 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth, height - unitWidth * 2); 111 | 112 | // Dots 113 | context.fillStyle = "#3C6A4E"; 114 | 115 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 1, unitWidth, unitWidth); 116 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 1, unitWidth, unitWidth); 117 | 118 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 3, unitWidth, unitWidth); 119 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 3, unitWidth, unitWidth); 120 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 3, unitWidth, unitWidth); 121 | 122 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 5, unitWidth, unitWidth); 123 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 5, unitWidth, unitWidth); 124 | 125 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 6, unitWidth, unitWidth); 126 | 127 | 128 | }, 129 | function(context, x, y, width, height) { 130 | 131 | var unitWidth = 0.125 * width; 132 | 133 | context.fillStyle = "#000"; 134 | context.fillRect(width * x, height * y, width, height); 135 | 136 | context.fillStyle = "#92BE7C"; 137 | context.fillRect(width * x, height * y + unitWidth, width, height - unitWidth * 2); 138 | 139 | // Dots 140 | context.fillStyle = "#3C6A4E"; 141 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 1, unitWidth, unitWidth); 142 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 1, unitWidth, unitWidth); 143 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 1, unitWidth, unitWidth); 144 | 145 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 146 | 147 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 3, unitWidth, unitWidth); 148 | 149 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 4, unitWidth, unitWidth); 150 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 4, unitWidth, unitWidth); 151 | 152 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 5, unitWidth, unitWidth); 153 | context.fillRect(width * x + unitWidth * 7, height * y + unitWidth * 5, unitWidth, unitWidth); 154 | 155 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 6, unitWidth, unitWidth); 156 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 6, unitWidth, unitWidth); 157 | 158 | 159 | }, 160 | function(context, x, y, width, height) { 161 | 162 | var unitWidth = 0.125 * width; 163 | 164 | context.fillStyle = "#000"; 165 | context.fillRect(width * x, height * y, width, height); 166 | 167 | context.fillStyle = "#92BE7C"; 168 | context.fillRect(width * x, height * y + unitWidth, width, height - unitWidth * 2); 169 | 170 | // Dots 171 | context.fillStyle = "#3C6A4E"; 172 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 1, unitWidth, unitWidth); 173 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 1, unitWidth, unitWidth); 174 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 1, unitWidth, unitWidth); 175 | 176 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 177 | 178 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 3, unitWidth, unitWidth); 179 | 180 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 4, unitWidth, unitWidth); 181 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 4, unitWidth, unitWidth); 182 | 183 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 5, unitWidth, unitWidth); 184 | context.fillRect(width * x + unitWidth * 7, height * y + unitWidth * 5, unitWidth, unitWidth); 185 | 186 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 6, unitWidth, unitWidth); 187 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 6, unitWidth, unitWidth); 188 | 189 | }, 190 | function(context, x, y, width, height) { 191 | 192 | var unitWidth = 0.125 * width; 193 | 194 | context.fillStyle = "#000"; 195 | context.fillRect(width * x, height * y, width, height); 196 | 197 | context.fillStyle = "#92BE7C"; 198 | context.fillRect(width * x, height * y + unitWidth, width - unitWidth, height - unitWidth * 2); 199 | 200 | // Dots 201 | context.fillStyle = "#3C6A4E"; 202 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 1, unitWidth, unitWidth); 203 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 1, unitWidth, unitWidth); 204 | 205 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, unitWidth, unitWidth); 206 | 207 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 3, unitWidth, unitWidth); 208 | 209 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 4, unitWidth, unitWidth); 210 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 4, unitWidth, unitWidth); 211 | 212 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 5, unitWidth, unitWidth); 213 | 214 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 6, unitWidth, unitWidth); 215 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 6, unitWidth, unitWidth); 216 | }, 217 | 218 | // v1 219 | function(context, x, y, width, height) { 220 | 221 | var unitWidth = 0.125 * width; 222 | context.fillStyle = "#000"; 223 | context.fillRect(width * x, height * y, width, height); 224 | 225 | context.fillStyle = "#92BE7C"; 226 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth); 227 | 228 | // Dots 229 | context.fillStyle = "#3C6A4E"; 230 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth, unitWidth, unitWidth); 231 | 232 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, unitWidth, unitWidth); 233 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 234 | 235 | context.fillRect(width * x + unitWidth, height * y + unitWidth * 4, unitWidth, unitWidth); 236 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 4, unitWidth, unitWidth); 237 | 238 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 5, unitWidth, unitWidth); 239 | 240 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 6, unitWidth, unitWidth); 241 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 6, unitWidth, unitWidth); 242 | 243 | }, 244 | function(context, x, y, width, height) { 245 | 246 | var unitWidth = 0.125 * width; 247 | 248 | context.fillStyle = "#000"; 249 | context.fillRect(width * x, height * y, width, height); 250 | 251 | context.fillStyle = "#92BE7C"; 252 | context.fillRect(width * x + unitWidth, height * y, width - unitWidth * 2, height); 253 | 254 | // Dots 255 | context.fillStyle = "#3C6A4E"; 256 | 257 | context.fillRect(width * x + unitWidth * 3, height * y, unitWidth, unitWidth); 258 | context.fillRect(width * x + unitWidth * 6, height * y, unitWidth, unitWidth); 259 | 260 | context.fillRect(width * x + unitWidth, height * y + unitWidth * 1, unitWidth, unitWidth); 261 | 262 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 2, unitWidth, unitWidth); 263 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 264 | 265 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 3, unitWidth, unitWidth); 266 | 267 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 4, unitWidth, unitWidth); 268 | 269 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 5, unitWidth, unitWidth); 270 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 5, unitWidth, unitWidth); 271 | 272 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 6, unitWidth, unitWidth); 273 | 274 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 7, unitWidth, unitWidth); 275 | 276 | }, 277 | function(context, x, y, width, height) { 278 | 279 | var unitWidth = 0.125 * width; 280 | 281 | context.fillStyle = "#000"; 282 | context.fillRect(width * x, height * y, width, height); 283 | 284 | context.fillStyle = "#92BE7C"; 285 | context.fillRect(width * x + unitWidth, height * y, width - unitWidth * 2, height); 286 | 287 | // Dots 288 | context.fillStyle = "#3C6A4E"; 289 | 290 | context.fillRect(width * x + unitWidth * 3, height * y, unitWidth, unitWidth); 291 | context.fillRect(width * x + unitWidth * 6, height * y, unitWidth, unitWidth); 292 | 293 | context.fillRect(width * x + unitWidth, height * y + unitWidth * 1, unitWidth, unitWidth); 294 | 295 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 2, unitWidth, unitWidth); 296 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 297 | 298 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 3, unitWidth, unitWidth); 299 | 300 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 4, unitWidth, unitWidth); 301 | 302 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 5, unitWidth, unitWidth); 303 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 5, unitWidth, unitWidth); 304 | 305 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 6, unitWidth, unitWidth); 306 | 307 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 7, unitWidth, unitWidth); 308 | }, 309 | function(context, x, y, width, height) { 310 | 311 | var unitWidth = 0.125 * width; 312 | 313 | context.fillStyle = "#000"; 314 | context.fillRect(width * x, height * y, width, height); 315 | 316 | context.fillStyle = "#92BE7C"; 317 | context.fillRect(width * x + unitWidth, height * y, width - unitWidth * 2, height - unitWidth); 318 | 319 | // Dots 320 | context.fillStyle = "#3C6A4E"; 321 | 322 | context.fillRect(width * x + unitWidth * 6, height * y, unitWidth, unitWidth); 323 | 324 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 1, unitWidth, unitWidth); 325 | 326 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 2, unitWidth, unitWidth); 327 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 2, unitWidth, unitWidth); 328 | 329 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 3, unitWidth, unitWidth); 330 | 331 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 4, unitWidth, unitWidth); 332 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 4, unitWidth, unitWidth); 333 | 334 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 5, unitWidth, unitWidth); 335 | 336 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 6, unitWidth, unitWidth); 337 | } 338 | ] 339 | 340 | var drawFunctions = [ 341 | 342 | square, 343 | 344 | jay, 345 | 346 | ell, 347 | 348 | zee, 349 | 350 | ess, 351 | 352 | tee, 353 | 354 | eyes 355 | 356 | ] 357 | 358 | function DrawFunctions(){}; 359 | 360 | DrawFunctions.prototype.getDrawFunction = function(index){ 361 | 362 | if( drawFunctions[index]) { 363 | return drawFunctions[index]; 364 | } else { 365 | return drawFunctions[5]; 366 | } 367 | } -------------------------------------------------------------------------------- /colored_classic/custom/draw_functions.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | function square(context, x, y, width, height) { 4 | 5 | var unitWidth = 0.125 * width; 6 | 7 | // Border 8 | context.fillStyle = "#000"; 9 | context.fillRect(width * x, height * y, width, height); 10 | 11 | context.fillStyle = "#EDBF3B"; 12 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 13 | 14 | context.fillStyle = "#000"; 15 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, width - unitWidth * 4, height - unitWidth * 4); 16 | 17 | } 18 | 19 | function jay(context, x, y, width, height) { 20 | 21 | var unitWidth = 0.125 * width; 22 | 23 | // Border 24 | context.fillStyle = "#000"; 25 | context.fillRect(width * x, height * y, width, height); 26 | 27 | context.fillStyle = "#3B78A7"; 28 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 29 | 30 | context.fillStyle = "#000"; 31 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, width - unitWidth * 4, height - unitWidth * 4); 32 | 33 | context.fillStyle = "#fff"; 34 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 3, width - unitWidth * 6, height - unitWidth * 6); 35 | } 36 | 37 | function ell(context, x, y, width, height) { 38 | 39 | var unitWidth = 0.125 * width; 40 | 41 | context.fillStyle = "#000"; 42 | context.fillRect(width * x, height * y, width, height); 43 | 44 | context.fillStyle = "#B82C2D"; 45 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 46 | 47 | } 48 | 49 | function zee(context, x, y, width, height) { 50 | 51 | var unitWidth = 0.125 * width; 52 | 53 | context.fillStyle = "#000"; 54 | context.fillRect(width * x, height * y, width, height); 55 | 56 | context.fillStyle = "#EDBF3B"; 57 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 58 | 59 | context.fillStyle = "#000"; 60 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 3, width - unitWidth * 6, height - unitWidth * 6); 61 | 62 | } 63 | 64 | function ess(context, x, y, width, height) { 65 | 66 | var unitWidth = 0.125 * width; 67 | 68 | context.fillStyle = "#000"; 69 | context.fillRect(width * x, height * y, width, height); 70 | 71 | context.fillStyle = "#C24175"; 72 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 73 | 74 | context.fillStyle = "#000"; 75 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, width - unitWidth * 4, height - unitWidth * 4); 76 | 77 | context.fillStyle = "#fff"; 78 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 3, width - unitWidth * 6, height - unitWidth * 6); 79 | } 80 | 81 | function tee(context, x, y, width, height) { 82 | 83 | var unitWidth = 0.125 * width; 84 | 85 | context.fillStyle = "#000"; 86 | context.fillRect(width * x, height * y, width, height); 87 | 88 | context.fillStyle = "#498E4D"; 89 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 90 | 91 | context.fillStyle = "#fff"; 92 | 93 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, unitWidth, height - unitWidth * 4); 94 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, unitWidth * 4, unitWidth); 95 | 96 | context.fillStyle = "#000"; 97 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 5, unitWidth * 4, unitWidth); 98 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 3, unitWidth, unitWidth * 3); 99 | 100 | } 101 | 102 | var eyes = [ 103 | //h1 104 | function(context, x, y, width, height) { 105 | 106 | var unitWidth = 0.125 * width; 107 | context.fillStyle = "#000"; 108 | context.fillRect(width * x, height * y, width, height); 109 | 110 | context.fillStyle = "#C28549"; 111 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth, height - unitWidth * 2); 112 | 113 | // Dots 114 | context.fillStyle = "#874437"; 115 | 116 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 1, unitWidth, unitWidth); 117 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 1, unitWidth, unitWidth); 118 | 119 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 3, unitWidth, unitWidth); 120 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 3, unitWidth, unitWidth); 121 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 3, unitWidth, unitWidth); 122 | 123 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 5, unitWidth, unitWidth); 124 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 5, unitWidth, unitWidth); 125 | 126 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 6, unitWidth, unitWidth); 127 | 128 | 129 | }, 130 | function(context, x, y, width, height) { 131 | 132 | var unitWidth = 0.125 * width; 133 | 134 | context.fillStyle = "#000"; 135 | context.fillRect(width * x, height * y, width, height); 136 | 137 | context.fillStyle = "#C28549"; 138 | context.fillRect(width * x, height * y + unitWidth, width, height - unitWidth * 2); 139 | 140 | // Dots 141 | context.fillStyle = "#874437"; 142 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 1, unitWidth, unitWidth); 143 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 1, unitWidth, unitWidth); 144 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 1, unitWidth, unitWidth); 145 | 146 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 147 | 148 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 3, unitWidth, unitWidth); 149 | 150 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 4, unitWidth, unitWidth); 151 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 4, unitWidth, unitWidth); 152 | 153 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 5, unitWidth, unitWidth); 154 | context.fillRect(width * x + unitWidth * 7, height * y + unitWidth * 5, unitWidth, unitWidth); 155 | 156 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 6, unitWidth, unitWidth); 157 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 6, unitWidth, unitWidth); 158 | 159 | 160 | }, 161 | function(context, x, y, width, height) { 162 | 163 | var unitWidth = 0.125 * width; 164 | 165 | context.fillStyle = "#000"; 166 | context.fillRect(width * x, height * y, width, height); 167 | 168 | context.fillStyle = "#C28549"; 169 | context.fillRect(width * x, height * y + unitWidth, width, height - unitWidth * 2); 170 | 171 | // Dots 172 | context.fillStyle = "#874437"; 173 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 1, unitWidth, unitWidth); 174 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 1, unitWidth, unitWidth); 175 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 1, unitWidth, unitWidth); 176 | 177 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 178 | 179 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 3, unitWidth, unitWidth); 180 | 181 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 4, unitWidth, unitWidth); 182 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 4, unitWidth, unitWidth); 183 | 184 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 5, unitWidth, unitWidth); 185 | context.fillRect(width * x + unitWidth * 7, height * y + unitWidth * 5, unitWidth, unitWidth); 186 | 187 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 6, unitWidth, unitWidth); 188 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 6, unitWidth, unitWidth); 189 | 190 | }, 191 | function(context, x, y, width, height) { 192 | 193 | var unitWidth = 0.125 * width; 194 | 195 | context.fillStyle = "#000"; 196 | context.fillRect(width * x, height * y, width, height); 197 | 198 | context.fillStyle = "#C28549"; 199 | context.fillRect(width * x, height * y + unitWidth, width - unitWidth, height - unitWidth * 2); 200 | 201 | // Dots 202 | context.fillStyle = "#874437"; 203 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 1, unitWidth, unitWidth); 204 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 1, unitWidth, unitWidth); 205 | 206 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, unitWidth, unitWidth); 207 | 208 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 3, unitWidth, unitWidth); 209 | 210 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 4, unitWidth, unitWidth); 211 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 4, unitWidth, unitWidth); 212 | 213 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 5, unitWidth, unitWidth); 214 | 215 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 6, unitWidth, unitWidth); 216 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 6, unitWidth, unitWidth); 217 | }, 218 | 219 | // v1 220 | function(context, x, y, width, height) { 221 | 222 | var unitWidth = 0.125 * width; 223 | context.fillStyle = "#000"; 224 | context.fillRect(width * x, height * y, width, height); 225 | 226 | context.fillStyle = "#C28549"; 227 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth); 228 | 229 | // Dots 230 | context.fillStyle = "#874437"; 231 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth, unitWidth, unitWidth); 232 | 233 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, unitWidth, unitWidth); 234 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 235 | 236 | context.fillRect(width * x + unitWidth, height * y + unitWidth * 4, unitWidth, unitWidth); 237 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 4, unitWidth, unitWidth); 238 | 239 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 5, unitWidth, unitWidth); 240 | 241 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 6, unitWidth, unitWidth); 242 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 6, unitWidth, unitWidth); 243 | 244 | }, 245 | function(context, x, y, width, height) { 246 | 247 | var unitWidth = 0.125 * width; 248 | 249 | context.fillStyle = "#000"; 250 | context.fillRect(width * x, height * y, width, height); 251 | 252 | context.fillStyle = "#C28549"; 253 | context.fillRect(width * x + unitWidth, height * y, width - unitWidth * 2, height); 254 | 255 | // Dots 256 | context.fillStyle = "#874437"; 257 | 258 | context.fillRect(width * x + unitWidth * 3, height * y, unitWidth, unitWidth); 259 | context.fillRect(width * x + unitWidth * 6, height * y, unitWidth, unitWidth); 260 | 261 | context.fillRect(width * x + unitWidth, height * y + unitWidth * 1, unitWidth, unitWidth); 262 | 263 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 2, unitWidth, unitWidth); 264 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 265 | 266 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 3, unitWidth, unitWidth); 267 | 268 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 4, unitWidth, unitWidth); 269 | 270 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 5, unitWidth, unitWidth); 271 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 5, unitWidth, unitWidth); 272 | 273 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 6, unitWidth, unitWidth); 274 | 275 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 7, unitWidth, unitWidth); 276 | 277 | }, 278 | function(context, x, y, width, height) { 279 | 280 | var unitWidth = 0.125 * width; 281 | 282 | context.fillStyle = "#000"; 283 | context.fillRect(width * x, height * y, width, height); 284 | 285 | context.fillStyle = "#C28549"; 286 | context.fillRect(width * x + unitWidth, height * y, width - unitWidth * 2, height); 287 | 288 | // Dots 289 | context.fillStyle = "#874437"; 290 | 291 | context.fillRect(width * x + unitWidth * 3, height * y, unitWidth, unitWidth); 292 | context.fillRect(width * x + unitWidth * 6, height * y, unitWidth, unitWidth); 293 | 294 | context.fillRect(width * x + unitWidth, height * y + unitWidth * 1, unitWidth, unitWidth); 295 | 296 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 2, unitWidth, unitWidth); 297 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 298 | 299 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 3, unitWidth, unitWidth); 300 | 301 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 4, unitWidth, unitWidth); 302 | 303 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 5, unitWidth, unitWidth); 304 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 5, unitWidth, unitWidth); 305 | 306 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 6, unitWidth, unitWidth); 307 | 308 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 7, unitWidth, unitWidth); 309 | }, 310 | function(context, x, y, width, height) { 311 | 312 | var unitWidth = 0.125 * width; 313 | 314 | context.fillStyle = "#000"; 315 | context.fillRect(width * x, height * y, width, height); 316 | 317 | context.fillStyle = "#C28549"; 318 | context.fillRect(width * x + unitWidth, height * y, width - unitWidth * 2, height - unitWidth); 319 | 320 | // Dots 321 | context.fillStyle = "#874437"; 322 | 323 | context.fillRect(width * x + unitWidth * 6, height * y, unitWidth, unitWidth); 324 | 325 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 1, unitWidth, unitWidth); 326 | 327 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 2, unitWidth, unitWidth); 328 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 2, unitWidth, unitWidth); 329 | 330 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 3, unitWidth, unitWidth); 331 | 332 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 4, unitWidth, unitWidth); 333 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 4, unitWidth, unitWidth); 334 | 335 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 5, unitWidth, unitWidth); 336 | 337 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 6, unitWidth, unitWidth); 338 | } 339 | ] 340 | 341 | var drawFunctions = [ 342 | 343 | square, 344 | 345 | jay, 346 | 347 | ell, 348 | 349 | zee, 350 | 351 | ess, 352 | 353 | tee, 354 | 355 | eyes 356 | 357 | ] 358 | 359 | function DrawFunctions(){}; 360 | 361 | DrawFunctions.prototype.getDrawFunction = function(index){ 362 | 363 | if( drawFunctions[index]) { 364 | return drawFunctions[index]; 365 | } else { 366 | return drawFunctions[5]; 367 | } 368 | } -------------------------------------------------------------------------------- /ambient/js/index.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | // http://stackoverflow.com/questions/17433015/change-the-hue-of-a-rgb-color-in-javascript 4 | // TODO: Clean up 5 | 6 | function changeHue(rgb, degree) { 7 | var hsl = rgbToHSL(rgb); 8 | hsl.h += degree; 9 | if (hsl.h > 360) { 10 | hsl.h -= 360; 11 | } 12 | else if (hsl.h < 0) { 13 | hsl.h += 360; 14 | } 15 | return hslToRGB(hsl); 16 | } 17 | 18 | // exepcts a string and returns an object 19 | function rgbToHSL(rgb) { 20 | // strip the leading # if it's there 21 | rgb = rgb.replace(/^\s*#|\s*$/g, ''); 22 | 23 | // convert 3 char codes --> 6, e.g. `E0F` --> `EE00FF` 24 | if(rgb.length == 3){ 25 | rgb = rgb.replace(/(.)/g, '$1$1'); 26 | } 27 | 28 | var r = parseInt(rgb.substr(0, 2), 16) / 255, 29 | g = parseInt(rgb.substr(2, 2), 16) / 255, 30 | b = parseInt(rgb.substr(4, 2), 16) / 255, 31 | cMax = Math.max(r, g, b), 32 | cMin = Math.min(r, g, b), 33 | delta = cMax - cMin, 34 | l = (cMax + cMin) / 2, 35 | h = 0, 36 | s = 0; 37 | 38 | if (delta == 0) { 39 | h = 0; 40 | } 41 | else if (cMax == r) { 42 | h = 60 * (((g - b) / delta) % 6); 43 | } 44 | else if (cMax == g) { 45 | h = 60 * (((b - r) / delta) + 2); 46 | } 47 | else { 48 | h = 60 * (((r - g) / delta) + 4); 49 | } 50 | 51 | if (delta == 0) { 52 | s = 0; 53 | } 54 | else { 55 | s = (delta/(1-Math.abs(2*l - 1))) 56 | } 57 | 58 | return { 59 | h: h, 60 | s: s, 61 | l: l 62 | } 63 | } 64 | 65 | // expects an object and returns a string 66 | function hslToRGB(hsl) { 67 | var h = hsl.h, 68 | s = hsl.s, 69 | l = hsl.l, 70 | c = (1 - Math.abs(2*l - 1)) * s, 71 | x = c * ( 1 - Math.abs((h / 60 ) % 2 - 1 )), 72 | m = l - c/ 2, 73 | r, g, b; 74 | 75 | if (h < 60) { 76 | r = c; 77 | g = x; 78 | b = 0; 79 | } 80 | else if (h < 120) { 81 | r = x; 82 | g = c; 83 | b = 0; 84 | } 85 | else if (h < 180) { 86 | r = 0; 87 | g = c; 88 | b = x; 89 | } 90 | else if (h < 240) { 91 | r = 0; 92 | g = x; 93 | b = c; 94 | } 95 | else if (h < 300) { 96 | r = x; 97 | g = 0; 98 | b = c; 99 | } 100 | else { 101 | r = c; 102 | g = 0; 103 | b = x; 104 | } 105 | 106 | r = normalize_rgb_value(r, m); 107 | g = normalize_rgb_value(g, m); 108 | b = normalize_rgb_value(b, m); 109 | 110 | return rgbToHex(r,g,b); 111 | } 112 | 113 | function normalize_rgb_value(color, m) { 114 | color = Math.floor((color + m) * 255); 115 | if (color < 0) { 116 | color = 0; 117 | } 118 | return color; 119 | } 120 | 121 | function rgbToHex(r, g, b) { 122 | return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); 123 | } 124 | /** 125 | * Color Manager 126 | * - Handles the slow hue rotations of colors 127 | */ 128 | 129 | function ColorManager( baseColor ){ 130 | this.hueRotation = 0; 131 | this.rotationSpeed = 4; 132 | this.baseColor = '#F0C9DD'; // Light pink 133 | }; 134 | 135 | ColorManager.prototype.getColor = function(){ 136 | 137 | // Rotate hue's for every new piece. 138 | this.hueRotation += this.rotationSpeed; 139 | if( this.hueRotation > 360 ) { 140 | this.hueRotation = 0; 141 | } 142 | 143 | return changeHue(this.baseColor, this.hueRotation); 144 | }; 145 | /** 146 | * Grid 147 | * - Manages the state of the grid 148 | */ 149 | 150 | // Init 151 | function Grid(rows, columns){ 152 | 153 | this.rows = rows; 154 | this.columns = columns; 155 | this.cells = new Array(rows); 156 | 157 | // For each row! 158 | // Has a column 159 | // Which has X cells in it. 160 | for (var r = 0; r < this.rows; r++) { 161 | 162 | this.cells[r] = new Array(this.columns); 163 | for(var c = 0; c < this.columns; c++){ 164 | this.cells[r][c] = 0; 165 | } 166 | } 167 | 168 | }; 169 | 170 | // Methods 171 | Grid.prototype.clone = function(){ 172 | var _grid = new Grid(this.rows, this.columns); 173 | for (var r = 0; r < this.rows; r++) { 174 | for(var c = 0; c < this.columns; c++){ 175 | _grid.cells[r][c] = this.cells[r][c]; 176 | } 177 | } 178 | return _grid; 179 | }; 180 | 181 | // Clear spaces in the grid, including when the blocks "fall" 182 | Grid.prototype.clearLines = function(){ 183 | 184 | var distance = 0; 185 | var row = new Array(this.columns); 186 | 187 | for(var r = this.rows - 1; r >= 0; r--){ 188 | 189 | // Clear full line 190 | if (this.isLine(r)){ 191 | 192 | distance++; 193 | for(var c = 0; c < this.columns; c++){ 194 | this.cells[r][c] = 0; 195 | } 196 | 197 | // Clear moved spaces 198 | } else if (distance > 0) { 199 | 200 | for(var c = 0; c < this.columns; c++){ 201 | this.cells[r + distance][c] = this.cells[r][c]; 202 | this.cells[r][c] = 0; 203 | } 204 | } 205 | } 206 | }; 207 | 208 | // If every item in the row has an item! 209 | Grid.prototype.isLine = function(row){ 210 | for(var c = 0; c < this.columns; c++){ 211 | if (this.cells[row][c] == 0){ 212 | return false; 213 | } 214 | } 215 | return true; 216 | }; 217 | 218 | Grid.prototype.isEmptyRow = function(row){ 219 | for(var c = 0; c < this.columns; c++){ 220 | 221 | // TH: != 0 rather than == 1 222 | if (this.cells[row][c] != 0){ 223 | return false; 224 | } 225 | } 226 | return true; 227 | }; 228 | 229 | Grid.prototype.exceeded = function(){ 230 | return !this.isEmptyRow(0) || !this.isEmptyRow(1); 231 | }; 232 | 233 | Grid.prototype.height = function(){ 234 | var r = 0; 235 | for(; r < this.rows && this.isEmptyRow(r); r++); 236 | return this.rows - r; 237 | }; 238 | 239 | Grid.prototype.lines = function(){ 240 | var count = 0; 241 | for(var r = 0; r < this.rows; r++){ 242 | if (this.isLine(r)){ 243 | count++; 244 | } 245 | } 246 | return count; 247 | }; 248 | 249 | Grid.prototype.holes = function(){ 250 | var count = 0; 251 | 252 | for(var c = 0; c < this.columns; c++){ 253 | var block = false; 254 | for(var r = 0; r < this.rows; r++){ 255 | 256 | // TH: != 0 rather than == 1 257 | if (this.cells[r][c] != 0) { 258 | block = true; 259 | }else if (this.cells[r][c] == 0 && block){ 260 | count++; 261 | } 262 | } 263 | } 264 | return count; 265 | }; 266 | 267 | Grid.prototype.blockades = function(){ 268 | var count = 0; 269 | 270 | for(var c = 0; c < this.columns; c++){ 271 | var hole = false; 272 | for(var r = this.rows - 1; r >= 0; r--){ 273 | if (this.cells[r][c] == 0){ 274 | hole = true; 275 | 276 | // TH: != 0 rather than == 1 277 | }else if (this.cells[r][c] != 0 && hole){ 278 | count++; 279 | } 280 | } 281 | } 282 | return count; 283 | } 284 | 285 | Grid.prototype.aggregateHeight = function(){ 286 | var total = 0; 287 | 288 | for(var c = 0; c < this.columns; c++){ 289 | total += this.columnHeight(c); 290 | } 291 | return total; 292 | }; 293 | 294 | Grid.prototype.bumpiness = function(){ 295 | var total = 0; 296 | for(var c = 0; c < this.columns - 1; c++){ 297 | total += Math.abs(this.columnHeight(c) - this.columnHeight(c+ 1)); 298 | } 299 | return total; 300 | } 301 | 302 | Grid.prototype.columnHeight = function(column){ 303 | var r = 0; 304 | 305 | for(; r < this.rows && this.cells[r][column] == 0; r++); 306 | return this.rows - r; 307 | }; 308 | 309 | // Piece 310 | Grid.prototype.addPiece = function(piece) { 311 | 312 | for(var r = 0; r < piece.cells.length; r++) { 313 | for (var c = 0; c < piece.cells[r].length; c++) { 314 | 315 | var _r = piece.row + r; 316 | var _c = piece.column + c; 317 | 318 | // TH: != 0 rather than == 1 319 | if (piece.cells[r][c] != 0 && _r >= 0){ 320 | 321 | // TH: Updates color, rather than 1 322 | if (piece.cells[r][c] > 1) { 323 | var num = piece.cells[r][c] - 2; 324 | this.cells[_r][_c] = piece.color[num]; 325 | } else { 326 | this.cells[_r][_c] = piece.color; 327 | } 328 | } 329 | 330 | } 331 | } 332 | }; 333 | 334 | Grid.prototype.valid = function(piece){ 335 | 336 | for(var r = 0; r < piece.cells.length; r++){ 337 | for(var c = 0; c < piece.cells[r].length; c++){ 338 | var _r = piece.row + r; 339 | var _c = piece.column + c; 340 | 341 | // TH: != 0 rather than == 1 342 | if (piece.cells[r][c] != 0){ 343 | if (!(_c < this.columns && _r < this.rows && this.cells[_r][_c] == 0)){ 344 | return false; 345 | } 346 | } 347 | } 348 | } 349 | return true; 350 | }; 351 | 352 | Grid.prototype.canMoveDown = function(piece){ 353 | for(var r = 0; r < piece.cells.length; r++){ 354 | for(var c = 0; c < piece.cells[r].length; c++){ 355 | var _r = piece.row + r + 1; 356 | var _c = piece.column + c; 357 | 358 | // TH: != 0 rather than == 1 359 | if (piece.cells[r][c] != 0 && _r >= 0){ 360 | 361 | if (!(_r < this.rows && this.cells[_r][_c] == 0)){ 362 | return false; 363 | } 364 | } 365 | } 366 | } 367 | return true; 368 | }; 369 | 370 | Grid.prototype.canMoveLeft = function(piece){ 371 | for(var r = 0; r < piece.cells.length; r++){ 372 | for(var c = 0; c < piece.cells[r].length; c++){ 373 | var _r = piece.row + r; 374 | var _c = piece.column + c - 1; 375 | 376 | // TH: != 0 rather than == 1 377 | if (piece.cells[r][c] != 0){ 378 | if (!(_c >= 0 && this.cells[_r][_c] == 0)){ 379 | return false; 380 | } 381 | } 382 | } 383 | } 384 | return true; 385 | }; 386 | 387 | Grid.prototype.canMoveRight = function(piece){ 388 | for(var r = 0; r < piece.cells.length; r++){ 389 | for(var c = 0; c < piece.cells[r].length; c++){ 390 | var _r = piece.row + r; 391 | var _c = piece.column + c + 1; 392 | 393 | // TH: != 0 rather than == 1 394 | if (piece.cells[r][c] != 0){ 395 | if (!(_c >= 0 && this.cells[_r][_c] == 0)){ 396 | return false; 397 | } 398 | } 399 | } 400 | } 401 | return true; 402 | }; 403 | 404 | Grid.prototype.rotateOffset = function(piece){ 405 | 406 | console.log("rotate?"); 407 | 408 | var _piece = piece.clone(); 409 | _piece.rotate(1); 410 | if (this.valid(_piece)) { 411 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 412 | } 413 | 414 | // Kicking 415 | var initialRow = _piece.row; 416 | var initialCol = _piece.column; 417 | 418 | for (var i = 0; i < _piece.dimension - 1; i++) { 419 | _piece.column = initialCol + i; 420 | if (this.valid(_piece)) { 421 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 422 | } 423 | 424 | for (var j = 0; j < _piece.dimension - 1; j++) { 425 | _piece.row = initialRow - j; 426 | if (this.valid(_piece)) { 427 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 428 | } 429 | } 430 | _piece.row = initialRow; 431 | } 432 | _piece.column = initialCol; 433 | 434 | for (var i = 0; i < _piece.dimension - 1; i++) { 435 | _piece.column = initialCol - i; 436 | if (this.valid(_piece)) { 437 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 438 | } 439 | 440 | for (var j = 0; j < _piece.dimension - 1; j++) { 441 | _piece.row = initialRow - j; 442 | if (this.valid(_piece)) { 443 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 444 | } 445 | } 446 | _piece.row = initialRow; 447 | } 448 | _piece.column = initialCol; 449 | 450 | return null; 451 | }; 452 | 453 | /** 454 | * Piece 455 | * - Represents a single piece on the board. 456 | */ 457 | 458 | // Object that represents a single piece & its properties. 459 | function Piece(cells, color){ 460 | this.cells = cells; 461 | this.dimension = this.cells.length; 462 | this.row = 0; 463 | this.column = 0; 464 | this.color = color; 465 | }; 466 | 467 | Piece.fromIndex = function(index, color){ 468 | 469 | var cells 470 | 471 | switch (index){ 472 | case 0:// O 473 | cells = [ 474 | [1, 1], 475 | [1, 1] 476 | ]; 477 | break; 478 | case 1: // J 479 | cells = [ 480 | [1, 0, 0], 481 | [1, 1, 1], 482 | [0, 0, 0] 483 | ]; 484 | break; 485 | case 2: // L 486 | cells = [ 487 | [0, 0, 1], 488 | [1, 1, 1], 489 | [0, 0, 0] 490 | ]; 491 | break; 492 | case 3: // Z 493 | cells = [ 494 | [1, 1, 0], 495 | [0, 1, 1], 496 | [0, 0, 0] 497 | ]; 498 | break; 499 | case 4: // S 500 | cells = [ 501 | [0, 1, 1], 502 | [1, 1, 0], 503 | [0, 0, 0] 504 | ]; 505 | break; 506 | case 5: // T 507 | cells = [ 508 | [0, 1, 0], 509 | [1, 1, 1], 510 | [0, 0, 0] 511 | ]; 512 | break; 513 | case 6: // I 514 | cells = [ 515 | [0, 0, 0, 0], 516 | [1, 1, 1, 1], 517 | [0, 0, 0, 0], 518 | [0, 0, 0, 0] 519 | ]; 520 | break; 521 | 522 | } 523 | 524 | var piece = new Piece(cells, color); 525 | 526 | piece.row = 0; 527 | piece.column = Math.floor((10 - piece.dimension) / 2); // Centralize 528 | return piece; 529 | }; 530 | 531 | Piece.prototype.clone = function(){ 532 | 533 | var _cells = new Array(this.dimension); 534 | for (var r = 0; r < this.dimension; r++) { 535 | _cells[r] = new Array(this.dimension); 536 | for(var c = 0; c < this.dimension; c++){ 537 | _cells[r][c] = this.cells[r][c]; 538 | } 539 | } 540 | 541 | var piece = new Piece(_cells, this.color); 542 | piece.row = this.row; 543 | piece.column = this.column; 544 | return piece; 545 | }; 546 | 547 | Piece.prototype.rotate = function(rotations){ 548 | for(var i = 0; i < rotations; i++) { 549 | var _cells = new Array(this.dimension); 550 | for (var r = 0; r < this.dimension; r++) { 551 | _cells[r] = new Array(this.dimension); 552 | } 553 | 554 | switch (this.dimension) { // Assumed square matrix 555 | case 2: 556 | _cells[0][0] = this.cells[1][0]; 557 | _cells[0][1] = this.cells[0][0]; 558 | _cells[1][0] = this.cells[1][1]; 559 | _cells[1][1] = this.cells[0][1]; 560 | break; 561 | case 3: 562 | _cells[0][0] = this.cells[2][0]; 563 | _cells[0][1] = this.cells[1][0]; 564 | _cells[0][2] = this.cells[0][0]; 565 | _cells[1][0] = this.cells[2][1]; 566 | _cells[1][1] = this.cells[1][1]; 567 | _cells[1][2] = this.cells[0][1]; 568 | _cells[2][0] = this.cells[2][2]; 569 | _cells[2][1] = this.cells[1][2]; 570 | _cells[2][2] = this.cells[0][2]; 571 | break; 572 | case 4: 573 | _cells[0][0] = this.cells[3][0]; 574 | _cells[0][1] = this.cells[2][0]; 575 | _cells[0][2] = this.cells[1][0]; 576 | _cells[0][3] = this.cells[0][0]; 577 | _cells[1][3] = this.cells[0][1]; 578 | _cells[2][3] = this.cells[0][2]; 579 | _cells[3][3] = this.cells[0][3]; 580 | _cells[3][2] = this.cells[1][3]; 581 | _cells[3][1] = this.cells[2][3]; 582 | _cells[3][0] = this.cells[3][3]; 583 | _cells[2][0] = this.cells[3][2]; 584 | _cells[1][0] = this.cells[3][1]; 585 | 586 | _cells[1][1] = this.cells[2][1]; 587 | _cells[1][2] = this.cells[1][1]; 588 | _cells[2][2] = this.cells[1][2]; 589 | _cells[2][1] = this.cells[2][2]; 590 | break; 591 | } 592 | 593 | this.cells = _cells; 594 | } 595 | }; 596 | 597 | /** 598 | * Game manager, manages flow and updating of game. 599 | */ 600 | 601 | function GameManager(){ 602 | 603 | this.gridCanvas = document.getElementById('grid-canvas'); 604 | 605 | this.gravityUpdater = new Updater(); 606 | 607 | this.gravityUpdater.onUpdate(function(){ 608 | self.applyGravity(); 609 | self.actuate(); 610 | }); 611 | 612 | var self = this; 613 | this.setup(); 614 | this.startAI(); 615 | this.gravityUpdater.checkUpdate(Date.now()); 616 | }; 617 | 618 | GameManager.prototype.setup = function(){ 619 | 620 | this.baseColumns = 8; 621 | 622 | this.pieceWidth = window.innerWidth / this.baseColumns; 623 | this.pieceHeight = this.pieceWidth; 624 | 625 | this.displacementWidth = Math.floor(this.pieceWidth / 4); 626 | this.strokeThickness = 20; 627 | 628 | var canvasHeightPieces = Math.ceil(window.innerHeight / this.pieceHeight) + 2; 629 | 630 | this.gridCanvas.width = window.innerWidth; 631 | this.gridCanvas.height = canvasHeightPieces * this.pieceHeight; 632 | 633 | this.grid = new Grid(canvasHeightPieces, this.baseColumns); 634 | this.rpg = new RandomPieceGenerator(); 635 | this.ai = new AI(0.510066, 0.760666, 0.35663, 0.184483); 636 | 637 | this.workingPieces = [this.rpg.nextPiece(), this.rpg.nextPiece()]; 638 | this.workingPiece = this.workingPieces[0]; 639 | 640 | this.isOver = true; 641 | 642 | this.stopAI(); 643 | this.actuate(); 644 | }; 645 | 646 | GameManager.prototype.actuate = function(){ 647 | 648 | var _grid = this.grid.clone(); 649 | 650 | if (this.workingPiece != null) { 651 | _grid.addPiece(this.workingPiece); 652 | } 653 | 654 | var context = this.gridCanvas.getContext('2d'); 655 | context.save(); 656 | 657 | context.clearRect(0, 0, this.gridCanvas.width, this.gridCanvas.height); 658 | 659 | for(var r = 2; r < _grid.rows; r++){ 660 | 661 | for(var c = 0; c < _grid.columns; c++){ 662 | 663 | if (_grid.cells[r][c] != 0){ 664 | 665 | context.fillStyle = _grid.cells[r][c]; 666 | context.strokeStyle = _grid.cells[r][c]; 667 | context.fillRect(this.pieceWidth * c, this.pieceHeight * r, this.pieceWidth, this.pieceHeight); 668 | 669 | // Border? 670 | context.fillStyle = "rgba(255, 255, 255, 0.3)"; 671 | context.fillRect(this.pieceWidth * c + this.displacementWidth, this.pieceHeight * r + this.displacementWidth, this.pieceWidth / 2, this.strokeThickness); 672 | context.fillRect(this.pieceWidth * c + this.displacementWidth, this.pieceHeight * r + this.displacementWidth + this.strokeThickness, this.strokeThickness, this.pieceWidth / 2 - this.strokeThickness ); 673 | } 674 | } 675 | } 676 | 677 | context.restore(); 678 | }; 679 | 680 | GameManager.prototype.startAI = function(){ 681 | this.aiActive = true; 682 | }; 683 | 684 | GameManager.prototype.stopAI = function(){ 685 | this.aiActive = false; 686 | }; 687 | 688 | GameManager.prototype.setWorkingPiece = function(){ 689 | 690 | this.grid.addPiece(this.workingPiece); 691 | this.grid.clearLines(); 692 | 693 | if (!this.grid.exceeded()){ 694 | 695 | for(var i = 0; i < this.workingPieces.length - 1; i++){ 696 | this.workingPieces[i] = this.workingPieces[i + 1]; 697 | } 698 | 699 | this.workingPieces[this.workingPieces.length - 1] = this.rpg.nextPiece(); 700 | this.workingPiece = this.workingPieces[0]; 701 | 702 | if (this.aiActive) { 703 | this.aiMove(); 704 | } 705 | } 706 | 707 | // TODO: NO WAYYYY 708 | else{ 709 | 710 | } 711 | }; 712 | 713 | GameManager.prototype.applyGravity = function(){ 714 | 715 | if (this.grid.canMoveDown(this.workingPiece)) { 716 | this.workingPiece.row++; 717 | }else{ 718 | this.setWorkingPiece(); 719 | } 720 | 721 | }; 722 | 723 | GameManager.prototype.drop = function(){ 724 | while(this.grid.canMoveDown(this.workingPiece)){ 725 | this.workingPiece.row++; 726 | } 727 | }; 728 | 729 | GameManager.prototype.moveLeft = function(){ 730 | if (this.grid.canMoveLeft(this.workingPiece)){ 731 | this.workingPiece.column--; 732 | } 733 | }; 734 | 735 | GameManager.prototype.moveRight = function(){ 736 | if (this.grid.canMoveRight(this.workingPiece)){ 737 | this.workingPiece.column++; 738 | } 739 | }; 740 | 741 | GameManager.prototype.rotate = function(){ 742 | var offset = this.grid.rotateOffset(this.workingPiece); 743 | if (offset != null){ 744 | this.workingPiece.rotate(1); 745 | this.workingPiece.row += offset.rowOffset; 746 | this.workingPiece.column += offset.columnOffset; 747 | } 748 | }; 749 | 750 | GameManager.prototype.aiMove = function(){ 751 | this.workingPiece = this.ai.best(this.grid, this.workingPieces, 0).piece; 752 | }; 753 | 754 | function RandomPieceGenerator(){ 755 | Math.seed 756 | this.bag = [0, 1, 2, 3, 4, 5, 6]; 757 | this.shuffleBag(); 758 | this.index = -1; 759 | 760 | this.colorManager = new ColorManager(); 761 | }; 762 | 763 | RandomPieceGenerator.prototype.nextPiece = function(){ 764 | 765 | this.index++; 766 | if (this.index >= this.bag.length){ 767 | this.shuffleBag(); 768 | this.index = 0; 769 | } 770 | 771 | var color = this.colorManager.getColor(); 772 | 773 | return Piece.fromIndex(this.bag[this.index], color); 774 | 775 | }; 776 | 777 | RandomPieceGenerator.prototype.shuffleBag = function() { 778 | var currentIndex = this.bag.length 779 | , temporaryValue 780 | , randomIndex 781 | ; 782 | 783 | // While there remain elements to shuffle... 784 | while (0 !== currentIndex) { 785 | 786 | // Pick a remaining element... 787 | randomIndex = Math.floor(Math.random() * currentIndex); 788 | currentIndex -= 1; 789 | 790 | // And swap it with the current element. 791 | temporaryValue = this.bag[currentIndex]; 792 | this.bag[currentIndex] = this.bag[randomIndex]; 793 | this.bag[randomIndex] = temporaryValue; 794 | } 795 | }; 796 | function AI(heightWeight, linesWeight, holesWeight, bumpinessWeight){ 797 | 798 | this.heightWeight = heightWeight; 799 | this.linesWeight = linesWeight; 800 | this.holesWeight = holesWeight; 801 | this.bumpinessWeight = bumpinessWeight; 802 | 803 | }; 804 | 805 | AI.prototype.best = function(grid, workingPieces, workingPieceIndex){ 806 | 807 | var best = null; 808 | var bestScore = null; 809 | var workingPiece = workingPieces[workingPieceIndex]; 810 | 811 | for(var rotation = 0; rotation < 4; rotation++){ 812 | var _piece = workingPiece.clone(); 813 | _piece.rotate(rotation); 814 | 815 | while(grid.canMoveLeft(_piece)){ 816 | _piece.column --; 817 | } 818 | 819 | while(grid.valid(_piece)){ 820 | var _pieceSet = _piece.clone(); 821 | while(grid.canMoveDown(_pieceSet)){ 822 | _pieceSet.row++; 823 | } 824 | 825 | var _grid = grid.clone(); 826 | _grid.addPiece(_pieceSet); 827 | 828 | var score = null; 829 | if (workingPieceIndex == (workingPieces.length - 1)) { 830 | score = -this.heightWeight * _grid.aggregateHeight() + this.linesWeight * _grid.lines() - this.holesWeight * _grid.holes() - this.bumpinessWeight * _grid.bumpiness(); 831 | }else{ 832 | score = this.best(_grid, workingPieces, workingPieceIndex + 1).score; 833 | } 834 | 835 | if (score > bestScore || bestScore == null){ 836 | bestScore = score; 837 | best = _piece.clone(); 838 | } 839 | 840 | _piece.column++; 841 | } 842 | } 843 | 844 | return {piece:best, score:bestScore}; 845 | }; 846 | /** 847 | * Updater, controls time and speed. 848 | */ 849 | 850 | function Updater() { 851 | this.lastUpdateTime = Date.now(); 852 | this.deltaThreshold = 250; // MS before each update 853 | this.updateCallback = null; 854 | 855 | window.requestAnimFrame = (function() { 856 | // Polyfill 857 | return ( 858 | window.requestAnimationFrame || 859 | window.webkitRequestAnimationFrame || 860 | window.mozRequestAnimationFrame || 861 | window.oRequestAnimationFrame || 862 | window.msRequestAnimationFrame || 863 | function(callback) { 864 | window.setTimeout(callback, 1000 / 60); 865 | } 866 | ); 867 | })(); 868 | } 869 | 870 | Updater.prototype.onUpdate = function(callback) { 871 | this.updateCallback = callback; 872 | }; 873 | 874 | Updater.prototype.doUpdate = function(timestamp) { 875 | if (this.updateCallback != null) { 876 | this.updateCallback(); 877 | } 878 | 879 | this.lastUpdateTime = timestamp; 880 | }; 881 | 882 | Updater.prototype.checkUpdate = function(timestamp) { 883 | var self = this; 884 | var delta = timestamp - this.lastUpdateTime; 885 | 886 | if (delta > this.deltaThreshold) { 887 | this.doUpdate(timestamp); 888 | } 889 | 890 | window.requestAnimFrame(function() { 891 | self.checkUpdate(Date.now()); 892 | }); 893 | }; 894 | -------------------------------------------------------------------------------- /classic/js/index.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | function square(context, x, y, width, height) { 4 | 5 | var unitWidth = 0.125 * width; 6 | 7 | // Border 8 | context.fillStyle = "#000"; 9 | context.fillRect(width * x, height * y, width, height); 10 | 11 | context.fillStyle = "#C6CFA4"; 12 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 13 | 14 | context.fillStyle = "#000"; 15 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, width - unitWidth * 4, height - unitWidth * 4); 16 | 17 | } 18 | 19 | function jay(context, x, y, width, height) { 20 | 21 | var unitWidth = 0.125 * width; 22 | 23 | // Border 24 | context.fillStyle = "#000"; 25 | context.fillRect(width * x, height * y, width, height); 26 | 27 | context.fillStyle = "#92BE7C"; 28 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 29 | 30 | context.fillStyle = "#000"; 31 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, width - unitWidth * 4, height - unitWidth * 4); 32 | 33 | context.fillStyle = "#C6CFA4"; 34 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 3, width - unitWidth * 6, height - unitWidth * 6); 35 | } 36 | 37 | function ell(context, x, y, width, height) { 38 | 39 | var unitWidth = 0.125 * width; 40 | 41 | context.fillStyle = "#000"; 42 | context.fillRect(width * x, height * y, width, height); 43 | 44 | context.fillStyle = "#3C6A4E"; 45 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 46 | 47 | } 48 | 49 | function zee(context, x, y, width, height) { 50 | 51 | var unitWidth = 0.125 * width; 52 | 53 | context.fillStyle = "#000"; 54 | context.fillRect(width * x, height * y, width, height); 55 | 56 | context.fillStyle = "#92BE7C"; 57 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 58 | 59 | context.fillStyle = "#000"; 60 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 3, width - unitWidth * 6, height - unitWidth * 6); 61 | 62 | } 63 | 64 | function ess(context, x, y, width, height) { 65 | 66 | var unitWidth = 0.125 * width; 67 | 68 | context.fillStyle = "#000"; 69 | context.fillRect(width * x, height * y, width, height); 70 | 71 | context.fillStyle = "#3C6A4E"; 72 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 73 | 74 | context.fillStyle = "#000"; 75 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, width - unitWidth * 4, height - unitWidth * 4); 76 | 77 | context.fillStyle = "#C6CFA4"; 78 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 3, width - unitWidth * 6, height - unitWidth * 6); 79 | } 80 | 81 | function tee(context, x, y, width, height) { 82 | 83 | var unitWidth = 0.125 * width; 84 | 85 | context.fillStyle = "#000"; 86 | context.fillRect(width * x, height * y, width, height); 87 | 88 | context.fillStyle = "#92BE7C"; 89 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 90 | 91 | context.fillStyle = "#C6CFA4"; 92 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, unitWidth, height - unitWidth * 4); 93 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, unitWidth * 4, unitWidth); 94 | 95 | context.fillStyle = "#000"; 96 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 5, unitWidth * 4, unitWidth); 97 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 3, unitWidth, unitWidth * 3); 98 | 99 | } 100 | 101 | var eyes = [ 102 | //h1 103 | function(context, x, y, width, height) { 104 | 105 | var unitWidth = 0.125 * width; 106 | context.fillStyle = "#000"; 107 | context.fillRect(width * x, height * y, width, height); 108 | 109 | context.fillStyle = "#92BE7C"; 110 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth, height - unitWidth * 2); 111 | 112 | // Dots 113 | context.fillStyle = "#3C6A4E"; 114 | 115 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 1, unitWidth, unitWidth); 116 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 1, unitWidth, unitWidth); 117 | 118 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 3, unitWidth, unitWidth); 119 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 3, unitWidth, unitWidth); 120 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 3, unitWidth, unitWidth); 121 | 122 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 5, unitWidth, unitWidth); 123 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 5, unitWidth, unitWidth); 124 | 125 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 6, unitWidth, unitWidth); 126 | 127 | 128 | }, 129 | function(context, x, y, width, height) { 130 | 131 | var unitWidth = 0.125 * width; 132 | 133 | context.fillStyle = "#000"; 134 | context.fillRect(width * x, height * y, width, height); 135 | 136 | context.fillStyle = "#92BE7C"; 137 | context.fillRect(width * x, height * y + unitWidth, width, height - unitWidth * 2); 138 | 139 | // Dots 140 | context.fillStyle = "#3C6A4E"; 141 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 1, unitWidth, unitWidth); 142 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 1, unitWidth, unitWidth); 143 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 1, unitWidth, unitWidth); 144 | 145 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 146 | 147 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 3, unitWidth, unitWidth); 148 | 149 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 4, unitWidth, unitWidth); 150 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 4, unitWidth, unitWidth); 151 | 152 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 5, unitWidth, unitWidth); 153 | context.fillRect(width * x + unitWidth * 7, height * y + unitWidth * 5, unitWidth, unitWidth); 154 | 155 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 6, unitWidth, unitWidth); 156 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 6, unitWidth, unitWidth); 157 | 158 | 159 | }, 160 | function(context, x, y, width, height) { 161 | 162 | var unitWidth = 0.125 * width; 163 | 164 | context.fillStyle = "#000"; 165 | context.fillRect(width * x, height * y, width, height); 166 | 167 | context.fillStyle = "#92BE7C"; 168 | context.fillRect(width * x, height * y + unitWidth, width, height - unitWidth * 2); 169 | 170 | // Dots 171 | context.fillStyle = "#3C6A4E"; 172 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 1, unitWidth, unitWidth); 173 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 1, unitWidth, unitWidth); 174 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 1, unitWidth, unitWidth); 175 | 176 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 177 | 178 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 3, unitWidth, unitWidth); 179 | 180 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 4, unitWidth, unitWidth); 181 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 4, unitWidth, unitWidth); 182 | 183 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 5, unitWidth, unitWidth); 184 | context.fillRect(width * x + unitWidth * 7, height * y + unitWidth * 5, unitWidth, unitWidth); 185 | 186 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 6, unitWidth, unitWidth); 187 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 6, unitWidth, unitWidth); 188 | 189 | }, 190 | function(context, x, y, width, height) { 191 | 192 | var unitWidth = 0.125 * width; 193 | 194 | context.fillStyle = "#000"; 195 | context.fillRect(width * x, height * y, width, height); 196 | 197 | context.fillStyle = "#92BE7C"; 198 | context.fillRect(width * x, height * y + unitWidth, width - unitWidth, height - unitWidth * 2); 199 | 200 | // Dots 201 | context.fillStyle = "#3C6A4E"; 202 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 1, unitWidth, unitWidth); 203 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 1, unitWidth, unitWidth); 204 | 205 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, unitWidth, unitWidth); 206 | 207 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 3, unitWidth, unitWidth); 208 | 209 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 4, unitWidth, unitWidth); 210 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 4, unitWidth, unitWidth); 211 | 212 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 5, unitWidth, unitWidth); 213 | 214 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 6, unitWidth, unitWidth); 215 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 6, unitWidth, unitWidth); 216 | }, 217 | 218 | // v1 219 | function(context, x, y, width, height) { 220 | 221 | var unitWidth = 0.125 * width; 222 | context.fillStyle = "#000"; 223 | context.fillRect(width * x, height * y, width, height); 224 | 225 | context.fillStyle = "#92BE7C"; 226 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth); 227 | 228 | // Dots 229 | context.fillStyle = "#3C6A4E"; 230 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth, unitWidth, unitWidth); 231 | 232 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, unitWidth, unitWidth); 233 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 234 | 235 | context.fillRect(width * x + unitWidth, height * y + unitWidth * 4, unitWidth, unitWidth); 236 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 4, unitWidth, unitWidth); 237 | 238 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 5, unitWidth, unitWidth); 239 | 240 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 6, unitWidth, unitWidth); 241 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 6, unitWidth, unitWidth); 242 | 243 | }, 244 | function(context, x, y, width, height) { 245 | 246 | var unitWidth = 0.125 * width; 247 | 248 | context.fillStyle = "#000"; 249 | context.fillRect(width * x, height * y, width, height); 250 | 251 | context.fillStyle = "#92BE7C"; 252 | context.fillRect(width * x + unitWidth, height * y, width - unitWidth * 2, height); 253 | 254 | // Dots 255 | context.fillStyle = "#3C6A4E"; 256 | 257 | context.fillRect(width * x + unitWidth * 3, height * y, unitWidth, unitWidth); 258 | context.fillRect(width * x + unitWidth * 6, height * y, unitWidth, unitWidth); 259 | 260 | context.fillRect(width * x + unitWidth, height * y + unitWidth * 1, unitWidth, unitWidth); 261 | 262 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 2, unitWidth, unitWidth); 263 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 264 | 265 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 3, unitWidth, unitWidth); 266 | 267 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 4, unitWidth, unitWidth); 268 | 269 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 5, unitWidth, unitWidth); 270 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 5, unitWidth, unitWidth); 271 | 272 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 6, unitWidth, unitWidth); 273 | 274 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 7, unitWidth, unitWidth); 275 | 276 | }, 277 | function(context, x, y, width, height) { 278 | 279 | var unitWidth = 0.125 * width; 280 | 281 | context.fillStyle = "#000"; 282 | context.fillRect(width * x, height * y, width, height); 283 | 284 | context.fillStyle = "#92BE7C"; 285 | context.fillRect(width * x + unitWidth, height * y, width - unitWidth * 2, height); 286 | 287 | // Dots 288 | context.fillStyle = "#3C6A4E"; 289 | 290 | context.fillRect(width * x + unitWidth * 3, height * y, unitWidth, unitWidth); 291 | context.fillRect(width * x + unitWidth * 6, height * y, unitWidth, unitWidth); 292 | 293 | context.fillRect(width * x + unitWidth, height * y + unitWidth * 1, unitWidth, unitWidth); 294 | 295 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 2, unitWidth, unitWidth); 296 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 297 | 298 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 3, unitWidth, unitWidth); 299 | 300 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 4, unitWidth, unitWidth); 301 | 302 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 5, unitWidth, unitWidth); 303 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 5, unitWidth, unitWidth); 304 | 305 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 6, unitWidth, unitWidth); 306 | 307 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 7, unitWidth, unitWidth); 308 | }, 309 | function(context, x, y, width, height) { 310 | 311 | var unitWidth = 0.125 * width; 312 | 313 | context.fillStyle = "#000"; 314 | context.fillRect(width * x, height * y, width, height); 315 | 316 | context.fillStyle = "#92BE7C"; 317 | context.fillRect(width * x + unitWidth, height * y, width - unitWidth * 2, height - unitWidth); 318 | 319 | // Dots 320 | context.fillStyle = "#3C6A4E"; 321 | 322 | context.fillRect(width * x + unitWidth * 6, height * y, unitWidth, unitWidth); 323 | 324 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 1, unitWidth, unitWidth); 325 | 326 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 2, unitWidth, unitWidth); 327 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 2, unitWidth, unitWidth); 328 | 329 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 3, unitWidth, unitWidth); 330 | 331 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 4, unitWidth, unitWidth); 332 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 4, unitWidth, unitWidth); 333 | 334 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 5, unitWidth, unitWidth); 335 | 336 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 6, unitWidth, unitWidth); 337 | } 338 | ] 339 | 340 | var drawFunctions = [ 341 | 342 | square, 343 | 344 | jay, 345 | 346 | ell, 347 | 348 | zee, 349 | 350 | ess, 351 | 352 | tee, 353 | 354 | eyes 355 | 356 | ] 357 | 358 | function DrawFunctions(){}; 359 | 360 | DrawFunctions.prototype.getDrawFunction = function(index){ 361 | 362 | if( drawFunctions[index]) { 363 | return drawFunctions[index]; 364 | } else { 365 | return drawFunctions[5]; 366 | } 367 | } 368 | /** 369 | * Grid 370 | * - Manages the state of the grid 371 | */ 372 | 373 | // Init 374 | function Grid(rows, columns){ 375 | 376 | this.rows = rows; 377 | this.columns = columns; 378 | this.cells = new Array(rows); 379 | 380 | // For each row! 381 | // Has a column 382 | // Which has X cells in it. 383 | for (var r = 0; r < this.rows; r++) { 384 | 385 | this.cells[r] = new Array(this.columns); 386 | for(var c = 0; c < this.columns; c++){ 387 | this.cells[r][c] = 0; 388 | } 389 | } 390 | 391 | }; 392 | 393 | // Methods 394 | Grid.prototype.clone = function(){ 395 | var _grid = new Grid(this.rows, this.columns); 396 | for (var r = 0; r < this.rows; r++) { 397 | for(var c = 0; c < this.columns; c++){ 398 | _grid.cells[r][c] = this.cells[r][c]; 399 | } 400 | } 401 | return _grid; 402 | }; 403 | 404 | // Clear spaces in the grid, including when the blocks "fall" 405 | Grid.prototype.clearLines = function(){ 406 | 407 | var distance = 0; 408 | var row = new Array(this.columns); 409 | 410 | for(var r = this.rows - 1; r >= 0; r--){ 411 | 412 | // Clear full line 413 | if (this.isLine(r)){ 414 | 415 | distance++; 416 | for(var c = 0; c < this.columns; c++){ 417 | this.cells[r][c] = 0; 418 | } 419 | 420 | // Clear moved spaces 421 | } else if (distance > 0) { 422 | 423 | for(var c = 0; c < this.columns; c++){ 424 | this.cells[r + distance][c] = this.cells[r][c]; 425 | this.cells[r][c] = 0; 426 | } 427 | } 428 | } 429 | }; 430 | 431 | // If every item in the row has an item! 432 | Grid.prototype.isLine = function(row){ 433 | for(var c = 0; c < this.columns; c++){ 434 | if (this.cells[row][c] == 0){ 435 | return false; 436 | } 437 | } 438 | return true; 439 | }; 440 | 441 | Grid.prototype.isEmptyRow = function(row){ 442 | for(var c = 0; c < this.columns; c++){ 443 | 444 | // TH: != 0 rather than == 1 445 | if (this.cells[row][c] != 0){ 446 | return false; 447 | } 448 | } 449 | return true; 450 | }; 451 | 452 | Grid.prototype.exceeded = function(){ 453 | return !this.isEmptyRow(0) || !this.isEmptyRow(1); 454 | }; 455 | 456 | Grid.prototype.height = function(){ 457 | var r = 0; 458 | for(; r < this.rows && this.isEmptyRow(r); r++); 459 | return this.rows - r; 460 | }; 461 | 462 | Grid.prototype.lines = function(){ 463 | var count = 0; 464 | for(var r = 0; r < this.rows; r++){ 465 | if (this.isLine(r)){ 466 | count++; 467 | } 468 | } 469 | return count; 470 | }; 471 | 472 | Grid.prototype.holes = function(){ 473 | var count = 0; 474 | 475 | for(var c = 0; c < this.columns; c++){ 476 | var block = false; 477 | for(var r = 0; r < this.rows; r++){ 478 | 479 | // TH: != 0 rather than == 1 480 | if (this.cells[r][c] != 0) { 481 | block = true; 482 | }else if (this.cells[r][c] == 0 && block){ 483 | count++; 484 | } 485 | } 486 | } 487 | return count; 488 | }; 489 | 490 | Grid.prototype.blockades = function(){ 491 | var count = 0; 492 | 493 | for(var c = 0; c < this.columns; c++){ 494 | var hole = false; 495 | for(var r = this.rows - 1; r >= 0; r--){ 496 | if (this.cells[r][c] == 0){ 497 | hole = true; 498 | 499 | // TH: != 0 rather than == 1 500 | }else if (this.cells[r][c] != 0 && hole){ 501 | count++; 502 | } 503 | } 504 | } 505 | return count; 506 | } 507 | 508 | Grid.prototype.aggregateHeight = function(){ 509 | var total = 0; 510 | 511 | for(var c = 0; c < this.columns; c++){ 512 | total += this.columnHeight(c); 513 | } 514 | return total; 515 | }; 516 | 517 | Grid.prototype.bumpiness = function(){ 518 | var total = 0; 519 | for(var c = 0; c < this.columns - 1; c++){ 520 | total += Math.abs(this.columnHeight(c) - this.columnHeight(c+ 1)); 521 | } 522 | return total; 523 | } 524 | 525 | Grid.prototype.columnHeight = function(column){ 526 | var r = 0; 527 | 528 | for(; r < this.rows && this.cells[r][column] == 0; r++); 529 | return this.rows - r; 530 | }; 531 | 532 | // Piece 533 | Grid.prototype.addPiece = function(piece) { 534 | 535 | for(var r = 0; r < piece.cells.length; r++) { 536 | for (var c = 0; c < piece.cells[r].length; c++) { 537 | 538 | var _r = piece.row + r; 539 | var _c = piece.column + c; 540 | 541 | // TH: != 0 rather than == 1 542 | if (piece.cells[r][c] != 0 && _r >= 0){ 543 | 544 | // TH: Updates color, rather than 1 545 | if (piece.cells[r][c] > 1) { 546 | var num = piece.cells[r][c] - 2; 547 | this.cells[_r][_c] = piece.color[num]; 548 | } else { 549 | this.cells[_r][_c] = piece.color; 550 | } 551 | } 552 | 553 | } 554 | } 555 | }; 556 | 557 | Grid.prototype.valid = function(piece){ 558 | 559 | for(var r = 0; r < piece.cells.length; r++){ 560 | for(var c = 0; c < piece.cells[r].length; c++){ 561 | var _r = piece.row + r; 562 | var _c = piece.column + c; 563 | 564 | // TH: != 0 rather than == 1 565 | if (piece.cells[r][c] != 0){ 566 | if (!(_c < this.columns && _r < this.rows && this.cells[_r][_c] == 0)){ 567 | return false; 568 | } 569 | } 570 | } 571 | } 572 | return true; 573 | }; 574 | 575 | Grid.prototype.canMoveDown = function(piece){ 576 | for(var r = 0; r < piece.cells.length; r++){ 577 | for(var c = 0; c < piece.cells[r].length; c++){ 578 | var _r = piece.row + r + 1; 579 | var _c = piece.column + c; 580 | 581 | // TH: != 0 rather than == 1 582 | if (piece.cells[r][c] != 0 && _r >= 0){ 583 | 584 | if (!(_r < this.rows && this.cells[_r][_c] == 0)){ 585 | return false; 586 | } 587 | } 588 | } 589 | } 590 | return true; 591 | }; 592 | 593 | Grid.prototype.canMoveLeft = function(piece){ 594 | for(var r = 0; r < piece.cells.length; r++){ 595 | for(var c = 0; c < piece.cells[r].length; c++){ 596 | var _r = piece.row + r; 597 | var _c = piece.column + c - 1; 598 | 599 | // TH: != 0 rather than == 1 600 | if (piece.cells[r][c] != 0){ 601 | if (!(_c >= 0 && this.cells[_r][_c] == 0)){ 602 | return false; 603 | } 604 | } 605 | } 606 | } 607 | return true; 608 | }; 609 | 610 | Grid.prototype.canMoveRight = function(piece){ 611 | for(var r = 0; r < piece.cells.length; r++){ 612 | for(var c = 0; c < piece.cells[r].length; c++){ 613 | var _r = piece.row + r; 614 | var _c = piece.column + c + 1; 615 | 616 | // TH: != 0 rather than == 1 617 | if (piece.cells[r][c] != 0){ 618 | if (!(_c >= 0 && this.cells[_r][_c] == 0)){ 619 | return false; 620 | } 621 | } 622 | } 623 | } 624 | return true; 625 | }; 626 | 627 | Grid.prototype.rotateOffset = function(piece){ 628 | 629 | console.log("rotate?"); 630 | 631 | var _piece = piece.clone(); 632 | _piece.rotate(1); 633 | if (this.valid(_piece)) { 634 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 635 | } 636 | 637 | // Kicking 638 | var initialRow = _piece.row; 639 | var initialCol = _piece.column; 640 | 641 | for (var i = 0; i < _piece.dimension - 1; i++) { 642 | _piece.column = initialCol + i; 643 | if (this.valid(_piece)) { 644 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 645 | } 646 | 647 | for (var j = 0; j < _piece.dimension - 1; j++) { 648 | _piece.row = initialRow - j; 649 | if (this.valid(_piece)) { 650 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 651 | } 652 | } 653 | _piece.row = initialRow; 654 | } 655 | _piece.column = initialCol; 656 | 657 | for (var i = 0; i < _piece.dimension - 1; i++) { 658 | _piece.column = initialCol - i; 659 | if (this.valid(_piece)) { 660 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 661 | } 662 | 663 | for (var j = 0; j < _piece.dimension - 1; j++) { 664 | _piece.row = initialRow - j; 665 | if (this.valid(_piece)) { 666 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 667 | } 668 | } 669 | _piece.row = initialRow; 670 | } 671 | _piece.column = initialCol; 672 | 673 | return null; 674 | }; 675 | 676 | /** 677 | * Piece 678 | * - Represents a single piece on the board. 679 | */ 680 | 681 | // Object that represents a single piece & its properties. 682 | function Piece(cells, color){ 683 | this.cells = cells; 684 | this.dimension = this.cells.length; 685 | this.row = 0; 686 | this.column = 0; 687 | this.color = color; 688 | }; 689 | 690 | Piece.fromIndex = function(index, color){ 691 | 692 | var cells 693 | 694 | switch (index){ 695 | case 0:// O 696 | cells = [ 697 | [1, 1], 698 | [1, 1] 699 | ]; 700 | break; 701 | case 1: // J 702 | cells = [ 703 | [1, 0, 0], 704 | [1, 1, 1], 705 | [0, 0, 0] 706 | ]; 707 | break; 708 | case 2: // L 709 | cells = [ 710 | [0, 0, 1], 711 | [1, 1, 1], 712 | [0, 0, 0] 713 | ]; 714 | break; 715 | case 3: // Z 716 | cells = [ 717 | [1, 1, 0], 718 | [0, 1, 1], 719 | [0, 0, 0] 720 | ]; 721 | break; 722 | case 4: // S 723 | cells = [ 724 | [0, 1, 1], 725 | [1, 1, 0], 726 | [0, 0, 0] 727 | ]; 728 | break; 729 | case 5: // T 730 | cells = [ 731 | [0, 1, 0], 732 | [1, 1, 1], 733 | [0, 0, 0] 734 | ]; 735 | break; 736 | case 6: // I 737 | cells = [ 738 | [0, 0, 0, 0], 739 | [2, 3, 4, 5], 740 | [0, 0, 0, 0], 741 | [0, 0, 0, 0] 742 | ]; 743 | break; 744 | 745 | } 746 | 747 | var piece = new Piece(cells, color); 748 | 749 | piece.row = 0; 750 | piece.column = Math.floor((10 - piece.dimension) / 2); // Centralize 751 | return piece; 752 | }; 753 | 754 | Piece.prototype.clone = function(){ 755 | 756 | var _cells = new Array(this.dimension); 757 | for (var r = 0; r < this.dimension; r++) { 758 | _cells[r] = new Array(this.dimension); 759 | for(var c = 0; c < this.dimension; c++){ 760 | _cells[r][c] = this.cells[r][c]; 761 | } 762 | } 763 | 764 | var piece = new Piece(_cells, this.color); 765 | piece.row = this.row; 766 | piece.column = this.column; 767 | return piece; 768 | }; 769 | 770 | Piece.prototype.rotate = function(rotations){ 771 | for(var i = 0; i < rotations; i++) { 772 | var _cells = new Array(this.dimension); 773 | for (var r = 0; r < this.dimension; r++) { 774 | _cells[r] = new Array(this.dimension); 775 | } 776 | 777 | switch (this.dimension) { // Assumed square matrix 778 | case 2: 779 | _cells[0][0] = this.cells[1][0]; 780 | _cells[0][1] = this.cells[0][0]; 781 | _cells[1][0] = this.cells[1][1]; 782 | _cells[1][1] = this.cells[0][1]; 783 | break; 784 | case 3: 785 | _cells[0][0] = this.cells[2][0]; 786 | _cells[0][1] = this.cells[1][0]; 787 | _cells[0][2] = this.cells[0][0]; 788 | _cells[1][0] = this.cells[2][1]; 789 | _cells[1][1] = this.cells[1][1]; 790 | _cells[1][2] = this.cells[0][1]; 791 | _cells[2][0] = this.cells[2][2]; 792 | _cells[2][1] = this.cells[1][2]; 793 | _cells[2][2] = this.cells[0][2]; 794 | break; 795 | case 4: 796 | _cells[0][0] = this.cells[3][0]; 797 | _cells[0][1] = this.cells[2][0]; 798 | _cells[0][2] = this.cells[1][0]; 799 | _cells[0][3] = this.cells[0][0]; 800 | _cells[1][3] = this.cells[0][1]; 801 | _cells[2][3] = this.cells[0][2]; 802 | _cells[3][3] = this.cells[0][3]; 803 | _cells[3][2] = this.cells[1][3]; 804 | _cells[3][1] = this.cells[2][3]; 805 | _cells[3][0] = this.cells[3][3]; 806 | _cells[2][0] = this.cells[3][2]; 807 | _cells[1][0] = this.cells[3][1]; 808 | 809 | _cells[1][1] = this.cells[2][1]; 810 | _cells[1][2] = this.cells[1][1]; 811 | _cells[2][2] = this.cells[1][2]; 812 | _cells[2][1] = this.cells[2][2]; 813 | break; 814 | } 815 | 816 | this.cells = _cells; 817 | } 818 | }; 819 | 820 | /** 821 | * Game manager, manages flow and updating of game. 822 | */ 823 | 824 | function GameManager(){ 825 | 826 | this.gridCanvas = document.getElementById('grid-canvas'); 827 | 828 | this.gravityUpdater = new Updater(); 829 | 830 | this.gravityUpdater.onUpdate(function(){ 831 | self.applyGravity(); 832 | self.actuate(); 833 | }); 834 | 835 | var self = this; 836 | this.setup(); 837 | this.startAI(); 838 | this.gravityUpdater.checkUpdate(Date.now()); 839 | }; 840 | 841 | GameManager.prototype.setup = function(){ 842 | 843 | this.baseColumns = 8; 844 | 845 | this.pieceWidth = window.innerWidth / this.baseColumns; 846 | this.pieceHeight = this.pieceWidth; 847 | 848 | this.displacementWidth = Math.floor(this.pieceWidth / 4); 849 | 850 | var canvasHeightPieces = Math.ceil(window.innerHeight / this.pieceHeight) + 2; 851 | 852 | this.gridCanvas.width = window.innerWidth; 853 | this.gridCanvas.height = canvasHeightPieces * this.pieceHeight; 854 | 855 | this.grid = new Grid(canvasHeightPieces, this.baseColumns); 856 | this.rpg = new RandomPieceGenerator(); 857 | this.ai = new AI(0.510066, 0.760666, 0.35663, 0.184483); 858 | 859 | this.workingPieces = [this.rpg.nextPiece(), this.rpg.nextPiece()]; 860 | this.workingPiece = this.workingPieces[0]; 861 | 862 | this.isOver = true; 863 | 864 | this.stopAI(); 865 | this.actuate(); 866 | }; 867 | 868 | GameManager.prototype.actuate = function(){ 869 | 870 | var _grid = this.grid.clone(); 871 | 872 | if (this.workingPiece != null) { 873 | _grid.addPiece(this.workingPiece); 874 | } 875 | 876 | var context = this.gridCanvas.getContext('2d'); 877 | context.save(); 878 | 879 | context.clearRect(0, 0, this.gridCanvas.width, this.gridCanvas.height); 880 | 881 | for(var r = 2; r < _grid.rows; r++){ 882 | 883 | for(var c = 0; c < _grid.columns; c++){ 884 | 885 | if (_grid.cells[r][c] != 0){ 886 | 887 | 888 | // console.log(_grid.cells[r], _grid.cells[r][c]); 889 | _grid.cells[r][c](context, c, r, this.pieceWidth, this.pieceHeight); 890 | 891 | } 892 | } 893 | } 894 | 895 | context.restore(); 896 | }; 897 | 898 | GameManager.prototype.startAI = function(){ 899 | this.aiActive = true; 900 | }; 901 | 902 | GameManager.prototype.stopAI = function(){ 903 | this.aiActive = false; 904 | }; 905 | 906 | GameManager.prototype.setWorkingPiece = function(){ 907 | 908 | this.grid.addPiece(this.workingPiece); 909 | this.grid.clearLines(); 910 | 911 | if (!this.grid.exceeded()){ 912 | 913 | for(var i = 0; i < this.workingPieces.length - 1; i++){ 914 | this.workingPieces[i] = this.workingPieces[i + 1]; 915 | } 916 | 917 | this.workingPieces[this.workingPieces.length - 1] = this.rpg.nextPiece(); 918 | this.workingPiece = this.workingPieces[0]; 919 | 920 | if (this.aiActive) { 921 | this.aiMove(); 922 | } 923 | 924 | // I piece 925 | if( this.workingPiece.cells.length > 3) { 926 | 927 | if( this.workingPiece.cells[0][2] !== 0 ) { 928 | this.workingPiece.cells[0][2] = 6; 929 | this.workingPiece.cells[1][2] = 7; 930 | this.workingPiece.cells[2][2] = 8; 931 | this.workingPiece.cells[3][2] = 9; 932 | } 933 | } 934 | } 935 | 936 | // TODO: NO WAYYYY 937 | else{ 938 | 939 | } 940 | }; 941 | 942 | GameManager.prototype.applyGravity = function(){ 943 | 944 | if (this.grid.canMoveDown(this.workingPiece)) { 945 | this.workingPiece.row++; 946 | }else{ 947 | this.setWorkingPiece(); 948 | } 949 | 950 | }; 951 | 952 | GameManager.prototype.drop = function(){ 953 | while(this.grid.canMoveDown(this.workingPiece)){ 954 | this.workingPiece.row++; 955 | } 956 | }; 957 | 958 | GameManager.prototype.moveLeft = function(){ 959 | if (this.grid.canMoveLeft(this.workingPiece)){ 960 | this.workingPiece.column--; 961 | } 962 | }; 963 | 964 | GameManager.prototype.moveRight = function(){ 965 | if (this.grid.canMoveRight(this.workingPiece)){ 966 | this.workingPiece.column++; 967 | } 968 | }; 969 | 970 | GameManager.prototype.rotate = function(){ 971 | var offset = this.grid.rotateOffset(this.workingPiece); 972 | if (offset != null){ 973 | this.workingPiece.rotate(1); 974 | this.workingPiece.row += offset.rowOffset; 975 | this.workingPiece.column += offset.columnOffset; 976 | } 977 | }; 978 | 979 | GameManager.prototype.aiMove = function(){ 980 | this.workingPiece = this.ai.best(this.grid, this.workingPieces, 0).piece; 981 | }; 982 | 983 | function RandomPieceGenerator(){ 984 | Math.seed 985 | this.bag = [0, 1, 2, 3, 4, 5, 6]; 986 | this.shuffleBag(); 987 | this.index = -1; 988 | 989 | this.drawFunctions = new DrawFunctions(); 990 | }; 991 | 992 | RandomPieceGenerator.prototype.nextPiece = function(){ 993 | 994 | this.index++; 995 | if (this.index >= this.bag.length){ 996 | this.shuffleBag(); 997 | this.index = 0; 998 | } 999 | 1000 | return Piece.fromIndex(this.bag[this.index], this.drawFunctions.getDrawFunction(this.bag[this.index])); 1001 | 1002 | }; 1003 | 1004 | RandomPieceGenerator.prototype.shuffleBag = function() { 1005 | var currentIndex = this.bag.length 1006 | , temporaryValue 1007 | , randomIndex 1008 | ; 1009 | 1010 | // While there remain elements to shuffle... 1011 | while (0 !== currentIndex) { 1012 | 1013 | // Pick a remaining element... 1014 | randomIndex = Math.floor(Math.random() * currentIndex); 1015 | currentIndex -= 1; 1016 | 1017 | // And swap it with the current element. 1018 | temporaryValue = this.bag[currentIndex]; 1019 | this.bag[currentIndex] = this.bag[randomIndex]; 1020 | this.bag[randomIndex] = temporaryValue; 1021 | } 1022 | }; 1023 | function AI(heightWeight, linesWeight, holesWeight, bumpinessWeight){ 1024 | 1025 | this.heightWeight = heightWeight; 1026 | this.linesWeight = linesWeight; 1027 | this.holesWeight = holesWeight; 1028 | this.bumpinessWeight = bumpinessWeight; 1029 | 1030 | }; 1031 | 1032 | AI.prototype.best = function(grid, workingPieces, workingPieceIndex){ 1033 | 1034 | var best = null; 1035 | var bestScore = null; 1036 | var workingPiece = workingPieces[workingPieceIndex]; 1037 | 1038 | for(var rotation = 0; rotation < 4; rotation++){ 1039 | var _piece = workingPiece.clone(); 1040 | _piece.rotate(rotation); 1041 | 1042 | while(grid.canMoveLeft(_piece)){ 1043 | _piece.column --; 1044 | } 1045 | 1046 | while(grid.valid(_piece)){ 1047 | var _pieceSet = _piece.clone(); 1048 | while(grid.canMoveDown(_pieceSet)){ 1049 | _pieceSet.row++; 1050 | } 1051 | 1052 | var _grid = grid.clone(); 1053 | _grid.addPiece(_pieceSet); 1054 | 1055 | var score = null; 1056 | if (workingPieceIndex == (workingPieces.length - 1)) { 1057 | score = -this.heightWeight * _grid.aggregateHeight() + this.linesWeight * _grid.lines() - this.holesWeight * _grid.holes() - this.bumpinessWeight * _grid.bumpiness(); 1058 | }else{ 1059 | score = this.best(_grid, workingPieces, workingPieceIndex + 1).score; 1060 | } 1061 | 1062 | if (score > bestScore || bestScore == null){ 1063 | bestScore = score; 1064 | best = _piece.clone(); 1065 | } 1066 | 1067 | _piece.column++; 1068 | } 1069 | } 1070 | 1071 | return {piece:best, score:bestScore}; 1072 | }; 1073 | /** 1074 | * Updater, controls time and speed. 1075 | */ 1076 | 1077 | function Updater() { 1078 | this.lastUpdateTime = Date.now(); 1079 | this.deltaThreshold = 250; // MS before each update 1080 | this.updateCallback = null; 1081 | 1082 | window.requestAnimFrame = (function() { 1083 | // Polyfill 1084 | return ( 1085 | window.requestAnimationFrame || 1086 | window.webkitRequestAnimationFrame || 1087 | window.mozRequestAnimationFrame || 1088 | window.oRequestAnimationFrame || 1089 | window.msRequestAnimationFrame || 1090 | function(callback) { 1091 | window.setTimeout(callback, 1000 / 60); 1092 | } 1093 | ); 1094 | })(); 1095 | } 1096 | 1097 | Updater.prototype.onUpdate = function(callback) { 1098 | this.updateCallback = callback; 1099 | }; 1100 | 1101 | Updater.prototype.doUpdate = function(timestamp) { 1102 | if (this.updateCallback != null) { 1103 | this.updateCallback(); 1104 | } 1105 | 1106 | this.lastUpdateTime = timestamp; 1107 | }; 1108 | 1109 | Updater.prototype.checkUpdate = function(timestamp) { 1110 | var self = this; 1111 | var delta = timestamp - this.lastUpdateTime; 1112 | 1113 | if (delta > this.deltaThreshold) { 1114 | this.doUpdate(timestamp); 1115 | } 1116 | 1117 | window.requestAnimFrame(function() { 1118 | self.checkUpdate(Date.now()); 1119 | }); 1120 | }; 1121 | -------------------------------------------------------------------------------- /colored_classic/js/index.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | function square(context, x, y, width, height) { 4 | 5 | var unitWidth = 0.125 * width; 6 | 7 | // Border 8 | context.fillStyle = "#000"; 9 | context.fillRect(width * x, height * y, width, height); 10 | 11 | context.fillStyle = "#EDBF3B"; 12 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 13 | 14 | context.fillStyle = "#000"; 15 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, width - unitWidth * 4, height - unitWidth * 4); 16 | 17 | } 18 | 19 | function jay(context, x, y, width, height) { 20 | 21 | var unitWidth = 0.125 * width; 22 | 23 | // Border 24 | context.fillStyle = "#000"; 25 | context.fillRect(width * x, height * y, width, height); 26 | 27 | context.fillStyle = "#3B78A7"; 28 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 29 | 30 | context.fillStyle = "#000"; 31 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, width - unitWidth * 4, height - unitWidth * 4); 32 | 33 | context.fillStyle = "#fff"; 34 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 3, width - unitWidth * 6, height - unitWidth * 6); 35 | } 36 | 37 | function ell(context, x, y, width, height) { 38 | 39 | var unitWidth = 0.125 * width; 40 | 41 | context.fillStyle = "#000"; 42 | context.fillRect(width * x, height * y, width, height); 43 | 44 | context.fillStyle = "#B82C2D"; 45 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 46 | 47 | } 48 | 49 | function zee(context, x, y, width, height) { 50 | 51 | var unitWidth = 0.125 * width; 52 | 53 | context.fillStyle = "#000"; 54 | context.fillRect(width * x, height * y, width, height); 55 | 56 | context.fillStyle = "#EDBF3B"; 57 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 58 | 59 | context.fillStyle = "#000"; 60 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 3, width - unitWidth * 6, height - unitWidth * 6); 61 | 62 | } 63 | 64 | function ess(context, x, y, width, height) { 65 | 66 | var unitWidth = 0.125 * width; 67 | 68 | context.fillStyle = "#000"; 69 | context.fillRect(width * x, height * y, width, height); 70 | 71 | context.fillStyle = "#C24175"; 72 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 73 | 74 | context.fillStyle = "#000"; 75 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, width - unitWidth * 4, height - unitWidth * 4); 76 | 77 | context.fillStyle = "#fff"; 78 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 3, width - unitWidth * 6, height - unitWidth * 6); 79 | } 80 | 81 | function tee(context, x, y, width, height) { 82 | 83 | var unitWidth = 0.125 * width; 84 | 85 | context.fillStyle = "#000"; 86 | context.fillRect(width * x, height * y, width, height); 87 | 88 | context.fillStyle = "#498E4D"; 89 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth * 2); 90 | 91 | context.fillStyle = "#fff"; 92 | 93 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, unitWidth, height - unitWidth * 4); 94 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, unitWidth * 4, unitWidth); 95 | 96 | context.fillStyle = "#000"; 97 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 5, unitWidth * 4, unitWidth); 98 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 3, unitWidth, unitWidth * 3); 99 | 100 | } 101 | 102 | var eyes = [ 103 | //h1 104 | function(context, x, y, width, height) { 105 | 106 | var unitWidth = 0.125 * width; 107 | context.fillStyle = "#000"; 108 | context.fillRect(width * x, height * y, width, height); 109 | 110 | context.fillStyle = "#C28549"; 111 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth, height - unitWidth * 2); 112 | 113 | // Dots 114 | context.fillStyle = "#874437"; 115 | 116 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 1, unitWidth, unitWidth); 117 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 1, unitWidth, unitWidth); 118 | 119 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 3, unitWidth, unitWidth); 120 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 3, unitWidth, unitWidth); 121 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 3, unitWidth, unitWidth); 122 | 123 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 5, unitWidth, unitWidth); 124 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 5, unitWidth, unitWidth); 125 | 126 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 6, unitWidth, unitWidth); 127 | 128 | 129 | }, 130 | function(context, x, y, width, height) { 131 | 132 | var unitWidth = 0.125 * width; 133 | 134 | context.fillStyle = "#000"; 135 | context.fillRect(width * x, height * y, width, height); 136 | 137 | context.fillStyle = "#C28549"; 138 | context.fillRect(width * x, height * y + unitWidth, width, height - unitWidth * 2); 139 | 140 | // Dots 141 | context.fillStyle = "#874437"; 142 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 1, unitWidth, unitWidth); 143 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 1, unitWidth, unitWidth); 144 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 1, unitWidth, unitWidth); 145 | 146 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 147 | 148 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 3, unitWidth, unitWidth); 149 | 150 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 4, unitWidth, unitWidth); 151 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 4, unitWidth, unitWidth); 152 | 153 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 5, unitWidth, unitWidth); 154 | context.fillRect(width * x + unitWidth * 7, height * y + unitWidth * 5, unitWidth, unitWidth); 155 | 156 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 6, unitWidth, unitWidth); 157 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 6, unitWidth, unitWidth); 158 | 159 | 160 | }, 161 | function(context, x, y, width, height) { 162 | 163 | var unitWidth = 0.125 * width; 164 | 165 | context.fillStyle = "#000"; 166 | context.fillRect(width * x, height * y, width, height); 167 | 168 | context.fillStyle = "#C28549"; 169 | context.fillRect(width * x, height * y + unitWidth, width, height - unitWidth * 2); 170 | 171 | // Dots 172 | context.fillStyle = "#874437"; 173 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 1, unitWidth, unitWidth); 174 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 1, unitWidth, unitWidth); 175 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 1, unitWidth, unitWidth); 176 | 177 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 178 | 179 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 3, unitWidth, unitWidth); 180 | 181 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 4, unitWidth, unitWidth); 182 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 4, unitWidth, unitWidth); 183 | 184 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 5, unitWidth, unitWidth); 185 | context.fillRect(width * x + unitWidth * 7, height * y + unitWidth * 5, unitWidth, unitWidth); 186 | 187 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 6, unitWidth, unitWidth); 188 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 6, unitWidth, unitWidth); 189 | 190 | }, 191 | function(context, x, y, width, height) { 192 | 193 | var unitWidth = 0.125 * width; 194 | 195 | context.fillStyle = "#000"; 196 | context.fillRect(width * x, height * y, width, height); 197 | 198 | context.fillStyle = "#C28549"; 199 | context.fillRect(width * x, height * y + unitWidth, width - unitWidth, height - unitWidth * 2); 200 | 201 | // Dots 202 | context.fillStyle = "#874437"; 203 | context.fillRect(width * x + unitWidth * 0, height * y + unitWidth * 1, unitWidth, unitWidth); 204 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 1, unitWidth, unitWidth); 205 | 206 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, unitWidth, unitWidth); 207 | 208 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 3, unitWidth, unitWidth); 209 | 210 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 4, unitWidth, unitWidth); 211 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 4, unitWidth, unitWidth); 212 | 213 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 5, unitWidth, unitWidth); 214 | 215 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 6, unitWidth, unitWidth); 216 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 6, unitWidth, unitWidth); 217 | }, 218 | 219 | // v1 220 | function(context, x, y, width, height) { 221 | 222 | var unitWidth = 0.125 * width; 223 | context.fillStyle = "#000"; 224 | context.fillRect(width * x, height * y, width, height); 225 | 226 | context.fillStyle = "#C28549"; 227 | context.fillRect(width * x + unitWidth, height * y + unitWidth, width - unitWidth * 2, height - unitWidth); 228 | 229 | // Dots 230 | context.fillStyle = "#874437"; 231 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth, unitWidth, unitWidth); 232 | 233 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 2, unitWidth, unitWidth); 234 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 235 | 236 | context.fillRect(width * x + unitWidth, height * y + unitWidth * 4, unitWidth, unitWidth); 237 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 4, unitWidth, unitWidth); 238 | 239 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 5, unitWidth, unitWidth); 240 | 241 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 6, unitWidth, unitWidth); 242 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 6, unitWidth, unitWidth); 243 | 244 | }, 245 | function(context, x, y, width, height) { 246 | 247 | var unitWidth = 0.125 * width; 248 | 249 | context.fillStyle = "#000"; 250 | context.fillRect(width * x, height * y, width, height); 251 | 252 | context.fillStyle = "#C28549"; 253 | context.fillRect(width * x + unitWidth, height * y, width - unitWidth * 2, height); 254 | 255 | // Dots 256 | context.fillStyle = "#874437"; 257 | 258 | context.fillRect(width * x + unitWidth * 3, height * y, unitWidth, unitWidth); 259 | context.fillRect(width * x + unitWidth * 6, height * y, unitWidth, unitWidth); 260 | 261 | context.fillRect(width * x + unitWidth, height * y + unitWidth * 1, unitWidth, unitWidth); 262 | 263 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 2, unitWidth, unitWidth); 264 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 265 | 266 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 3, unitWidth, unitWidth); 267 | 268 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 4, unitWidth, unitWidth); 269 | 270 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 5, unitWidth, unitWidth); 271 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 5, unitWidth, unitWidth); 272 | 273 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 6, unitWidth, unitWidth); 274 | 275 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 7, unitWidth, unitWidth); 276 | 277 | }, 278 | function(context, x, y, width, height) { 279 | 280 | var unitWidth = 0.125 * width; 281 | 282 | context.fillStyle = "#000"; 283 | context.fillRect(width * x, height * y, width, height); 284 | 285 | context.fillStyle = "#C28549"; 286 | context.fillRect(width * x + unitWidth, height * y, width - unitWidth * 2, height); 287 | 288 | // Dots 289 | context.fillStyle = "#874437"; 290 | 291 | context.fillRect(width * x + unitWidth * 3, height * y, unitWidth, unitWidth); 292 | context.fillRect(width * x + unitWidth * 6, height * y, unitWidth, unitWidth); 293 | 294 | context.fillRect(width * x + unitWidth, height * y + unitWidth * 1, unitWidth, unitWidth); 295 | 296 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 2, unitWidth, unitWidth); 297 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 2, unitWidth, unitWidth); 298 | 299 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 3, unitWidth, unitWidth); 300 | 301 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 4, unitWidth, unitWidth); 302 | 303 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 5, unitWidth, unitWidth); 304 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 5, unitWidth, unitWidth); 305 | 306 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 6, unitWidth, unitWidth); 307 | 308 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 7, unitWidth, unitWidth); 309 | }, 310 | function(context, x, y, width, height) { 311 | 312 | var unitWidth = 0.125 * width; 313 | 314 | context.fillStyle = "#000"; 315 | context.fillRect(width * x, height * y, width, height); 316 | 317 | context.fillStyle = "#C28549"; 318 | context.fillRect(width * x + unitWidth, height * y, width - unitWidth * 2, height - unitWidth); 319 | 320 | // Dots 321 | context.fillStyle = "#874437"; 322 | 323 | context.fillRect(width * x + unitWidth * 6, height * y, unitWidth, unitWidth); 324 | 325 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 1, unitWidth, unitWidth); 326 | 327 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 2, unitWidth, unitWidth); 328 | context.fillRect(width * x + unitWidth * 5, height * y + unitWidth * 2, unitWidth, unitWidth); 329 | 330 | context.fillRect(width * x + unitWidth * 3, height * y + unitWidth * 3, unitWidth, unitWidth); 331 | 332 | context.fillRect(width * x + unitWidth * 1, height * y + unitWidth * 4, unitWidth, unitWidth); 333 | context.fillRect(width * x + unitWidth * 6, height * y + unitWidth * 4, unitWidth, unitWidth); 334 | 335 | context.fillRect(width * x + unitWidth * 4, height * y + unitWidth * 5, unitWidth, unitWidth); 336 | 337 | context.fillRect(width * x + unitWidth * 2, height * y + unitWidth * 6, unitWidth, unitWidth); 338 | } 339 | ] 340 | 341 | var drawFunctions = [ 342 | 343 | square, 344 | 345 | jay, 346 | 347 | ell, 348 | 349 | zee, 350 | 351 | ess, 352 | 353 | tee, 354 | 355 | eyes 356 | 357 | ] 358 | 359 | function DrawFunctions(){}; 360 | 361 | DrawFunctions.prototype.getDrawFunction = function(index){ 362 | 363 | if( drawFunctions[index]) { 364 | return drawFunctions[index]; 365 | } else { 366 | return drawFunctions[5]; 367 | } 368 | } 369 | /** 370 | * Grid 371 | * - Manages the state of the grid 372 | */ 373 | 374 | // Init 375 | function Grid(rows, columns){ 376 | 377 | this.rows = rows; 378 | this.columns = columns; 379 | this.cells = new Array(rows); 380 | 381 | // For each row! 382 | // Has a column 383 | // Which has X cells in it. 384 | for (var r = 0; r < this.rows; r++) { 385 | 386 | this.cells[r] = new Array(this.columns); 387 | for(var c = 0; c < this.columns; c++){ 388 | this.cells[r][c] = 0; 389 | } 390 | } 391 | 392 | }; 393 | 394 | // Methods 395 | Grid.prototype.clone = function(){ 396 | var _grid = new Grid(this.rows, this.columns); 397 | for (var r = 0; r < this.rows; r++) { 398 | for(var c = 0; c < this.columns; c++){ 399 | _grid.cells[r][c] = this.cells[r][c]; 400 | } 401 | } 402 | return _grid; 403 | }; 404 | 405 | // Clear spaces in the grid, including when the blocks "fall" 406 | Grid.prototype.clearLines = function(){ 407 | 408 | var distance = 0; 409 | var row = new Array(this.columns); 410 | 411 | for(var r = this.rows - 1; r >= 0; r--){ 412 | 413 | // Clear full line 414 | if (this.isLine(r)){ 415 | 416 | distance++; 417 | for(var c = 0; c < this.columns; c++){ 418 | this.cells[r][c] = 0; 419 | } 420 | 421 | // Clear moved spaces 422 | } else if (distance > 0) { 423 | 424 | for(var c = 0; c < this.columns; c++){ 425 | this.cells[r + distance][c] = this.cells[r][c]; 426 | this.cells[r][c] = 0; 427 | } 428 | } 429 | } 430 | }; 431 | 432 | // If every item in the row has an item! 433 | Grid.prototype.isLine = function(row){ 434 | for(var c = 0; c < this.columns; c++){ 435 | if (this.cells[row][c] == 0){ 436 | return false; 437 | } 438 | } 439 | return true; 440 | }; 441 | 442 | Grid.prototype.isEmptyRow = function(row){ 443 | for(var c = 0; c < this.columns; c++){ 444 | 445 | // TH: != 0 rather than == 1 446 | if (this.cells[row][c] != 0){ 447 | return false; 448 | } 449 | } 450 | return true; 451 | }; 452 | 453 | Grid.prototype.exceeded = function(){ 454 | return !this.isEmptyRow(0) || !this.isEmptyRow(1); 455 | }; 456 | 457 | Grid.prototype.height = function(){ 458 | var r = 0; 459 | for(; r < this.rows && this.isEmptyRow(r); r++); 460 | return this.rows - r; 461 | }; 462 | 463 | Grid.prototype.lines = function(){ 464 | var count = 0; 465 | for(var r = 0; r < this.rows; r++){ 466 | if (this.isLine(r)){ 467 | count++; 468 | } 469 | } 470 | return count; 471 | }; 472 | 473 | Grid.prototype.holes = function(){ 474 | var count = 0; 475 | 476 | for(var c = 0; c < this.columns; c++){ 477 | var block = false; 478 | for(var r = 0; r < this.rows; r++){ 479 | 480 | // TH: != 0 rather than == 1 481 | if (this.cells[r][c] != 0) { 482 | block = true; 483 | }else if (this.cells[r][c] == 0 && block){ 484 | count++; 485 | } 486 | } 487 | } 488 | return count; 489 | }; 490 | 491 | Grid.prototype.blockades = function(){ 492 | var count = 0; 493 | 494 | for(var c = 0; c < this.columns; c++){ 495 | var hole = false; 496 | for(var r = this.rows - 1; r >= 0; r--){ 497 | if (this.cells[r][c] == 0){ 498 | hole = true; 499 | 500 | // TH: != 0 rather than == 1 501 | }else if (this.cells[r][c] != 0 && hole){ 502 | count++; 503 | } 504 | } 505 | } 506 | return count; 507 | } 508 | 509 | Grid.prototype.aggregateHeight = function(){ 510 | var total = 0; 511 | 512 | for(var c = 0; c < this.columns; c++){ 513 | total += this.columnHeight(c); 514 | } 515 | return total; 516 | }; 517 | 518 | Grid.prototype.bumpiness = function(){ 519 | var total = 0; 520 | for(var c = 0; c < this.columns - 1; c++){ 521 | total += Math.abs(this.columnHeight(c) - this.columnHeight(c+ 1)); 522 | } 523 | return total; 524 | } 525 | 526 | Grid.prototype.columnHeight = function(column){ 527 | var r = 0; 528 | 529 | for(; r < this.rows && this.cells[r][column] == 0; r++); 530 | return this.rows - r; 531 | }; 532 | 533 | // Piece 534 | Grid.prototype.addPiece = function(piece) { 535 | 536 | for(var r = 0; r < piece.cells.length; r++) { 537 | for (var c = 0; c < piece.cells[r].length; c++) { 538 | 539 | var _r = piece.row + r; 540 | var _c = piece.column + c; 541 | 542 | // TH: != 0 rather than == 1 543 | if (piece.cells[r][c] != 0 && _r >= 0){ 544 | 545 | // TH: Updates color, rather than 1 546 | if (piece.cells[r][c] > 1) { 547 | var num = piece.cells[r][c] - 2; 548 | this.cells[_r][_c] = piece.color[num]; 549 | } else { 550 | this.cells[_r][_c] = piece.color; 551 | } 552 | } 553 | 554 | } 555 | } 556 | }; 557 | 558 | Grid.prototype.valid = function(piece){ 559 | 560 | for(var r = 0; r < piece.cells.length; r++){ 561 | for(var c = 0; c < piece.cells[r].length; c++){ 562 | var _r = piece.row + r; 563 | var _c = piece.column + c; 564 | 565 | // TH: != 0 rather than == 1 566 | if (piece.cells[r][c] != 0){ 567 | if (!(_c < this.columns && _r < this.rows && this.cells[_r][_c] == 0)){ 568 | return false; 569 | } 570 | } 571 | } 572 | } 573 | return true; 574 | }; 575 | 576 | Grid.prototype.canMoveDown = function(piece){ 577 | for(var r = 0; r < piece.cells.length; r++){ 578 | for(var c = 0; c < piece.cells[r].length; c++){ 579 | var _r = piece.row + r + 1; 580 | var _c = piece.column + c; 581 | 582 | // TH: != 0 rather than == 1 583 | if (piece.cells[r][c] != 0 && _r >= 0){ 584 | 585 | if (!(_r < this.rows && this.cells[_r][_c] == 0)){ 586 | return false; 587 | } 588 | } 589 | } 590 | } 591 | return true; 592 | }; 593 | 594 | Grid.prototype.canMoveLeft = function(piece){ 595 | for(var r = 0; r < piece.cells.length; r++){ 596 | for(var c = 0; c < piece.cells[r].length; c++){ 597 | var _r = piece.row + r; 598 | var _c = piece.column + c - 1; 599 | 600 | // TH: != 0 rather than == 1 601 | if (piece.cells[r][c] != 0){ 602 | if (!(_c >= 0 && this.cells[_r][_c] == 0)){ 603 | return false; 604 | } 605 | } 606 | } 607 | } 608 | return true; 609 | }; 610 | 611 | Grid.prototype.canMoveRight = function(piece){ 612 | for(var r = 0; r < piece.cells.length; r++){ 613 | for(var c = 0; c < piece.cells[r].length; c++){ 614 | var _r = piece.row + r; 615 | var _c = piece.column + c + 1; 616 | 617 | // TH: != 0 rather than == 1 618 | if (piece.cells[r][c] != 0){ 619 | if (!(_c >= 0 && this.cells[_r][_c] == 0)){ 620 | return false; 621 | } 622 | } 623 | } 624 | } 625 | return true; 626 | }; 627 | 628 | Grid.prototype.rotateOffset = function(piece){ 629 | 630 | console.log("rotate?"); 631 | 632 | var _piece = piece.clone(); 633 | _piece.rotate(1); 634 | if (this.valid(_piece)) { 635 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 636 | } 637 | 638 | // Kicking 639 | var initialRow = _piece.row; 640 | var initialCol = _piece.column; 641 | 642 | for (var i = 0; i < _piece.dimension - 1; i++) { 643 | _piece.column = initialCol + i; 644 | if (this.valid(_piece)) { 645 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 646 | } 647 | 648 | for (var j = 0; j < _piece.dimension - 1; j++) { 649 | _piece.row = initialRow - j; 650 | if (this.valid(_piece)) { 651 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 652 | } 653 | } 654 | _piece.row = initialRow; 655 | } 656 | _piece.column = initialCol; 657 | 658 | for (var i = 0; i < _piece.dimension - 1; i++) { 659 | _piece.column = initialCol - i; 660 | if (this.valid(_piece)) { 661 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 662 | } 663 | 664 | for (var j = 0; j < _piece.dimension - 1; j++) { 665 | _piece.row = initialRow - j; 666 | if (this.valid(_piece)) { 667 | return {rowOffset: _piece.row - piece.row, columnOffset:_piece.column - piece.column}; 668 | } 669 | } 670 | _piece.row = initialRow; 671 | } 672 | _piece.column = initialCol; 673 | 674 | return null; 675 | }; 676 | 677 | /** 678 | * Piece 679 | * - Represents a single piece on the board. 680 | */ 681 | 682 | // Object that represents a single piece & its properties. 683 | function Piece(cells, color){ 684 | this.cells = cells; 685 | this.dimension = this.cells.length; 686 | this.row = 0; 687 | this.column = 0; 688 | this.color = color; 689 | }; 690 | 691 | Piece.fromIndex = function(index, color){ 692 | 693 | var cells 694 | 695 | switch (index){ 696 | case 0:// O 697 | cells = [ 698 | [1, 1], 699 | [1, 1] 700 | ]; 701 | break; 702 | case 1: // J 703 | cells = [ 704 | [1, 0, 0], 705 | [1, 1, 1], 706 | [0, 0, 0] 707 | ]; 708 | break; 709 | case 2: // L 710 | cells = [ 711 | [0, 0, 1], 712 | [1, 1, 1], 713 | [0, 0, 0] 714 | ]; 715 | break; 716 | case 3: // Z 717 | cells = [ 718 | [1, 1, 0], 719 | [0, 1, 1], 720 | [0, 0, 0] 721 | ]; 722 | break; 723 | case 4: // S 724 | cells = [ 725 | [0, 1, 1], 726 | [1, 1, 0], 727 | [0, 0, 0] 728 | ]; 729 | break; 730 | case 5: // T 731 | cells = [ 732 | [0, 1, 0], 733 | [1, 1, 1], 734 | [0, 0, 0] 735 | ]; 736 | break; 737 | case 6: // I 738 | cells = [ 739 | [0, 0, 0, 0], 740 | [2, 3, 4, 5], 741 | [0, 0, 0, 0], 742 | [0, 0, 0, 0] 743 | ]; 744 | break; 745 | 746 | } 747 | 748 | var piece = new Piece(cells, color); 749 | 750 | piece.row = 0; 751 | piece.column = Math.floor((10 - piece.dimension) / 2); // Centralize 752 | return piece; 753 | }; 754 | 755 | Piece.prototype.clone = function(){ 756 | 757 | var _cells = new Array(this.dimension); 758 | for (var r = 0; r < this.dimension; r++) { 759 | _cells[r] = new Array(this.dimension); 760 | for(var c = 0; c < this.dimension; c++){ 761 | _cells[r][c] = this.cells[r][c]; 762 | } 763 | } 764 | 765 | var piece = new Piece(_cells, this.color); 766 | piece.row = this.row; 767 | piece.column = this.column; 768 | return piece; 769 | }; 770 | 771 | Piece.prototype.rotate = function(rotations){ 772 | for(var i = 0; i < rotations; i++) { 773 | var _cells = new Array(this.dimension); 774 | for (var r = 0; r < this.dimension; r++) { 775 | _cells[r] = new Array(this.dimension); 776 | } 777 | 778 | switch (this.dimension) { // Assumed square matrix 779 | case 2: 780 | _cells[0][0] = this.cells[1][0]; 781 | _cells[0][1] = this.cells[0][0]; 782 | _cells[1][0] = this.cells[1][1]; 783 | _cells[1][1] = this.cells[0][1]; 784 | break; 785 | case 3: 786 | _cells[0][0] = this.cells[2][0]; 787 | _cells[0][1] = this.cells[1][0]; 788 | _cells[0][2] = this.cells[0][0]; 789 | _cells[1][0] = this.cells[2][1]; 790 | _cells[1][1] = this.cells[1][1]; 791 | _cells[1][2] = this.cells[0][1]; 792 | _cells[2][0] = this.cells[2][2]; 793 | _cells[2][1] = this.cells[1][2]; 794 | _cells[2][2] = this.cells[0][2]; 795 | break; 796 | case 4: 797 | _cells[0][0] = this.cells[3][0]; 798 | _cells[0][1] = this.cells[2][0]; 799 | _cells[0][2] = this.cells[1][0]; 800 | _cells[0][3] = this.cells[0][0]; 801 | _cells[1][3] = this.cells[0][1]; 802 | _cells[2][3] = this.cells[0][2]; 803 | _cells[3][3] = this.cells[0][3]; 804 | _cells[3][2] = this.cells[1][3]; 805 | _cells[3][1] = this.cells[2][3]; 806 | _cells[3][0] = this.cells[3][3]; 807 | _cells[2][0] = this.cells[3][2]; 808 | _cells[1][0] = this.cells[3][1]; 809 | 810 | _cells[1][1] = this.cells[2][1]; 811 | _cells[1][2] = this.cells[1][1]; 812 | _cells[2][2] = this.cells[1][2]; 813 | _cells[2][1] = this.cells[2][2]; 814 | break; 815 | } 816 | 817 | this.cells = _cells; 818 | } 819 | }; 820 | 821 | /** 822 | * Game manager, manages flow and updating of game. 823 | */ 824 | 825 | function GameManager(){ 826 | 827 | this.gridCanvas = document.getElementById('grid-canvas'); 828 | 829 | this.gravityUpdater = new Updater(); 830 | 831 | this.gravityUpdater.onUpdate(function(){ 832 | self.applyGravity(); 833 | self.actuate(); 834 | }); 835 | 836 | var self = this; 837 | this.setup(); 838 | this.startAI(); 839 | this.gravityUpdater.checkUpdate(Date.now()); 840 | }; 841 | 842 | GameManager.prototype.setup = function(){ 843 | 844 | this.baseColumns = 8; 845 | 846 | this.pieceWidth = window.innerWidth / this.baseColumns; 847 | this.pieceHeight = this.pieceWidth; 848 | 849 | this.displacementWidth = Math.floor(this.pieceWidth / 4); 850 | 851 | var canvasHeightPieces = Math.ceil(window.innerHeight / this.pieceHeight) + 2; 852 | 853 | this.gridCanvas.width = window.innerWidth; 854 | this.gridCanvas.height = canvasHeightPieces * this.pieceHeight; 855 | 856 | this.grid = new Grid(canvasHeightPieces, this.baseColumns); 857 | this.rpg = new RandomPieceGenerator(); 858 | this.ai = new AI(0.510066, 0.760666, 0.35663, 0.184483); 859 | 860 | this.workingPieces = [this.rpg.nextPiece(), this.rpg.nextPiece()]; 861 | this.workingPiece = this.workingPieces[0]; 862 | 863 | this.isOver = true; 864 | 865 | this.stopAI(); 866 | this.actuate(); 867 | }; 868 | 869 | GameManager.prototype.actuate = function(){ 870 | 871 | var _grid = this.grid.clone(); 872 | 873 | if (this.workingPiece != null) { 874 | _grid.addPiece(this.workingPiece); 875 | } 876 | 877 | var context = this.gridCanvas.getContext('2d'); 878 | context.save(); 879 | 880 | context.clearRect(0, 0, this.gridCanvas.width, this.gridCanvas.height); 881 | 882 | for(var r = 2; r < _grid.rows; r++){ 883 | 884 | for(var c = 0; c < _grid.columns; c++){ 885 | 886 | if (_grid.cells[r][c] != 0){ 887 | 888 | 889 | // console.log(_grid.cells[r], _grid.cells[r][c]); 890 | _grid.cells[r][c](context, c, r, this.pieceWidth, this.pieceHeight); 891 | 892 | } 893 | } 894 | } 895 | 896 | context.restore(); 897 | }; 898 | 899 | GameManager.prototype.startAI = function(){ 900 | this.aiActive = true; 901 | }; 902 | 903 | GameManager.prototype.stopAI = function(){ 904 | this.aiActive = false; 905 | }; 906 | 907 | GameManager.prototype.setWorkingPiece = function(){ 908 | 909 | this.grid.addPiece(this.workingPiece); 910 | this.grid.clearLines(); 911 | 912 | if (!this.grid.exceeded()){ 913 | 914 | for(var i = 0; i < this.workingPieces.length - 1; i++){ 915 | this.workingPieces[i] = this.workingPieces[i + 1]; 916 | } 917 | 918 | this.workingPieces[this.workingPieces.length - 1] = this.rpg.nextPiece(); 919 | this.workingPiece = this.workingPieces[0]; 920 | 921 | if (this.aiActive) { 922 | this.aiMove(); 923 | } 924 | 925 | // I piece 926 | if( this.workingPiece.cells.length > 3) { 927 | 928 | if( this.workingPiece.cells[0][2] !== 0 ) { 929 | this.workingPiece.cells[0][2] = 6; 930 | this.workingPiece.cells[1][2] = 7; 931 | this.workingPiece.cells[2][2] = 8; 932 | this.workingPiece.cells[3][2] = 9; 933 | } 934 | } 935 | } 936 | 937 | // TODO: NO WAYYYY 938 | else{ 939 | 940 | } 941 | }; 942 | 943 | GameManager.prototype.applyGravity = function(){ 944 | 945 | if (this.grid.canMoveDown(this.workingPiece)) { 946 | this.workingPiece.row++; 947 | }else{ 948 | this.setWorkingPiece(); 949 | } 950 | 951 | }; 952 | 953 | GameManager.prototype.drop = function(){ 954 | while(this.grid.canMoveDown(this.workingPiece)){ 955 | this.workingPiece.row++; 956 | } 957 | }; 958 | 959 | GameManager.prototype.moveLeft = function(){ 960 | if (this.grid.canMoveLeft(this.workingPiece)){ 961 | this.workingPiece.column--; 962 | } 963 | }; 964 | 965 | GameManager.prototype.moveRight = function(){ 966 | if (this.grid.canMoveRight(this.workingPiece)){ 967 | this.workingPiece.column++; 968 | } 969 | }; 970 | 971 | GameManager.prototype.rotate = function(){ 972 | var offset = this.grid.rotateOffset(this.workingPiece); 973 | if (offset != null){ 974 | this.workingPiece.rotate(1); 975 | this.workingPiece.row += offset.rowOffset; 976 | this.workingPiece.column += offset.columnOffset; 977 | } 978 | }; 979 | 980 | GameManager.prototype.aiMove = function(){ 981 | this.workingPiece = this.ai.best(this.grid, this.workingPieces, 0).piece; 982 | }; 983 | 984 | function RandomPieceGenerator(){ 985 | Math.seed 986 | this.bag = [0, 1, 2, 3, 4, 5, 6]; 987 | this.shuffleBag(); 988 | this.index = -1; 989 | 990 | this.drawFunctions = new DrawFunctions(); 991 | }; 992 | 993 | RandomPieceGenerator.prototype.nextPiece = function(){ 994 | 995 | this.index++; 996 | if (this.index >= this.bag.length){ 997 | this.shuffleBag(); 998 | this.index = 0; 999 | } 1000 | 1001 | return Piece.fromIndex(this.bag[this.index], this.drawFunctions.getDrawFunction(this.bag[this.index])); 1002 | 1003 | }; 1004 | 1005 | RandomPieceGenerator.prototype.shuffleBag = function() { 1006 | var currentIndex = this.bag.length 1007 | , temporaryValue 1008 | , randomIndex 1009 | ; 1010 | 1011 | // While there remain elements to shuffle... 1012 | while (0 !== currentIndex) { 1013 | 1014 | // Pick a remaining element... 1015 | randomIndex = Math.floor(Math.random() * currentIndex); 1016 | currentIndex -= 1; 1017 | 1018 | // And swap it with the current element. 1019 | temporaryValue = this.bag[currentIndex]; 1020 | this.bag[currentIndex] = this.bag[randomIndex]; 1021 | this.bag[randomIndex] = temporaryValue; 1022 | } 1023 | }; 1024 | function AI(heightWeight, linesWeight, holesWeight, bumpinessWeight){ 1025 | 1026 | this.heightWeight = heightWeight; 1027 | this.linesWeight = linesWeight; 1028 | this.holesWeight = holesWeight; 1029 | this.bumpinessWeight = bumpinessWeight; 1030 | 1031 | }; 1032 | 1033 | AI.prototype.best = function(grid, workingPieces, workingPieceIndex){ 1034 | 1035 | var best = null; 1036 | var bestScore = null; 1037 | var workingPiece = workingPieces[workingPieceIndex]; 1038 | 1039 | for(var rotation = 0; rotation < 4; rotation++){ 1040 | var _piece = workingPiece.clone(); 1041 | _piece.rotate(rotation); 1042 | 1043 | while(grid.canMoveLeft(_piece)){ 1044 | _piece.column --; 1045 | } 1046 | 1047 | while(grid.valid(_piece)){ 1048 | var _pieceSet = _piece.clone(); 1049 | while(grid.canMoveDown(_pieceSet)){ 1050 | _pieceSet.row++; 1051 | } 1052 | 1053 | var _grid = grid.clone(); 1054 | _grid.addPiece(_pieceSet); 1055 | 1056 | var score = null; 1057 | if (workingPieceIndex == (workingPieces.length - 1)) { 1058 | score = -this.heightWeight * _grid.aggregateHeight() + this.linesWeight * _grid.lines() - this.holesWeight * _grid.holes() - this.bumpinessWeight * _grid.bumpiness(); 1059 | }else{ 1060 | score = this.best(_grid, workingPieces, workingPieceIndex + 1).score; 1061 | } 1062 | 1063 | if (score > bestScore || bestScore == null){ 1064 | bestScore = score; 1065 | best = _piece.clone(); 1066 | } 1067 | 1068 | _piece.column++; 1069 | } 1070 | } 1071 | 1072 | return {piece:best, score:bestScore}; 1073 | }; 1074 | /** 1075 | * Updater, controls time and speed. 1076 | */ 1077 | 1078 | function Updater() { 1079 | this.lastUpdateTime = Date.now(); 1080 | this.deltaThreshold = 250; // MS before each update 1081 | this.updateCallback = null; 1082 | 1083 | window.requestAnimFrame = (function() { 1084 | // Polyfill 1085 | return ( 1086 | window.requestAnimationFrame || 1087 | window.webkitRequestAnimationFrame || 1088 | window.mozRequestAnimationFrame || 1089 | window.oRequestAnimationFrame || 1090 | window.msRequestAnimationFrame || 1091 | function(callback) { 1092 | window.setTimeout(callback, 1000 / 60); 1093 | } 1094 | ); 1095 | })(); 1096 | } 1097 | 1098 | Updater.prototype.onUpdate = function(callback) { 1099 | this.updateCallback = callback; 1100 | }; 1101 | 1102 | Updater.prototype.doUpdate = function(timestamp) { 1103 | if (this.updateCallback != null) { 1104 | this.updateCallback(); 1105 | } 1106 | 1107 | this.lastUpdateTime = timestamp; 1108 | }; 1109 | 1110 | Updater.prototype.checkUpdate = function(timestamp) { 1111 | var self = this; 1112 | var delta = timestamp - this.lastUpdateTime; 1113 | 1114 | if (delta > this.deltaThreshold) { 1115 | this.doUpdate(timestamp); 1116 | } 1117 | 1118 | window.requestAnimFrame(function() { 1119 | self.checkUpdate(Date.now()); 1120 | }); 1121 | }; 1122 | --------------------------------------------------------------------------------