diff --git a/src/data/color.ts b/src/data/color.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/game/board.ts b/src/game/board.ts new file mode 100644 index 0000000..53bd77f --- /dev/null +++ b/src/game/board.ts @@ -0,0 +1,145 @@ +import { Direction } from "../utils/enums"; +import { CoordinatePair, MergingPairs } from "../utils/types"; + +export default class Board { + + dim: number; + board: Array>; + + constructor(dim: number) { + this.dim = dim; + + for (let i = 0; i < dim; ++i) { + let row = []; + for (let i = 0; i < dim; ++i) + row.push(-1); + + this.board.push(row); + } + } + + getBoard = (): Array> => this.board; + + swipe = (direction: Direction) => { + // merge all + this.getMergableIndices(direction).forEach(pair => { + this.board[pair.mergee.row][pair.mergee.col] += this.board[pair.merger.row][pair.merger.col]; + this.board[pair.merger.row][pair.merger.col] = -1; + }); + + + // cascade to direction + + + // add new tile + let newTile = this.newTile(); + } + + validate = (): boolean => { + for (let i = 0; i < this.dim; ++i) { + for (let j = 0; j < this.dim; ++j) { + // board has empty cell + if (this.board[i][j] == -1) + return true; + + // cell can be combined with neighbour + let neighbours: Array = this.getNeighbourIndices({ row: i, col: j }); + for (let k = 0; i < neighbours.length; ++k) { + let pair: CoordinatePair = neighbours[i]; + + if (this.board[pair.row][pair.col] == this.board[i][j]) + return true; + } + } + } + return false; + } + + private getAvailable = (): Array => { + let rt: Array = []; + this.board.forEach((row, rIndex) => row.forEach((cell, cIndex) => { + if (cell == -1) + rt.push(rIndex * this.dim + cIndex); + })); + + return rt; + } + + private getMergableIndices = (direction: Direction): Array => { + let rt: Array = []; + + let openList: Array = []; + for (let i = 0; i < this.dim * this.dim; ++i) + openList.push(i); + + for (let i = 0; i < this.dim; ++i) { + for (let j = 0; j < this.dim; ++j) { + // directional ordering + let row, col; + switch (direction) { + case Direction.down: + row = this.dim - i - 2; + col = j; + break; + case Direction.left: + row = i; + col = j - 1; + break; + case Direction.right: + row = i; + col = this.dim - j; + break; + default: + row = i + 1; + col = j; + } + + let toBeMerged = [row, col]; + let tbmNumericIndex = row * this.dim + col; + let curNumericIndex = i * this.dim + j; + if (!this.isValidIndex(toBeMerged) && !openList.includes(tbmNumericIndex) && !openList.includes(curNumericIndex)) + continue; + + // can be merged + if (this.board[i][j] === this.board[toBeMerged[0]][toBeMerged[j]]) { + rt.push({ + mergee: { + row: i, + col: j, + }, + merger: { + row: toBeMerged[0], + col: toBeMerged[1], + } + }); + openList.splice(openList.indexOf(tbmNumericIndex), 1); + openList.splice(openList.indexOf(curNumericIndex), 1); + } + } + } + + return rt; + } + + private getNeighbourIndices = (coordinate: CoordinatePair): Array => + [[0, 1], [0, -1], [-1, 0], [1, 0]] + .map(pair => [pair[0] + coordinate.row, pair[1] + coordinate.col]) + .filter(this.isValidIndex) + .map(pair => ({ row: pair[0], col: pair[1] })); + + private isValidIndex = (pair: Array): boolean => + pair[0] >= 0 && pair[1] >= 0 && pair[0] < this.dim && pair[1] < this.dim; + + private newTile = (): Array => { + let empty: Array = this.getAvailable(); + let selection: number = empty[Math.floor(Math.random() * empty.length)]; + + let row: number = Math.floor(selection / this.dim); + let col: number = selection % this.dim; + let value: number = (Math.random() > 0.7) ? 4 : 2; + + this.board[row][col] = value; + + return [row, col, value]; + } +} \ No newline at end of file diff --git a/src/utils/enums.ts b/src/utils/enums.ts new file mode 100644 index 0000000..30379d6 --- /dev/null +++ b/src/utils/enums.ts @@ -0,0 +1,6 @@ +export enum Direction { + up, + down, + left, + right, +} \ No newline at end of file diff --git a/src/utils/types.ts b/src/utils/types.ts new file mode 100644 index 0000000..39da84d --- /dev/null +++ b/src/utils/types.ts @@ -0,0 +1,18 @@ +import { ActionName } from "../redux/action"; + +// board util types +export interface CoordinatePair { + row: number; + col: number; +} + +export interface MergingPairs { + mergee: CoordinatePair, + merger: CoordinatePair, +} + +// redux types +export interface ActionType { + type: ActionName, + payload?: any +}