1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import {DataType } from '../model/GameModuel'; 17 18// gameStatus 19enum GameStatus { 20 BEFORE = -1, 21 RUNNING = 1, 22 OVER = 0 23} 24 25export class GameRule { 26 private row: number = 4 27 private column: number = 4 28 29 private index(i: number, j: number): number { 30 return i * this.row + j 31 } 32 33 dataNumbers: Array<number> = [] 34 status: number = GameStatus.BEFORE 35 score: number = 0 36 37 constructor(numbers: Array<DataType>) { 38 numbers.forEach((item) => { 39 this.dataNumbers.push(item.data); 40 }) 41 } 42 43 // random 44 randomNum(): boolean { 45 do { 46 let a = Math.floor(Math.random() * this.dataNumbers.length) 47 if (this.dataNumbers[a] === 0) { 48 let num = Math.random() > 0.3 ? 2 : 4 49 this.dataNumbers[a] = num 50 break 51 } 52 } while (this.dataNumbers.some((val) => { 53 return val === 0 54 })) 55 return false 56 } 57 58 // init 59 init(): void { 60 this.dataNumbers = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 61 this.status = GameStatus.RUNNING 62 this.score = 0 63 this.randomNum() 64 this.randomNum() 65 } 66 67 // move 68 move(direction: string): void { 69 let before = String(this.dataNumbers) 70 let length = (direction === 'left' || direction === 'right') ? this.row : this.column 71 for (let a = 0;a < length; a++) { 72 this.moveInRow(direction, a) 73 } 74 let after = String(this.dataNumbers) 75 if (before !== after) { 76 this.randomNum() 77 if (this.isGameOver()) { 78 this.status = GameStatus.OVER 79 } 80 } 81 } 82 83 // prepare to move 84 moveInRow(direction: string, a: number) { 85 if (direction === 'left') { 86 for (let b = 0;b < this.column - 1; b++) { 87 let next = this.moveNext(a, b, direction) 88 b = this.dataChange(a, b, next, direction).b 89 if (next === -1) break 90 } 91 } else if (direction === 'right') { 92 for (let b = this.column - 1;b > 0; b--) { 93 let next = this.moveNext(a, b, direction) 94 b = this.dataChange(a, b, next, direction).b 95 if (next === -1) break 96 } 97 } else if (direction === 'up') { 98 for (let b = 0;b < this.row - 1; b++) { 99 let next = this.moveNext(b, a, direction) 100 b = this.dataChange(b, a, next, direction).a 101 if (next === -1) break 102 } 103 } else if (direction === 'down') { 104 for (let b = this.row - 1;b > 0; b--) { 105 let next = this.moveNext(b, a, direction) 106 b = this.dataChange(b, a, next, direction).a 107 if (next === -1) break 108 } 109 } 110 } 111 112 // new number moveStatus 113 moveNext(a: number, b: number, direction: string): number { 114 if (direction === 'left') { 115 for (let i = b + 1;i < this.column; i++) { 116 if (this.dataNumbers[this.index(a, i)] !== 0) { 117 return i 118 } 119 } 120 } else if (direction === 'right') { 121 for (let i = b - 1;i >= 0; i--) { 122 if (this.dataNumbers[this.index(a, i)] !== 0) { 123 return i 124 } 125 } 126 } else if (direction === 'up') { 127 for (let i = a + 1;i < 4; i++) { 128 if (this.dataNumbers[this.index(i, b)] !== 0) { 129 return i 130 } 131 } 132 } else if (direction === 'down') { 133 for (let i = a - 1;i >= 0; i--) { 134 if (this.dataNumbers[this.index(i, b)] !== 0) { 135 return i 136 } 137 } 138 } 139 return -1 140 } 141 142 // get gameStatus 143 isGameOver(): boolean { 144 for (let a = 0;a < this.row; a++) { 145 for (let b = 0;b < this.column; b++) { 146 let tempA = this.index(a, b) 147 if (this.dataNumbers[tempA] === 0) { 148 return false 149 } 150 if (a < this.row - 1) { 151 if (this.dataNumbers[tempA] === this.dataNumbers[this.index(a + 1, b)]) { 152 return false 153 } 154 } 155 if (b < this.column - 1) { 156 if (this.dataNumbers[tempA] === this.dataNumbers[tempA+1]) { 157 return false 158 } 159 } 160 } 161 } 162 return true 163 } 164 165 // move and merge 166 dataChange(a: number, b: number, next: number, direction: string): { 167 a: number, 168 b: number 169 } { 170 let tempA = this.index(a, b) 171 let tempB = 0 172 if (direction === 'left' || direction === 'right') { 173 tempB = this.index(a, next) 174 } else { 175 tempB = this.index(next, b) 176 } 177 if (next !== -1) { 178 if (this.dataNumbers[tempA] === 0) { 179 this.dataNumbers[tempA] = this.dataNumbers[tempB] 180 this.dataNumbers[tempB] = 0 181 direction === 'left' && b-- 182 direction === 'right' && b++ 183 direction === 'up' && a-- 184 direction === 'down' && a++ 185 } else if (this.dataNumbers[tempA] === this.dataNumbers[tempB]) { 186 this.dataNumbers[tempA] *= 2 187 this.score += this.dataNumbers[tempA] 188 this.dataNumbers[tempB] = 0 189 } 190 } 191 return { 192 a, b 193 } 194 } 195}