policychanges/src/shapes.js

452 lines
8.9 KiB
JavaScript

var consts = require('./consts.js');
var COLORS = consts.COLORS;
var COLUMN_COUNT = consts.COLUMN_COUNT;
/**
Defined all shapes used in Tetris game.
You can add more shapes if you wish.
*/
function ShapeL() {
var state1 = [
[1, 0],
[1, 0],
[1, 1]
];
var state2 = [
[0, 0, 1],
[1, 1, 1]
];
var state3 = [
[1, 1],
[0, 1],
[0, 1]
];
var state4 = [
[1, 1, 1],
[1, 0, 0]
];
this.states = [state1, state2, state3, state4];
this.x = 4;
this.y = -3;
this.originY = -3;
this.flag = 'L';
}
function ShapeLR() {
var state1 = [
[0, 1],
[0, 1],
[1, 1]
];
var state2 = [
[1, 1, 1],
[0, 0, 1]
];
var state3 = [
[1, 1],
[1, 0],
[1, 0]
];
var state4 = [
[1, 0, 0],
[1, 1, 1]
];
this.states = [state1, state2, state3, state4];
this.x = 4;
this.y = -3;
this.originY = -3;
this.flag = 'LR';
}
function ShapeO() {
var state1 = [
[1, 1],
[1, 1]
];
this.states = [state1];
this.x = 4;
this.y = -2;
this.originY = -2;
this.flag = 'O';
}
function ShapeI() {
var state1 = [
[1],
[1],
[1],
[1]
];
var state2 = [
[1, 1, 1, 1]
];
this.states = [state1, state2];
this.x = 5;
this.y = -4;
this.originY = -4;
this.flag = 'I';
}
function ShapeT() {
var state1 = [
[1, 1, 1],
[0, 1, 0]
];
var state2 = [
[1, 0],
[1, 1],
[1, 0]
];
var state3 = [
[0, 1, 0],
[1, 1, 1]
];
var state4 = [
[0, 1],
[1, 1],
[0, 1]
];
this.states = [state1, state2, state3, state4];
this.x = 4;
this.y = -2;
this.originY = -2;
this.flag = 'T';
}
function ShapeZ() {
var state1 = [
[1, 1, 0],
[0, 1, 1]
];
var state2 = [
[0, 1],
[1, 1],
[1, 0]
];
this.states = [state1, state2];
this.x = 4;
this.y = -2;
this.originY = -2;
this.flag = 'Z';
}
function ShapeZR() {
var state1 = [
[0, 1, 1],
[1, 1, 0]
];
var state2 = [
[1, 0],
[1, 1],
[0, 1]
];
this.states = [state1, state2];
this.x = 4;
this.y = -2
this.originY = -2;
this.flag = 'ZR';
}
/**
Is shape can move
@param shape: tetris shape
@param matrix: game matrix
@param action: 'left','right','down','rotate'
*/
var isShapeCanMove = function(shape, matrix, action) {
var rows = matrix.length;
var cols = matrix[0].length;
var rotationDirection = 0;
var isBoxCanMove = function(box) {
var x = shape.x + box.x;
var y = shape.y + box.y;
if (y < 0) {
return true;
}
if (action === 'left') {
x -= 1;
return x >= 0 && x < cols && matrix[y][x] == 0;
} else if (action === 'right') {
x += 1;
return x >= 0 && x < cols && matrix[y][x] == 0;
} else if (action === 'down') {
y += 1;
return y < rows && matrix[y][x] == 0;
} else if (action === 'rotate') {
rotationDirection = 1;
return y < rows && !matrix[y][x];
} else if (action === 'rotateclockwise') {
rotationDirection = -1;
return y < rows && !matrix[y][x];
}
};
//var boxes = action === 'rotate'?shape.getBoxes(shape.nextState()) : shape.getBoxes(shape.state);
var boxes;
if(rotationDirection != 0)
boxes = shape.getBoxes(shape.nextState(rotationDirection));
else
boxes = shape.getBoxes(shape.state);
for (var i in boxes) {
if (!isBoxCanMove(boxes[i])) {
return false;
}
}
return true;
};
/**
All shapes shares the same method, use prototype for memory optimized
*/
ShapeL.prototype =
ShapeLR.prototype =
ShapeO.prototype =
ShapeI.prototype =
ShapeT.prototype =
ShapeZ.prototype =
ShapeZR.prototype = {
init: function(result) {
this.color = COLORS[result];
this.state = 0;
this.allBoxes = {};
this.y = 0;
},
// Get boxes matrix which composite the shape
getBoxes: function(state) {
var boxes = this.allBoxes[state] || [];
if (boxes.length) {
return boxes;
}
var matrix = this.matrix(state);
for (var i = 0; i < matrix.length; i++) {
var row = matrix[i];
for (var j = 0; j < row.length; j++) {
if (row[j] === 1) {
boxes.push({
x: j,
y: i
});
}
}
}
this.allBoxes[state] = boxes;
return boxes;
},
//Get matrix for specified state
matrix: function(state) {
var st = state !== undefined ? state : this.state;
return this.states[st];
},
//Rotate shape
rotate: function(matrix) {
if (isShapeCanMove(this,matrix,'rotate')){
this.state = this.nextState(1);
//fix position if shape is out of right border
var right = this.getRight();
if ( right >= COLUMN_COUNT){
this.x -= right - COLUMN_COUNT + 1;
}
/*var left = this.getLeft();
if(left <= 0)
this.x += 1;*/
}
},
//Rotate shape clockwise
rotateClockwise: function(matrix) {
if (isShapeCanMove(this, matrix, 'rotateclockwise')) {
this.state = this.nextState(-1);
//fix position if shape is out of right border
var right = this.getRight();
if (right >= COLUMN_COUNT) {
this.x -= right - COLUMN_COUNT + 1;
}
}
},
//Caculate the max column of the shape
getColumnCount: function() {
var mtx = this.matrix();
var colCount = 0;
for (var i = 0; i < mtx.length; i++) {
colCount = Math.max(colCount, mtx[i].length);
}
return colCount;
},
//Caculate the max row of the shape
getRowCount: function() {
return this.matrix().length;
},
//Get the right pos of the shape
getRight: function() {
var boxes = this.getBoxes(this.state);
var right = 0;
for (var i in boxes) {
right = Math.max(boxes[i].x, right);
}
return this.x + right;
},
//Return the next state of the shape
nextState: function(direction) {
var rotate = this.state;
rotate += direction;
if(rotate < 0)
return this.states.length - 1;
return rotate % this.states.length;
},
//Check if the shape can move down
canDown: function(matrix) {
return isShapeCanMove(this, matrix, 'down');
},
//Move the shape down
goDown: function(matrix) {
if (isShapeCanMove(this, matrix, 'down')) {
this.y += 1;
}
},
//Move the shape to the Bottommost
bottomAt: function(matrix) {
var save = this.y;
var ret;
while (isShapeCanMove(this, matrix, 'down')) {
this.y += 1;
}
ret = this.y;
this.y = save;
return ret;
},
//Move the shape to the Bottommost
goBottom: function(matrix) {
while (isShapeCanMove(this, matrix, 'down')) {
this.y += 1;
}
},
//Move the shape to the left
goLeft: function(matrix) {
if (isShapeCanMove(this, matrix, 'left')) {
this.x -= 1;
}
},
//Move the shape to the right
goRight: function(matrix) {
if (isShapeCanMove(this, matrix, 'right')) {
this.x += 1;
}
},
//Copy the shape data to the game data
copyTo: function(matrix) {
var smatrix = this.matrix();
for (var i = 0; i < smatrix.length; i++) {
var row = smatrix[i];
for (var j = 0; j < row.length; j++) {
if (row[j] === 1) {
var x = this.x + j;
var y = this.y + i;
if (x >= 0 && x < matrix[0].length && y >= 0 && y < matrix.length) {
matrix[y][x] = this.color;
}
}
}
}
},
resetOrigin: function() {
this.y = this.originY + 1;
}
}
/**
Create a random shape for game
*/
// Handles randomly generating and returning a tetromino
var RandomGenerator = {
bag: [],
getTetrimino() {
if (this.bag.length === 0) {
this.bag = this.generateNewBag();
}
return this.bag.shift();
},
generateNewBag() {
//var tetrominoes = ['I', 'J', 'L', 'O', 'S', 'T', 'Z'];
var tetrominoes = ['0', '1', '2', '3', '4', '5', '6'];
//var tetrominoes = ['L','L','L','L','L','L','L',];
var bag = [];
for (var i = 7; i > 0; i--) {
var tetrominoIndex = Math.floor(Math.random() * i);
bag.push(tetrominoes[tetrominoIndex]);
tetrominoes.splice(tetrominoIndex, 1);
}
return bag;
}
};
function randomShape() {
var result = parseInt(RandomGenerator.getTetrimino(),10);//Math.floor(Math.random() * 7);
var shape;
switch (result) {
case 0:
shape = new ShapeL();
break;
case 1:
shape = new ShapeO();
break;
case 2:
shape = new ShapeZ();
break;
case 3:
shape = new ShapeT();
break;
case 4:
shape = new ShapeLR();
break;
case 5:
shape = new ShapeZR();
break;
case 6:
shape = new ShapeI();
break;
}
shape.init(result);
return shape;
}
module.exports.randomShape = randomShape;