You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

252 lines
7.0 KiB

export default class Match3 {
// constructor, simply turns obj information into class properties
constructor(obj) {
this.rows = obj.rows;
this.columns = obj.columns;
this.items = obj.items;
}
// generates the game field
generateField() {
this.gameArray = [];
this.selectedItem = false;
for (let i = 0; i < this.rows; i++) {
this.gameArray[i] = [];
for (let j = 0; j < this.columns; j++) {
do {
let randomValue = Math.floor(Math.random() * this.items);
this.gameArray[i][j] = {
value: randomValue,
isEmpty: false,
row: i,
column: j,
};
} while (this.isPartOfMatch(i, j));
}
}
}
// returns true if there is a match in the board
matchInBoard() {
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.columns; j++) {
if (this.isPartOfMatch(i, j)) {
return true;
}
}
}
return false;
}
// returns true if the item at (row, column) is part of a match
isPartOfMatch(row, column) {
return (
this.isPartOfHorizontalMatch(row, column) ||
this.isPartOfVerticalMatch(row, column)
);
}
// returns true if the item at (row, column) is part of an horizontal match
isPartOfHorizontalMatch(row, column) {
return (
(this.valueAt(row, column) === this.valueAt(row, column - 1) &&
this.valueAt(row, column) === this.valueAt(row, column - 2)) ||
(this.valueAt(row, column) === this.valueAt(row, column + 1) &&
this.valueAt(row, column) === this.valueAt(row, column + 2)) ||
(this.valueAt(row, column) === this.valueAt(row, column - 1) &&
this.valueAt(row, column) === this.valueAt(row, column + 1))
);
}
// returns true if the item at (row, column) is part of an horizontal match
isPartOfVerticalMatch(row, column) {
return (
(this.valueAt(row, column) === this.valueAt(row - 1, column) &&
this.valueAt(row, column) === this.valueAt(row - 2, column)) ||
(this.valueAt(row, column) === this.valueAt(row + 1, column) &&
this.valueAt(row, column) === this.valueAt(row + 2, column)) ||
(this.valueAt(row, column) === this.valueAt(row - 1, column) &&
this.valueAt(row, column) === this.valueAt(row + 1, column))
);
}
// returns the value of the item at (row, column), or false if it's not a valid pick
valueAt(row, column) {
if (!this.validPick(row, column)) {
return false;
}
return this.gameArray[row][column].value;
}
// returns true if the item at (row, column) is a valid pick
validPick(row, column) {
return (
row >= 0 &&
row < this.rows &&
column >= 0 &&
column < this.columns &&
this.gameArray[row] != undefined &&
this.gameArray[row][column] != undefined
);
}
// returns the number of board rows
getRows() {
return this.rows;
}
// returns the number of board columns
getColumns() {
return this.columns;
}
// sets a custom data on the item at (row, column)
setCustomData(row, column, customData) {
this.gameArray[row][column].customData = customData;
}
// returns the custom data of the item at (row, column)
customDataOf(row, column) {
return this.gameArray[row][column].customData;
}
// returns the selected item
getSelectedItem() {
return this.selectedItem;
}
// set the selected item as a {row, column} object
setSelectedItem(row, column) {
this.selectedItem = {
row: row,
column: column,
};
}
// deleselects any item
deleselectItem() {
this.selectedItem = false;
}
// checks if the item at (row, column) is the same as the item at (row2, column2)
areTheSame(row, column, row2, column2) {
return row == row2 && column == column2;
}
// returns true if two items at (row, column) and (row2, column2) are next to each other horizontally or vertically
areNext(row, column, row2, column2) {
return Math.abs(row - row2) + Math.abs(column - column2) == 1;
}
// swap the items at (row, column) and (row2, column2) and returns an object with movement information
swapItems(row, column, row2, column2) {
let tempObject = Object.assign(this.gameArray[row][column]);
this.gameArray[row][column] = Object.assign(this.gameArray[row2][column2]);
this.gameArray[row2][column2] = Object.assign(tempObject);
return [
{
row: row,
column: column,
deltaRow: row - row2,
deltaColumn: column - column2,
},
{
row: row2,
column: column2,
deltaRow: row2 - row,
deltaColumn: column2 - column,
},
];
}
// return the items part of a match in the board as an array of {row, column} object
getMatchList() {
let matches = [];
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.columns; j++) {
if (this.isPartOfMatch(i, j)) {
matches.push({
row: i,
column: j,
});
}
}
}
return matches;
}
// removes all items forming a match
removeMatches() {
let matches = this.getMatchList();
matches.forEach(
function (item) {
this.setEmpty(item.row, item.column);
}.bind(this)
);
}
// set the item at (row, column) as empty
setEmpty(row, column) {
this.gameArray[row][column].isEmpty = true;
}
// returns true if the item at (row, column) is empty
isEmpty(row, column) {
return this.gameArray[row][column].isEmpty;
}
// returns the amount of empty spaces below the item at (row, column)
emptySpacesBelow(row, column) {
let result = 0;
if (row != this.getRows()) {
for (let i = row + 1; i < this.getRows(); i++) {
if (this.isEmpty(i, column)) {
result++;
}
}
}
return result;
}
// arranges the board after a match, making items fall down. Returns an object with movement information
arrangeBoardAfterMatch() {
let result = [];
for (let i = this.getRows() - 2; i >= 0; i--) {
for (let j = 0; j < this.getColumns(); j++) {
let emptySpaces = this.emptySpacesBelow(i, j);
if (!this.isEmpty(i, j) && emptySpaces > 0) {
this.swapItems(i, j, i + emptySpaces, j);
result.push({
row: i + emptySpaces,
column: j,
deltaRow: emptySpaces,
deltaColumn: 0,
});
}
}
}
return result;
}
// replenished the board and returns an object with movement information
replenishBoard() {
let result = [];
for (let i = 0; i < this.getColumns(); i++) {
if (this.isEmpty(0, i)) {
let emptySpaces = this.emptySpacesBelow(0, i) + 1;
for (let j = 0; j < emptySpaces; j++) {
let randomValue = Math.floor(Math.random() * this.items);
result.push({
row: j,
column: i,
deltaRow: emptySpaces,
deltaColumn: 0,
});
this.gameArray[j][i].value = randomValue;
this.gameArray[j][i].isEmpty = false;
}
}
}
return result;
}
}